Introduction
Welcome to the Cubyn API! This API is organized around REST over HTTPS.
To implement the Cubyn API on your website, please refer to Connecting the Cubyn API to get your API application Key.
If you need a Sandbox environment to test the connection, please contact us at onboarding@cubyn.com and refer to Using Cubyn Sandbox.
All our endpoints speak JSON fluently.
Authentication
Try this with your
applicationKey
curl https://api.cubyn.com/v2 \
-H 'X-Application: my-api-key'
RESPONSE
{
"version": "0.0.3",
"name": "cubyn.api",
"description": "Please visit developers.cubyn.com for further information on this API.",
"auth": {
"application": {
"name": "My API application",
"createdAt": "2015-08-19T10:18:13.000Z",
"updatedAt": "2015-08-19T10:18:14.000Z"
},
"user": {
"id": 706293859,
"firstName": "Jane",
"lastName": "Doe",
"phone": "0606060606",
"createdAt": "2015-08-19T10:18:13.000Z",
"updatedAt": "2015-08-19T10:18:13.000Z",
"email": "jane.doe@acme.com"
}
}
}
All endpoints except GET /v2
require a proper authentication. Your API credentials will consist of an applicationKey
. Authentication is done simply by adding an X-Application
header containing your API Key.
Quick Start Guide
Cubyn enables e-merchants to manage their inventory, orders and returns from a single interface. The process is simple as below:
STEP 1: you create an inbound order to send us your products
STEP 2: you can track your inventory in real-time once your products are stored in our warehouse
STEP 3: you create parcels that we fulfill (picking, packing and delivery to final recipient)
STEP 4: you are notified in real-time on your orders statuses
Step | Description | API METHOD |
---|---|---|
STEP 1 | Send inventory | POST /v2/storage-inbound/orders?filters[warehouseId]=24082363 |
STEP 2 | Track inventory | GET /v2/product-catalog/products/ |
STEP 3 | Create parcels | POST /v2/parcels |
STEP 4 | Track parcels | GET /v2/parcels/:id |
STEP 1: Send inventory
1. Create an inbound order
REQUEST (curl)
curl --request POST \
--url 'https://api.cubyn.com/v2/storage-inbound/orders?filters%5BwarehouseId%5D=24082363&=' \
--header 'content-type: application/json' \
--header 'x-application: my-app-key' \
--data ' {
"items": [{
"productName": "product33",
"sku": "mySku_product33",
"barcode": "EAN_product33",
"quantity": 4
}]
}'
RESPONSE
{
"id": "e4f007ae-4412-4f90-bc17-a7aa2679b7a6",
"pid": "290833",
"declaredItems": 4,
"status": "VALIDATED"
}
POST /v2/storage-inbound/orders?filters[warehouseId]=24082363
Field | Type | Details |
---|---|---|
items | Array | Array of items in the inbound order |
items.$.productName* | String | Name of the product |
items.$.sku* | String | Unique reference of the product |
items.$.barcode* | String | Physical identification of the product (EAN, IMEI, UPC...) |
items.$.quantity* | Integer | Quantity of objects per item |
Golden rules for an inbound order creation :
Fields
SKU
,productName
,barcode
andquantity
are mandatory.Within an inbound order, one
barcode
cannot be used for different SKUs.One SKU can have several barcodes (example: different IMEI for a same mobile SKU).
This route returns informations about the created inbound order. Here are the most important :
Field | Type | Details |
---|---|---|
id | String | Id used for other API calls needing this inbound order |
declaredItems | Number | Number of items declared in the inbound order |
status | String | Status of the inbound order |
2. Associate deliveries to inbound order
REQUEST (curl)
curl --request POST \
--url 'https://api.cubyn.com/v2/storage-inbound/orders/batch-deliveries' \
--header 'content-type: application/json;charset=UTF-8' \
--header 'x-application: my-app-key' \
--data '{
"orderId": "e4f007ae-4412-4f90-bc17-a7aa2679b7a6",
"deliveries": [
{
"carrierName": "UPS",
"carrierTrackingId": "1Z1234567890123456",
"declaredPackingUnits": 1,
"estimatedReceptionDate": "2020-12-31T23:00:00Z"
}
]
}'
RESPONSE
[
{
"id": "a3c96e92-e33a-4135-9e81-6e4232029d7b",
"status": "CREATED",
"orderId": "e4f007ae-4412-4f90-bc17-a7aa2679b7a6",
"carrierTrackingId": "1Z1234567890123456",
"carrierName": "UPS",
"estimatedReceptionDate": "2020-12-31T23:00:00.000Z",
"declaredPackingUnits": 1,
}
]
POST /v2/storage-inbound/orders/batch-deliveries
Field | Type | Details |
---|---|---|
orderId* | String | ID of the inbound order to associate deliveries to |
deliveries* | Array | Array of deliveries to create and associate to the inbound order |
deliveries.$.carrierName* | String | Name of the delivery carrier. Supported carrier names : UPS , DHL , Other carrier (see details below) |
deliveries.$.carrierTrackingId* | String | Carrier tracking ID of the delivery |
deliveries.$.declaredPackingUnits* | Number | Number of packing units in the delivery |
deliveries.$.estimatedReceptionDate | Date | Estimated reception date of the delivery at the warehouse |
skipEmail | Boolean | Whether to skip sending email containing the delivery document (used for Other carrier deliveries only), by default the email is sent |
Deliveries allow warehouse operators to know which incoming order is associated with each package received. For this reason, carrier tracking IDs must be indicated for each delivery.
This route returns the list of created deliveries and their informations. Here are the most important :
Field | Type | Details |
---|---|---|
$.id | String | Id of the delivery |
$.status | String | Status of the delivery |
$.orderId | String | Id of the inbound order associated to the delivery |
$.carrierTrackingId | String | Carrier tracking ID of the delivery |
$.carrierName | String | Name of the delivery carrier |
$.estimatedReceptionDate | Date | Estimated reception date of the delivery at the warehouse |
$.declaredPackingUnits | Number | Number of packing units declared in the delivery |
STEP 2: Track inventory
REQUEST (curl)
curl --request GET \
--url https://api.cubyn.com/v2/product-catalog/products/ \
--header 'x-application: my-app-key'
RESPONSE
[
{
"id": "e7fe10a9-0fcf-4810-8def-b6b53849616b",
"ownerId": 161181051,
"sku": "bundle phone 1",
"sanitizedSku": "BUNDLE PHONE 1",
"name": "Bundle test phone",
"isVirtual": false,
"isBundle": true,
"isUnknown": false,
"createdAt": "2020-05-15T16:49:17.000Z",
"updatedAt": "2020-05-15T16:49:17.000Z",
"scubsIds": [
"7ceade20-7638-4713-924c-c94eab12c4fb",
"9216cdaa-3d1f-4a9c-ab04-2e3ef487fd3a"
],
"stock": {
"hadStockInbounded": false,
"quantityAvailable": 4,
"quantityOutbounded": 0,
"quantityInbounding": 0,
"quantityOutbounding": 0
},
"requiresItemIdentifiers": null,
"externalReferences": [
{
"value": "BUNDLE PHONE 1",
"rawValue": "bundle phone 1"
}
]
}
]
GET /v2/product-catalog/products/{product_id}
This endpoint will return 1 product
GET /v2/product-catalog/products
Using filters you can filter out the products you are looking for, few examples:
Endpoint | Description |
---|---|
/v2/product-catalog/products?filters[sku]=an_item |
returns array of item(s) that has an_item value in sku field |
/v2/product-catalog/products?filters[isBundle]=1 |
returns array of item(s) that are a bundle boolean values true/false values are represented as 1/0 |
STEP 3: Create parcels
REQUEST (curl)
curl https://api.cubyn.com/v2/parcels \
-H 'X-Application: my-app-key' \
-H 'Content-Type: application/json' \
--data '{ \
"firstName":"Sophie", \
"lastName":"Martin", \
"items":[ \
{ \
"reference":"product_name", \
"count":1 \
}, \
{ \
"reference":"product_name_2", \
"count":2 \
} \
], \
"orderRef": "my_order_reference", \
"address":{ \
"line1":"3 place de la Republique", \
"zip":"69002", \
"city":"Lyon", \
"country":"France", \
"additionalInformation":"code 9898" \
}, \
"objectCount":2 \
}'
RESPONSE
{
"id": 673847167,
"status": "CREATED",
"address": {
"line1": "3 place de la Republique",
"zip": "69002",
"city": "Lyon",
"country": "France",
"additionalInformation": "code 9898"
},
"firstName": "Sophie",
"lastName": "Martin",
"deliveryMode": "standard",
"deliverySigned": false,
"isAdvalorem": 0,
"applcationId": "92390180134",
"shipperId": "2932983427982",
"collectId": null,
"barcode": null,
"qrCode": null,
"createdAt": "2015-08-18T16:26:08.000Z",
"updatedAt": "2015-08-18T16:26:08.000Z"
}
- You can create parcels by providing recipient information and list of products (SKU x quantity)
- You can update / cancel a parcel while its status is still
CREATED
. - Every parcel is validated according to available stock in warehouse and address standards
- Once a parcel is validated, its status is changed to
PICKED
(you cannot edit or cancel a parcel in this status)
POST /v2/parcels
POST /v2/parcels/batch
Using batch creation body should contain an array with objects containing parameters
Field | Type | Details |
---|---|---|
address * |
<Address> |
Defines the recipient address (see format) |
items |
[<Item>] |
Array of items contained in this parcel (see format) |
firstName |
string |
First name of recipient (max 35 characters) |
lastName |
string |
Last name of recipient (max 35 characters) |
organizationName |
string |
Organization name (max 35 characters) One of firstName , lastName and organizationName has to be defined |
deliveryMode |
Enum<string> |
Shipping mode allowed: standard , express or relay |
deliverySigned |
boolean |
Should shipment be handed against signature |
relayPickupRef |
string |
Pickup point identifier (only if deliveryMode is relay ) (see handling relay) |
phone |
string |
Phone of recipient (phone format needed) |
email |
string |
Email of recipient (email format needed) |
isAdvalorem |
boolean |
Activation of ad valorem insurance of your parcel according to the value of your SKUs |
orderRef |
string |
Unique reference of the parcel |
value |
number |
Overall value of parcel (for international shipping only) |
customsHsCode |
string |
Harmonized system code (for international shipping only) |
customsCategory |
Enum<string> |
Nature of the order 'GIFT','DOCUMENTS','COMMERCIAL_SAMPLE','COMMERCIAL','RETURNED_GOODS','OTHER' |
customsDescription |
string |
Description of contect (for international shipping only) (max 65 characters) |
customsOriginCountry |
string |
Origin country (for international shipping only) |
STEP 4: Track parcels
REQUEST (curl)
curl https://api.cubyn.com/v2/parcels/673847167 \
-H 'X-Application: my-app-key'
RESPONSE
{
"id": 297706966,
"batchId": "cafedd5e-e824-46c3-b6cc-3e077aa00846",
"type": "SHIPMENT",
"trackingId": "CUB297706966",
"status": "PICKED",
"aside": false,
"address": {
"line1": "31 rue du Pere Corentin",
"line2": "",
"zip": "75014",
"city": "Paris",
"state": "",
"country": "FR",
"additionalInformation": ""
},
"firstName": "Robin",
"lastName": "Dubois",
"organizationName": "cubyndemo2",
"deliveryMode": "express",
"deliverySigned": false,
"objectCount": 1,
"isAdvalorem": false,
"orderRef": "91251234",
"createdAt": "2019-12-11T18:11:29.000Z",
"updatedAt": "2019-12-11T18:11:29.000Z",
"validationStatus": "INFO",
"cancellationStatus": "NONE",
"shipperId": 427380376,
"selfReturnActivated": true,
"deliverySaturday": false,
"isAnonymized": true,
"isStorage": true,
"isRemoval": false
}
GET /v2/parcels/:id
Use webhooks to subscribe to events related to parcels you created.
By providing us with a webhook, you will be notified everytime a parcel
sees its status
change. This allows you to take the appropriate action in the shortest delay, such as informing your customers that their product has been shipped.
Enabling webhooks
To activate webhooks for your account, configue on shipper.cubyn.com applications:
- URL of the Webhook
- Events you want to subscribe to (see below)
Webhook event types
A webhook call will be triggered in each of those events:
Event | Description |
---|---|
parcel:cancelled |
parcel parcel ready for picking; has been cancelled |
parcel:picked |
parcel goes from being CREATED to being PICKED |
parcel:shipped |
parcel is labelled and ready to be taken by carrier |
parcel:carrier-status:changed |
parcel transits within the carrier network |
Securing your webhook
A webhook creates a potential backdoor on your system, we thus recommend:
- providing us with an HTTPs webhook URL
- comparing your API key: every request will contain your api key within its body. Use it to make sure of caller's identity.
Backoff webhook attempts
If your server responds with a HTTP 500 status, our servers will attempt to replay the request up to 3 times: 1, 2, 4 minutes later.
Webhook request
A JSON payload
POST
ed to your webhook
{
"event": "parcel:picked",
"key": "my-app-key",
"parcel": {
"id": 673847167,
"label": "iPhone 7",
"status": "PICKED",
"address": {
"line1": "3 place de la Republique",
"zip": "69002",
"city": "Lyon",
"country": "France",
"additionalInformation": "code 9898"
},
"firstName": "Sophie",
"lastName": "Martin",
"deliveryMode": "standard",
"objectCount": 2,
"insurance": 250,
"createdAt": "2015-08-18T16:26:08.000Z",
"updatedAt": "2015-08-18T16:26:08.000Z"
}
}
Our systems will issue POST requests to your Webhook URL with these 3 fields in the request body:
parcel
: take special attention to theparcel.status
key
: your API key, provided here as an authentication mechanismevent
: the original event which triggered the webhook
Testing your webhooks
Simply use these simple curl commands to try your webhooks -›
Try your webhook with the two following parcel events
curl https://<URL_WEBHOOK> -H 'Content-Type: application/json' \
--data '{ \
"key":"<API_KEY>", \
"event":"parcel:picked", \
"parcel":{"id":"<CUBYN_ID>","orderRef":"<ORDER_REFERENCE>","status":"PICKED"} \
}'
curl https://<URL_WEBHOOK> -H 'Content-Type: application/json' \
--data '{ \
"key":"<API_KEY>", \
"event":"parcel:carrier-status:changed", \
"parcel":{"id":"<CUBYN_ID>","orderRef":"<ORDER_REFERENCE>","status":"CARRIER_DELIVERED"} \
}'
API Reference
Find here all API endpoints available.
Addresses
This is the address model used in Shipper
and Parcel
objects.
Field | Type | Details |
---|---|---|
line1 * |
string |
(max length: 35 chars.) |
line2 |
string |
(max length: 35 chars.) |
zip * |
string |
city's zip code |
city * |
string |
city's name |
state |
string |
required for US |
country * |
string |
|
additionalInformation |
string |
any detail (floor, code, ...) needed by the carrier to deliver / messenger to pick. (max length: 35 chars.) |
Items
This is the item model used in to specify an object contained in a Parcel
.
Field | Type | Details |
---|---|---|
count * |
string |
Number of items to pick |
reference* |
string |
SKU of your product |
Users
Method | Path | Description |
---|---|---|
GET | /v2/users |
Get user currently connected |
GET | /v2/users/:id |
Read user details |
PUT | /v2/users/:id |
Edit a user |
Parcels
Method | Path | Description |
---|---|---|
GET | /v2/parcels |
List all your parcels |
POST | /v2/parcels |
Create a parcel |
GET | /v2/parcels/:id |
Read details of this parcel |
PUT | /v2/parcels/:id |
Edit a parcel |
PUT | /v2/parcels/:id/cancel |
Cancel a parcel ready for picking |
Attachments
Method | Path | Body | Description |
---|---|---|---|
GET | /v2/attachments |
– | List all your attachments |
GET | /v2/attachments?filters[parcelId]=:id |
– | List all attachments of this parcel |
POST | /v2/attachments |
{ "parcelId": ":id" } | Upload a new attachment on this parcel |
GET | /v2/attachments/:id |
– | Read details of this attachment |
DELETE | /v2/attachments/:id |
– | Delete this attachment |
Inbound orders
Method | Path | Body | Description |
---|---|---|---|
GET | /v2/storage-inbound/orders?filters[status]=:status |
– | List an inbound order with given status |
GET | /v2/storage-inbound/warehouses |
– | List all your warehouses |
GET | /v2/storage-inbound/orders/:orderId |
– | Read details of an inbound order with given id |
POST | /v2/storage-inbound/orders?filters[warehouseId]=:warehouseId |
{"packingUnits": 1, "items": [{"productName": "product33", "sku": "er1234" "barcode": "barcode74", "quantity": 1}]} | Create an inbound order |
DELETE | /v2/storage-inbound/orders/:orderId?ownerId=:ownerId |
– | Delete an inbound order |
Products
Method | Path | Body | Description |
---|---|---|---|
GET | /v2/product-catalog/products/ |
– | List all your products |
PUT | /v2/product-catalog/products/:productId |
{"sku":"newSku", "name":"newName"} | Update a product |
Glossary
Word | Definition |
---|---|
sku | Unique reference of your product |
barcode | Physical identification of your product (EAN, IMEI, UPC...) |
packing unit | Boxes or pallets containing your products in the inbound order |
inbound order | Group of declared products sent to Cubyn |
Guides
Understanding Cubyn statuses
Parcels and their Attachments all have a status
field.
Parcel statuses
Status | Stakeholder | Description |
---|---|---|
CREATED |
Shipper | Parcel has been created and is still editable. The status remains CREATED in two scenarios: 1) The parcel is in error, for example missing stock, unknown external reference, error in address or 2) the parcel is well-validated and ready to be picked |
PICKED |
Cubyn | Parcel has been picked by an operator from Cubyn picking team. At this point of the process, the parcel can no longer be cancelled |
SHIPPED |
Cubyn | Parcel is now in carrier hands |
CARRIER_IN_TRANSIT |
Carrier | Parcel is on the way, transitting within carrier network |
CARRIER_OUT_FOR_DELIVERY |
Carrier | Carrier is ready to deliver the parcel |
CARRIER_FAILED_ATTEMPT |
Carrier | Carrier attempted to deliver the parcel but will try again |
CARRIER_DELIVERED |
Carrier | (final status) Parcel delivered successfully |
CARRIER_EXCEPTION |
Carrier | (final status) Parcel not delivered / returned to shipper |
CARRIER_RETURN_RECEIVED |
Cubyn | (final status) Parcel not delivered to recipient / returned to Cubyn warehouse |
Parcel cancellation statuses
Status | Description |
---|---|
NONE |
Default parcel cancellation status |
IN_PROGRESS |
Parcel is in cancellation |
SUCCEEDED |
Parcel has been cancelled |
FAILED |
An error occured while cancelling the parcel |
Attachment statuses
Status | Description |
---|---|
IN_PROGRESS |
Attachment is being downloaded or processed by our servers |
SUCCESS |
Attachment is ready to be printed |
PRINTED |
Attachment has been printed and packed in your parcel |
Parcel attachments
REQUEST (curl)
curl https://api.cubyn.com/v2/attachments \
-H 'X-Application: my-app-key' \
-F name=my-file.pdf \
-F parcelId=983264786 \
-F 'file=@/path/to/my-file.pdf'
RESPONSE
{
"id":923743672,
"type":"OTHER",
"status":"SUCCESS",
"name":"my-file.pdf",
"file": {
"url": "https://attachment.domain/path/to"
},
"pageCount":1,
"fileSize":24218,
"createdAt":"2016-08-23T15:27:54.000Z",
"updatedAt":"2016-08-23T15:27:54.000Z"
}
Parcel attachments are a convenient way to have Cubyn print and pack documents in your parcels. e.g. Invoices, User guides, Ads, ...
Maximum allowed size: 2Mo. Only PDF files are supported.
You can also list and delete attachments as described in API Reference.
Endpoint
POST /v2/attachments
Tracking page
Cubyn offers a unified tracking page that is common to every carrier we support. We highly recommend using it:
- the web page is accessible as soon as your parcel is picked by our messengers
- it unifies your customer experience across all our carriers
To do so:
1. Build your Cubyn tracking number
CUB{{your parcel id}}
2. Build your Cubyn tracking page
http://track.cubyn.com/{{your tracking number}}
Handling Cubyn relay
Cubyn supports relay
as a third delivery mode which requires a valid relayPickupRef
to be set on the parcel.
We recommend using our iframe to facilitate the Relay integration into your own systems.
If you do not want to integrate our iframe, please be aware that our relay
offer is currently routed on Mondial Relay's network, so relayPickupRef
needs to be a valid Mondial Relay pickup point ID. Check Mondial Relay Widget to have a map of pickup points.
Important note: We support many relay points now (all Mondial Relay zones)
https://app.cubyn.com/tools/relay-iframe/index.html?address=[...]&callback=[...]
Field | Type | Details |
---|---|---|
address * |
string |
Remember to URL encode this value Address must be formatted as follows: [line1] [line2] [zip] [city] [country] |
callback * |
string |
Remember to URL encode this value That URL will be given query parameters telling which pickup point the user has selected. |
Field | Type | Details |
---|---|---|
id |
string |
This is the one and only ID you need to set on parcel.relayPickupRef . |
name |
string |
Name of the pickup point |
image |
string |
|
openinghours |
string |
Example: MON.0700.1830-TUE.0700.1830-WED.0700.1830... |
street |
string |
|
city |
string |
|
zip |
string |
|
country |
string |
No page reload
shop.com/cart
<!-- This is your main checkout tunnel page. -->
<!-- You can include that iframe inside a popup for instance-->
<iframe src="https://app.cubyn.com/tools/relay-iframe/index.html?address=[...]&callback=http%3A%2F%2Fshop.com%2Fcallback">
</iframe>
<script type="text/javascript">
window.setRelay = function(info) {
console.log('Yeay — relay selected:', info);
}
</script>
shop.com/callback
<!-- Once the relay is selected, the iframe will redirect to this page. -->
<script type="text/javascript">
// call parent (out of iframe, but on same domain so that works)
window.parent.setRelay(parseGetParams());
function parseGetParams() {
var vars = window.location.search.substring(1).split('&');
var getPrms = {};
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
getPrms[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
}
return getPrms;
}
</script>
Our iframe relies on a http redirect to give you back results, thus (re)loading a new page. You can avoid this redirect by loading the map inside an iframe (in a popup for instance). Beware that cross domain scripting is not allowed. Here is a simple scenario to illustrate how to overcome this:
Using Cubyn Sandbox
Cubyn provides a Sandbox environment where you will be able to test your integration before going live. Ask us for a sandbox account here onboarding@cubyn.com.
Endpoint
https://apisandbox.cubyn.com/v2
Cubyn customer interface URL
https://shippersandbox.cubyn.com
Handling errors
When
PUT
ing orPOST
ing - in case of a validation error, our API will describe each erroneous field. Here is an example:
REQUEST (curl)
curl https://api.cubyn.com/v2/users/124288383 \
-X PUT \
-H 'X-Application: my-app-key' \
-H 'Content-Type: application/json' \
--data '{"email":"wrongemail.com","password":"mypassword"}'
RESPONSE
{
"errors": [
{
"field": "email",
"message": "Validation isEmail failed"
}
],
"message": "Validation error: Validation isEmail failed",
"type": "ValidationError"
}
Code | Type | Description |
---|---|---|
400 | BadRequestError |
Often missing a required parameter |
400 | ValidationError |
Some field is badly formatted or has validation errors |
404 | ResourceNotFoundError |
The requested resource does not exist |
403 | ForbiddenError |
You cannot perform that action on this resource |
413 | TooBigFileError |
The file you uploaded is too big |
50X | ServerError |
Oops - that's for us. |