Code Logo

This page contains the technical documentation of the Code R&E API. The API can be used to push data towards the R&E application in case of certain events, as well as to receive updates from the RMA requests (return merchandise authorization) done through the application by webhooks.

The API is generally interesting for 3rd parties integrating with the Code R&E application, e.g. third party logistics, shipping parties, and parties that gather statistics.

How to connect?

Currently the API is opened up to merchants and integrators on a per-request basis. Please contact us here to find out more!

Flows

The API consists of two flows, in and out:

  • The in flow is served by an endpoint /event that received POST calls for relevant events at the 3rd-party.
  • The out flow is served by webhooks. On specific events within the application a webhook handling endpoint can get called with data related to the RMA request.

In flow

Currently there is only one flow into the application from external parties on the API. This is through the /event endpoint. This endpoint is fully documented in the Swagger interface and the OpenAPI specification.

The endpoint is secured trough https and expects both a rma-shop-domain and rma-hmac-sha header or shop and hmac parameter in the url. So both of the following request would be accepted:

curl \
    --request POST '<endpoint>/event' \
    --header 'rma-hmac-sha: <hmac>' \
    --header 'rma-shop-domain: <yourshop>.myshopify.com' \
    ...
curl \
    --request POST '<endpoint>/event?hmac=<hmac>&shop=<yourshop>.myshopify.com' \
    ...

HMAC

HMAC is used to check the integrity and origin of the incoming event message. In short, it guarantees that the message coming in is written by someone who owns the same secret as was entered into the R&E application, without exposing this secret in the message itself. Note; it does not encrypt the message itself, this is left to the https protocol.

The HMAC value should be calculated by creating a digest in hexadecimal format using of the request body using the configured hash algorithm (default sha1) and secret. Digests can easily be created using cryptographic packages in your language/environment of choice (NodeJS, Python, Java, C++, Rust) or on the commandline:

echo -n "<data>" | openssl dgst -sha1 -hmac "<secret>"
> 63ac6b48f0c7ce19ad954aa1acfd093611066abe

Shop

Included in the header or url query we also expect the name of the shop for which this event is fired. This value identifies the shop this event is for, and is coupled to your HMAC secret. An example of a valid shop name is:

my-favorite-shop.myshopify.com

Note that this is the exact domain name Shopify reserved for your shop, ignoring any custom domains.

Data

The data in the request body to be sent over the endpoint differs per event. It should always be valid JSON. At the moment only the received event is supported.

Received

The received event schema consists of a type "received", a timestamp (ISO), the RMA reference (name), an optional problem string, and a list of items that were received:

{
  "type": string,
  "timestamp": string,
  "rmaReference": string,
  "problem": string | undefined,
  "rmaItems": [
    {
      "sku": string,
      "quantity": number
    }
  ]
}

The RMA request will usually flow into the Returned state in the app after receiving the received event including all items. Note that currently there is no support for splitting the received items across multiple received events. The event is considered the only and final received event on the referenced RMA. Unless the response is not 200, any subsequent calls will be rejected.

Example

Example request to notify the application of receiving back a damaged item with SKU ABC (using secret as the secret key).

curl \
    --request POST '<endpoint>/event' \
    --header 'rma-hmac-sha: ff90710be02846277954fee67992af44864f6cea' \
    --header 'rma-shop-domain: allvital-demo.myshopify.com' \
    --header 'Content-Type: application/json' \
    --data-raw '{"type":"received","timestamp":"2022-05-18T11:07:21.223Z","rmaReference":"CODE-123-R1","problem":"Damaged during transport","rmaItems":[{"sku":"ABC","quantity":1}]}'

Out flow

The out flow serves the purpose of notifying external parties of updates in de application. When certain state changes happen, the application fires a POST request towards a predefined URL (webhook) with the RMA request state in JSON format. The request body contains the current state of the RMA request as well as the type of event that was fired.

The request is also signed using HMAC in a similar way as for the in flow, using an algorithm (default sha1) and a shared secret. It is up to the webhook receiving endpoint to check the HMAC, and optionally check for replay attacks using the timestamp in the request body.

The headers contain the following application specific keys:

  • rma-shop-domain: the shop for which this webhook was fired,
  • rma-hmac-sha: the HMAC calculated from the request body and the secret, using the specified algorithm,
  • pid: a process ID for the webhook executor,

The full schema of the request body can be found in Swagger under the EventOutput schema. An example of such a request body can be found below.

{
  "timestamp": "2022-05-21T14:25:42.231Z",
  "rmaReference": "CODE-123-R1", // Name (reference) of the RMA request.
  "type": "processed", // Varies for each state change, check Swagger for the options.
  "customerNote": "Such beautiful pants! Unfortunately, I ordered the wrong color.",
  "customer": "Jan Janssen",
  "originalOrder": {
    "id": 8351047361539, // Shopify Order ID.
    "name": "CODE-123",
    "shippingCountry": "Netherlands",
    "shippingCountryCode": "NL"
  },
  // Some states can be skipped, so some parts in the timeline might not
  // be set.
  "timeline": {
    "orderCreatedAt": "2022-05-15T09:00:47.043Z",
    "rmaSubmittedAt": "2022-05-19T09:01:26.674Z",
    "rmaShippedAt": "2022-05-19T17:41:12.912Z",
    "rmaPaymentPendingAt": null,
    "rmaReturnedAt": "2022-05-20T10:05:05.772Z",
    "rmaProcessedAt": "2022-05-21T14:25:40.113Z"
  },
  // Some states can be skipped, so some parts in the status might remain
  // false even after processing.
  "status": {
    "isSubmitted": true,
    "isUnprocessable": false,
    "isShipping": true,
    "isReturned": true,
    "isPaymentPending": false,
    "isProcessed": true,
    "hasError": false,
    "hasFlag": false
  },
  "rmaItems": [
    {
      "returned": true,
      "type": "return", // Can be "return" or "exchange".
      "returnProduct": {
        "productId": 73849201735194, // Shopify product ID.
        "productTitle": "Clown Pants",
        "variantId": 82923409292394, // Shopify variant ID.
        "variantTitle": "23 / 64",
        "sku": "ABC"
      },
      "reasons": [
        {
          "id": "2", // Return reason ID as defined in the R&E application.
          "label": "Color not as expected" // Human readable return reason.
        }
      ]
    }
  ]
}