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.

Note: Webhook subscriptions are scoped only to the application that they're registered to which means other applications can't read, modify, or delete them.

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 three additional HTTP headers added to the webhook event to aid applications in processing them.

  • 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. Events with more than 11 consecutive failed attempts will be evicted from the queue and the associated webhook deleted so that future events are no longer triggered.

The address must respond within 5 seconds overall or it will be considered a failed attempt. If you believe it will take longer than 5 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 11 times (~34 hours) before deleting the 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:\/\/www.boxc.com\/h\/track?id=9261290185965500000103",
        "warehouse_id": "WH0HKG01"
    }
}

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 tracking event changes the shipment status.

{
    "shipment": {
        "chargeable_weight": 0.4,
        "event": {
            "code": 200,
            "city": "AUSTIN",
            "province": "TX",
            "postal_code": "78701",
            "time": "2019-10-10 12:12:12"
        },
        "gross_weight": 0.235,
        "id": 1521231,
        "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

address

{"address": "https://www.boxc.com/path/to/script"}

String (Required) - The URL for the webhook that will process the event. It can be updated. Max length: 128.
created

{"created": "2019-10-05 15:43:03"}

String - The date and time the webhook was created. Set by the system.
id

{"id": 201921}

Integer - The unique ID of the webhook. Set by the system.
key

{"key": "9FkaaYZILF9pWHqJzXDD"}

String (Required) - A string between 16 and 32 characters long set by the application or user and used for calculating the HMAC digest of a webhook event. It can be updated but is not readable after creation. It doesn't have to be unique.
topic

{"topic": "shipments_status"}

String (Required) - The topic the user wishes to subscribe to. Immutable.
updated

{"updated": "2019-10-05 19:12:00"}

String - The date and time the webhook was last updated. Set by the system.
GET
/webooks/{id}
Retrieves a webhook
request
GET /webhooks/100001
response

HTTP/1.1 200 OK

{
    "webhook": {
        "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
Creates a webhook
request
POST /webhooks
{
	"webhook": {
		"address": "https://www.example.com/path",
		"key": "9FkaaYZILF9pWHqJzXDD",
		"topic": "fulfillments_complete"
	}
}
response

HTTP/1.1 201 Created

{
    "webhook": {
        "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/{id}/queue
Adds an event to the webhook's queue. Used for testing.
request
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"
    }
}
response

HTTP/1.1 201 Created


		
PUT
/webhooks/{id}
Updates a webhook
request
PUT /webhooks/100000
{
	"webhook": {
		"address": "https://www.example.com/path/2/update"
	}
}
response

HTTP/1.1 200 OK

{
    "webhook": {
        "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/{id}
Deletes a webhook
request
DELETE /webhooks/100000
response

HTTP/1.1 200 OK