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.
Currently the API is opened up to merchants and integrators on a per-request basis. Please contact us here to find out more!
There are two options for security measures in place to ensure the integrity of the data flowing through the API:
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
JWT 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.
To create a JWT token, you need to post the following data to the JWT provider, which is Google's Identity Toolkit:
{
"email": "<Account email>",
"password": "<Account password>",
"returnSecureToken": true
}
The endpoint to POST to for a token
is https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=<APIKey>
where APIKey is AIzaSyBnBpeMxZCQ1VObDVmyAt2rqlWCeH8YuxI
for regular Shopify app installs.
Contact us for the API key for your install if you didn't install it through the Shopify
App Store.
The API consists of three flows, in, out, and search:
/event
that received POST calls for relevant events at the 3rd-party./search
that can be used to search for RMA requests and order
information in the application.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. Alternatively, you can use a JWT token instead of the HMAC by using it as the
Authorization header.
So all 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' \
...
curl \
--request POST '<endpoint>/event?shop=<yourshop>.myshopify.com' \
--header 'Authorization: Bearer <JWT>' \
...
curl \
--request POST '<endpoint>/event' \
--header 'Authorization: Bearer <JWT>' \
--header 'rma-shop-domain: <yourshop>.myshopify.com' \
...
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.
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.
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 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}]}'
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",
// Name (reference) of the RMA request.
"rmaReference": "CODE-123-R1",
"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"
},
"exchangeOrder": {
"id": 8351047361538,
// Shopify Order ID.
"name": "CODE-122",
"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": {
"lineItemId": 54987954987332,
// Order Line Item ID
"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.
}
]
}
]
}
The search flow is a utility that external parties can use to search for RMA requests in the application. It is a simple GET request that returns a list of RMA requests that match the search query.
The query parameters that can be used to search are:
rma
: the RMA reference (name) of the RMA request (e.g CODE-123-R1
),order
: the Shopify order name of the original order (e.g. CODE-123
),trackingCode
: the tracking code of the RMA request (e.g. 3SABCD123456789
),An example of a search request:
curl -X 'GET' \
'<endpoint>/search?trackingCode=3SYZXG7532624' \
--header 'Authorization: Bearer <token>'
The response is a list of RMA requests and orders that match the query parameters, e.g.:
[
{
"shop": "allvital-demo.myshopify.com",
"order": {
"name": "CODE-DEV1596",
"customer": {
"name": "Yuri van Geffen"
},
"shippingAddress": {
"countryCode": "NL"
},
"items": [
{
"name": "Baristas * The Longs - 28 / 32",
"sku": "8720195081241",
"barcode": "8720195081241",
"quantity": 1,
"thumbnail": "https://code.nl"
}
]
},
"rma": {
"name": "CODE-DEV1596-R1",
"note": "",
"items": [
{
"sku": "8720195081241",
"quantity": 1
}
]
}
}
]