Webhooks
The Webhooks resource allows applications to subscribe to topics and receive events for users. Events are pushed to the webhook's address
with a payload by issuing an HTTP POST request each time.
Address Rules
To create a webhook you register a valid HTTP address for consuming the events. It can be updated at any time. An address is considered valid if it meets the following conditions:
- Must be RFC compliant (include HTTP/S).
- Must include a valid hostname (example: www.boxc.com).
- Must include a path and can't be just a domain or IP address (example: http://boxc.com/path/to/script).
- Can't include localhost in the hostname.
- Must be less than or equal to 128 characters in length.
HTTP Headers
There are four additional HTTP headers added to the webhook event to aid applications in processing them.
- User-Agent - Always "BoxC/1.0 Webhook" for filtering webhook requests.
- X-BoxC-Hmac-SHA256 - Base64 encoded HMAC digest. Useful for verifying the event is authentic (example: Ikaxp9lMrkNXb6kxVhYxxiYDZplIN1kQcHV6gK3duFk=).
- X-BoxC-Topic - The subject of the event (example: shipments_status).
- X-BoxC-Account - The user ID affected by the event (example: 9512).
Verifying Events
A key
is required when creating a webhook. Every webhook has a key
that is used to calculate the X-BoxC-Hmac-SHA256 HTTP header by using the payload sent in the request. To verify the request came from BoxC, compute the HMAC digest using the SHA-256 hash function, encode it to Base64, and compare it to the X-BoxC-Hmac-SHA256 header.
Keys are provided by the application and must be between 16 and 32 characters long. They're not unique or immutable.
Payloads
The payload contains a JSON object with the data for the webhook event. The contents and structure of each payload varies depending on the topic.
Responding to Webhooks
The configured webhook address
must respond with an HTTP Status between 200 and 299 (inclusive) to be considered successful. Any response outside the 200 range will result in a failed attempt and will be queued for three additional attempts within an hour before it's evicted. Requests made to the webhook address will not follow any redirects.
The address
must connect within 2 seconds and respond within 4 seconds overall or it will be considered a failed attempt. If you believe it will take longer than 4 seconds to respond then you should process the request asynchronously after responding with 200 OK.
BoxC uses an exponential backoff timer for calculating the next attempt and will continue to retry three times within an hour. Webhook addresses that don't respond with a successful status 1000 consecutive times are deactivated until the client updates the malfunctioning webhook.
Testing Webhooks
Applications can test their integration by POSTing an event to a webhook they manage. The same event will be injected into the queue and subsequently POSTed to the webhook's configured address without any alterations. A fake payload from one of the topics below can be used as a template and modified to test the different stages of an object's lifecycle. The event's payload must match the topic's schema the webhook is subscribed to.
Topics
Listed below are the current topics and their respective event structures that users may subscribe to.
fulfillments_complete
This event is triggered when a fulfillment is fulfilled and finalized at a warehouse. Tracking numbers will be provided in most cases, but sometimes there's a delay from the carrier - users should subscribe to fulfillments_update
to handle this scenario.
{ "fulfillment": { "id": 619231, "line_items": [ { "product_id": 121000, "quantity": 2, "sku": "MYSKU123" } ], "order_id": 600001, "service": "BoxC Parcel", "shipment_id": 1521231, "shop": { "id": "my-test-shop", "order_id": "#1002" }, "tracking_number": null, "tracking_url": null, "warehouse_id": "WH0HKG01" } }
fulfillments_update
This event is triggered when a fulfillment's tracking information is updated by the carrier after it was already completed. Some carriers don't provide a tracking number immediately.
{ "fulfillment": { "id": 619231, "order_id": 600001, "service": "BoxC Parcel", "shipment_id": 1521231, "shop": { "id": "my-test-shop", "order_id": "#1002" }, "tracking_number": "9261290185965500000103", "tracking_url": "https:\/\/track.boxc.com\/?id=9261290185965500000103", "warehouse_id": "WH0HKG01" } }
manifests_complete
This event is triggered when a manifest finished processing and any related PDF documents are available for download.
{ "manifest": { "created": "2022-08-02 12:12:12", "entry_point": "LAXI01", "exit_point": "SYD", "id": 909447, "forms": [ "Toll_IPEC.pdf" ], "mawb_id": null, "overpacks": [ { "carrier": "Toll", "created": "2021-08-01 00:26:05", "height": 10, "id": 1002730, "length": 10, "service": "BoxC Parcel", "terms": "DDU", "type86": false, "weight": 5, "width": 10 } ], "total_shipments": 4, "warehouse_no": "02599225803" } }
orders_status
This event is triggered when an order's status changes. Only orders updated to "Exception" will trigger this event.
{ "order": { "created": "2020-02-27 12:12:12", "id": 1831488, "line_items": [ { "product_id": 123456, "sku": "sku123", "quantity": 1 } ], "placed_at": "2020-02-27 15:15:15", "service": "BoxC Priority", "status": "Exception", "shipping_address": { "company_name": null, "phone": null, "email": null, "name": "John Smith", "street1": "555 5TH AVE", "street2": null, "city": "NEW YORK", "province": "NY", "postal_code": "10001", "country": "US" }, "shop": { "id": "my-test-shop", "order_id": "123456" } } }
shipments_label
This event is triggered when a label is generated in the BoxC system. In most cases this webhook will immediately fire off during shipment creation. However, some carriers provide shipping labels asynchronously so they won't be available after creating a shipment. They make take anywhere from a few seconds to a few minutes to be ingested into our system. The shipment.data
is a base 64 encoded string that must be decoded before saving as the indicated content_type
. All label data will be sent as "application/pdf".
{ "shipment": { "carrier": "Janio", "content_type": "application\/pdf", "data": "aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g\/dj1kUXc0dzlXZ1hjUQ==", "id": 1521231, "tracking_number": "9261290185965500000103" } }
shipments_status
This event is triggered when a new tracking event is injected. The tracking event along with some shipment details is sent to the subscribed webhooks.
{ "shipment": { "chargeable_weight": 0.4, "comments": [ "Order123456" ], "entry_point": "SZXI01", "event": { "carrier": "USPS", "code": 200, "city": "AUSTIN", "province": "TX", "postal_code": "78701", "country": "US", "time": "2019-10-10 12:12:12" }, "exit_point": "DFW", "gross_weight": 0.235, "id": 1521231, "order_number": null, "service": "BoxC Parcel", "status": "Delivered", "tracking_number": "9261290185965500000103", "volumetric_weight": 0.4 } }
Actions
GET /webhooks |
Retrieves a paginated list of webhooks |
GET /webhooks/{id} |
Retrieves a webhook |
POST /webhooks |
Creates a webhook |
POST /webhooks/{id}/queue |
Adds an event to the webhook's queue |
PUT /webhooks/{id} |
Updates a webhook |
DELETE /webhooks/{id} |
Deletes a webhook |
Properties
active |
|
address |
|
created |
|
id |
|
key |
|
topic |
|
updated |
|
limit |
The number of results to return. Max: 100. Default: 50. |
order |
The order of the results. Options are "asc" for ascending, or "desc" (default) for descending. |
page |
The page number of the results. Default is 1. |
page_token |
Used for selecting the page after the initial query. |
GET /webhooks
limit=50&order=desc
HTTP/1.1 200 OK
{ "webhooks": [ { "active": true, "address": "https://www.example.com/path", "created": "2019-10-05 13:01:01", "id": 100001, "topic": "fulfillments_complete", "updated": "2019-10-05 13:01:01" }, { "active": true, "address": "https://www.example.com/path/2/update", "created": "2019-10-04 16:10:15", "id": 100000, "topic": "shipments_status", "updated": "2019-10-05 12:54:07" } ], "next_page": null }
GET /webhooks/100001
HTTP/1.1 200 OK
{ "webhook": { "active": true, "address": "https://www.example.com/path", "created": "2019-10-05 13:01:01", "id": 100001, "topic": "fulfillments_complete", "updated": "2019-10-05 13:01:01" } }
POST /webhooks
{ "webhook": { "address": "https://www.example.com/path", "key": "9FkaaYZILF9pWHqJzXDD", "topic": "fulfillments_complete" } }
HTTP/1.1 201 Created
{ "webhook": { "active": true, "address": "https://www.example.com/path", "created": "2019-10-05 13:01:01", "id": 100001, "topic": "fulfillments_complete", "updated": "2019-10-05 13:01:01" } }
POST /webhooks/10000/queue
{ "fulfillment": { "id": 619231, "line_items": [ { "product_id": 121000, "quantity": 2, "sku": "MYSKU123" } ], "order_id": 600001, "service": "BoxC Parcel", "shipment_id": 1521231, "shop": { "id": "my-test-shop", "order_id": "#1002" }, "tracking_number": null, "tracking_url": null, "warehouse_id": "WH0HKG01" } }
HTTP/1.1 201 Created
PUT /webhooks/100000
{ "webhook": { "address": "https://www.example.com/path/2/update" } }
HTTP/1.1 200 OK
{ "webhook": { "active" true, "address": "https://www.example.com/path/2/update", "created": "2019-10-04 16:10:15", "id": 100000, "topic": "shipments_status", "updated": "2019-10-05 12:54:07" } }
DELETE /webhooks/100000
HTTP/1.1 200 OK