swagger: '2.0' info: x-logo: url: https://storage.googleapis.com/boxc_cdn/public/boxc-logo.png altText: BoxC title: BoxC CalculateDuty Webhooks API version: '1.123' description: 'A simple but powerful logistics API that drives international ecommerce by utilizing a single integration with access to dozens of carriers and global markets. BoxC can complete every leg or only select steps of a shipment''s journey on your behalf with our routing engine. ' schemes: - https tags: - name: Webhooks x-displayName: Webhooks description: "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.\n\n**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.\n### Address Rules\nTo 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:\n\n- Must be RFC compliant (include HTTP/S).\n- Must include a valid hostname (example: www.boxc.com).\n- Must include a path and can't be just a domain or IP address (example: http://boxc.com/path/to/script).\n- Can't include localhost in the hostname.\n- Must be less than or equal to 128 characters in length.\n\n### HTTP Headers\nThere are four additional HTTP headers added to the webhook event to aid applications in processing them.\n\n- **User-Agent** - Always \"BoxC/1.0 Webhook\" for filtering webhook requests.\n- **X-BoxC-Hmac-SHA256** - Base64 encoded HMAC digest. Useful for verifying the event is authentic (example: Ikaxp9lMrkNXb6kxVhYxxiYDZplIN1kQcHV6gK3duFk=).\n- **X-BoxC-Topic** - The subject of the event (example: shipments_status).\n- **X-BoxC-Account** - The user ID affected by the event (example: 9512).\n### Verifying Events\nA `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](https://en.wikipedia.org/wiki/Base64), and compare it to the X-BoxC-Hmac-SHA256 header.\n\nKeys are provided by the application and must be between 16 and 32 characters long. They're not unique or immutable.\n### Payloads\nThe payload contains a JSON object with the data for the webhook event. The contents and structure of each payload varies depending on the topic.\n### Responding to Webhooks\nThe 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.\n\nThe `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.\n\nBoxC uses an exponential backoff timer for calculating the next attempt and will continue to retry three more times. Webhook addresses that don't respond with a successful status 1000 consecutive times are deactivated until the client updates the malfunctioning webhook. An email is sent to the OAuth client when a webhook is deactivated.\n### Testing Webhooks\nApplications 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.\n### Topics\nListed below are the current topics and their respective event structures that users may subscribe to.\n\n#### fulfillments_complete\n\nThis 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.\n```json\n{\n \"fulfillment\": {\n \"id\": 619231,\n \"line_items\": [\n {\n \"product_id\": 121000,\n \"quantity\": 2,\n \"sku\": \"MYSKU123\"\n }\n ],\n \"order_id\": 600001,\n \"service\": \"BoxC Parcel\",\n \"shipment_id\": 1521231,\n \"shop\": {\n \"id\": \"my-test-shop\",\n \"order_id\": \"#1002\"\n },\n \"tracking_number\": null,\n \"tracking_url\": null,\n \"warehouse_id\": \"WH0HKG01\"\n }\n}\n```\n\n#### fulfillments_update\n\nThis 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.\n```json\n{\n \"fulfillment\": {\n \"id\": 619231,\n \"order_id\": 600001,\n \"service\": \"BoxC Parcel\",\n \"shipment_id\": 1521231,\n \"shop\": {\n \"id\": \"my-test-shop\",\n \"order_id\": \"#1002\"\n },\n \"tracking_number\": \"9261290185965500000103\",\n \"tracking_url\": \"https:\\/\\/track.boxc.com\\/?id=9261290185965500000103\",\n \"warehouse_id\": \"WH0HKG01\"\n }\n}\n```\n\n#### manifests_complete\n\nThis event is triggered when a manifest finished processing and any related PDF documents are available for download.\n```json\n{\n \"manifest\": {\n \"created\": \"2022-08-02 12:12:12\",\n \"entry_point\": \"LAXI01\",\n \"exit_point\": \"SYD\",\n \"id\": 909447,\n \"forms\": [\n \"Toll_IPEC.pdf\"\n ],\n \"mawb_id\": null,\n \"overpacks\": [\n {\n \"carrier\": \"Toll\",\n \"created\": \"2021-08-01 00:26:05\",\n \"height\": 10,\n \"id\": 1002730,\n \"length\": 10,\n \"service\": \"BoxC Parcel\",\n \"terms\": \"DDU\",\n \"type86\": false,\n \"weight\": 5,\n \"width\": 10\n }\n ],\n \"total_shipments\": 4,\n \"warehouse_no\": \"02599225803\"\n }\n}\n```\n\n#### orders_status\n\nThis event is triggered when an order's status changes. Only orders updated to \"Exception\" will trigger this event.\n```json\n{\n \"order\": {\n \"created\": \"2020-02-27 12:12:12\",\n \"id\": 1831488,\n \"line_items\": [\n {\n \"product_id\": 123456,\n \"sku\": \"sku123\",\n \"quantity\": 1\n }\n ],\n \"placed_at\": \"2020-02-27 15:15:15\",\n \"service\": \"BoxC Priority\",\n \"status\": \"Exception\",\n \"shipping_address\": {\n \"company_name\": null,\n \"phone\": null,\n \"email\": null,\n \"name\": \"John Smith\",\n \"street1\": \"555 5TH AVE\",\n \"street2\": null,\n \"city\": \"NEW YORK\",\n \"province\": \"NY\",\n \"postal_code\": \"10001\",\n \"country\": \"US\"\n },\n \"shop\": {\n \"id\": \"my-test-shop\",\n \"order_id\": \"123456\"\n }\n }\n}\n```\n\n#### shipments_label\n\nThis 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\".\n```json\n{\n \"shipment\": {\n \"carrier\": \"Janio\",\n \"content_type\": \"application\\/pdf\",\n \"data\": \"aHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g\\/dj1kUXc0dzlXZ1hjUQ==\",\n \"id\": 1521231,\n \"tracking_number\": \"9261290185965500000103\"\n }\n}\n```\n\n#### shipments_status\n\nThis event is triggered when a new tracking event is injected. The tracking event along with some shipment details is sent to the subscribed webhooks.\n```json\n{\n \"shipment\": {\n \"chargeable_weight\": 0.4,\n \"comments\": [\n \"Order123456\"\n ],\n \"entry_point\": \"TEST01\",\n \"event\": {\n \"carrier\": \"USPS\",\n \"code\": 200,\n \"city\": \"AUSTIN\",\n \"province\": \"TX\",\n \"postal_code\": \"78701\",\n \"country\": \"US\",\n \"time\": \"2019-10-10 12:12:12\",\n \"longitude\": null,\n \"latitude\": null\n },\n \"exit_point\": \"DFW\",\n \"gross_weight\": 0.235,\n \"id\": 1521231,\n \"images\": {\n \"pod\": [],\n \"scans\": []\n },\n \"order_number\": null,\n \"service\": \"BoxC Parcel\",\n \"status\": \"Delivered\",\n \"tracking_number\": \"9261290185965500000103\",\n \"volumetric_weight\": 0.4\n }\n}\n```\n" paths: /webhooks: get: tags: - Webhooks summary: GET /webhooks description: Retrieves a list of webhooks. operationId: getWebhooks consumes: - application/json produces: - application/json security: - JWT: - read_webhooks parameters: - in: query name: limit description: The number of results to return. default: 50 maximum: 100 required: false type: integer - in: query name: order description: The sort order of the results. Options are "asc" for ascending, or "desc" for descending. default: desc required: false type: string - in: query name: page_token description: Used for selecting the page after the initial query. required: false type: string x-codeSamples: - lang: cURL label: cURL source: "curl -H \"Authorization: Bearer \" \\\n -H \"Accept: application/json\" \\\n https://api.boxc.com/v1/webhooks\\?limit=50\\&order=desc\n" responses: '200': description: OK content: application/json: schema: type: object properties: webhooks: type: array items: $ref: '#/definitions/Webhook' next_page: type: string description: Page token. example: null '400': description: Bad Request content: application/json: schema: $ref: '#/definitions/BadRequest' examples: invalidToken: summary: Bad Request description: Invalid page token value: code: 1025 message: Invalid page token errors: - Invalid page token '401': $ref: '#/definitions/Unauthorized' '403': $ref: '#/definitions/Forbidden' '429': $ref: '#/definitions/RateLimit' post: tags: - Webhooks summary: POST /webhooks description: Creates a webhook. Clients may create multiple webhooks for the same user and topic as long as the `address` is unique. operationId: addWebhook consumes: - application/json produces: - application/json security: - JWT: - write_webhooks x-codeSamples: - lang: cURL label: cURL source: "curl -X POST https://api.boxc.com/v1/webhooks \\\n -H \"Authorization: Bearer \" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"webhook\": {\n \"address\": \"https://www.boxc.com/path/to/script\",\n \"key\": \"9FkaaYZILF9pWHqJzXDD\",\n \"topic\": \"shipments_status\"\n }\n }'\n" requestBody: required: true content: application/json: schema: type: object description: Webhook object properties: webhook: type: object properties: address: description: The URL for the webhook that will process the event. It can be updated. type: string format: uri maxLength: 128 example: https://www.boxc.com/path/to/script key: description: A secret key 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. type: string example: 9FkaaYZILF9pWHqJzXDD minLength: 16 maxLength: 40 topic: description: The topic the user wishes to subscribe to. Immutable. type: string example: shipments_status required: - address - key - topic required: - webhook responses: '201': description: OK content: application/json: schema: type: object description: Webhook object properties: webhook: $ref: '#/definitions/Webhook' '400': description: Bad Request content: application/json: schema: $ref: '#/definitions/BadRequest' examples: validation: summary: Validation error description: The request schema is invalid. value: code: 1000 message: 'Validation Error. /webhook: The required properties (topic) are missing' status: error errors: - '/webhook: The required properties (topic) are missing' badRequest: summary: Bad Request description: User is already subscribed to topic value: code: 1401 message: User is already subscribed to topic errors: - User is already subscribed to topic '401': $ref: '#/definitions/Unauthorized' '403': $ref: '#/definitions/Forbidden' '429': $ref: '#/definitions/RateLimit' '500': description: Internal Server Error content: application/json: schema: $ref: '#/definitions/InternalServerError' examples: internalServerError: summary: Internal Server Error description: Webhook can't be created value: code: 1402 message: Webhook can't be created errors: - Webhook can't be created /webhooks/{id}: get: tags: - Webhooks summary: GET /webhooks/{id} description: Retrieves a webhook. operationId: getWebhooksById consumes: - application/json produces: - application/json security: - JWT: - read_webhooks parameters: - name: id in: path description: The webhook ID required: true type: integer x-codeSamples: - lang: cURL label: cURL source: "curl -H \"Authorization: Bearer \" \\\n -H \"Accept: application/json\" \\\n https://api.boxc.com/v1/webhooks/{id}\n" responses: '200': description: OK content: application/json: schema: type: object properties: webhook: $ref: '#/definitions/Webhook' '401': $ref: '#/definitions/Unauthorized' '403': $ref: '#/definitions/Forbidden' '404': description: Not Found content: application/json: schema: $ref: '#/definitions/NotFound' examples: notFound: summary: Not Found description: Webhook not found value: code: 1400 message: Webhook not found errors: - Webhook not found '429': $ref: '#/definitions/RateLimit' put: tags: - Webhooks summary: PUT /webhooks/{id} description: Updates a webhook. operationId: updateWebhook consumes: - application/json produces: - application/json security: - JWT: - write_webhooks parameters: - name: id in: path description: The webhook ID required: true type: integer x-codeSamples: - lang: cURL label: cURL source: "curl -X PUT https://api.boxc.com/v1/webhooks/{id} \\\n -H \"Authorization: Bearer \" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"webhook\": {\n \"address\": \"https://www.boxc.com/path/to/script\"\n }\n }'\n" requestBody: required: true content: application/json: schema: type: object properties: webhook: type: object properties: address: description: The URL for the webhook that will process the event. type: string format: uri maxLength: 128 example: https://www.boxc.com/path/to/script required: - webhook responses: '200': description: OK content: application/json: schema: type: object description: Webhook object properties: webhook: $ref: '#/definitions/Webhook' '400': description: Bad Request content: application/json: schema: $ref: '#/definitions/BadRequest' examples: validation: summary: Validation error description: The request schema is invalid. value: code: 1000 message: 'Validation Error. /webhook/key: Minimum string length is 16, found 12' status: error errors: - 'Validation Error. /webhook/key: Minimum string length is 16, found 12' '401': $ref: '#/definitions/Unauthorized' '403': $ref: '#/definitions/Forbidden' '404': description: Not Found content: application/json: schema: $ref: '#/definitions/NotFound' examples: notFound: summary: Not Found description: Webhook not found value: code: 1400 message: Webhook not found errors: - Webhook not found '429': $ref: '#/definitions/RateLimit' delete: tags: - Webhooks summary: DELETE /webhooks/{id} description: Deletes a webhook. operationId: deleteWebhook consumes: - application/json produces: - application/json security: - JWT: - write_webhooks parameters: - name: id in: path description: The webhook ID required: true type: integer x-codeSamples: - lang: cURL label: cURL source: "curl -X DELETE https://api.boxc.com/v1/webhooks/{id} \\\n -H \"Authorization: Bearer \" \\\n -H \"Content-Type: application/json\"\n" responses: '200': description: OK '401': $ref: '#/definitions/Unauthorized' '403': $ref: '#/definitions/Forbidden' '404': description: Not Found content: application/json: schema: $ref: '#/definitions/NotFound' examples: notFound: summary: Not Found description: Webhook not found value: code: 1400 message: Webhook not found errors: - Webhook not found '429': $ref: '#/definitions/RateLimit' '500': description: Internal Server Error content: application/json: schema: $ref: '#/definitions/InternalServerError' examples: internalServerError: summary: Internal Server Error description: Webhook can't be deleted value: code: 1404 message: Webhook can't be deleted errors: - Webhook can't be deleted /webhooks/{id}/queue: post: tags: - Webhooks summary: POST /webhooks/{id}/queue description: Adds an event to the webhook's queue for testing your subscriptions. Refer to [Webhooks](/#tag/Webhooks) for sample payloads. operationId: addWebhookEvent consumes: - application/json produces: - application/json security: - JWT: - write_webhooks parameters: - name: id in: path description: The webhook ID required: true type: integer x-codeSamples: - lang: cURL label: cURL source: "curl -X POST https://api.boxc.com/v1/webhooks/{id}/queue \\\n -H \"Authorization: Bearer \" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"shipment\": {\n \"chargeable_weight\": 0.4,\n \"comments\": [\n \"Order123456\"\n ],\n \"entry_point\": \"TEST01\",\n \"event\": {\n \"carrier\": \"USPS\",\n \"code\": 200,\n \"city\": \"AUSTIN\",\n \"province\": \"TX\",\n \"postal_code\": \"78701\",\n \"country\": \"US\",\n \"time\": \"2019-10-10 12:12:12\"\n },\n \"exit_point\": \"DFW\",\n \"gross_weight\": 0.235,\n \"id\": 1521231,\n \"order_number\": null,\n \"service\": \"BoxC Parcel\",\n \"status\": \"Delivered\",\n \"tracking_number\": \"9261290185965500000103\",\n \"volumetric_weight\": 0.4\n }\n }'\n" responses: '201': description: Created content: null '400': description: Bad Request content: application/json: schema: $ref: '#/definitions/BadRequest' examples: badRequest: summary: Bad Request description: Webhook event can't be enqueued due to an error value: code: 1405 message: Webhook event can't be enqueued due to an error errors: - Webhook event can't be enqueued due to an error '401': $ref: '#/definitions/Unauthorized' '403': $ref: '#/definitions/Forbidden' '404': description: Not Found content: application/json: schema: $ref: '#/definitions/NotFound' examples: notFound: summary: Not Found description: Webhook not found value: code: 1400 message: Webhook not found errors: - Webhook not found '429': $ref: '#/definitions/RateLimit' '500': description: Internal Server Error content: application/json: schema: $ref: '#/definitions/InternalServerError' examples: internalServerError: summary: Internal Server Error description: Webhook event can't be enqueued due to an error value: code: 1405 message: Webhook event can't be enqueued due to an error errors: - Webhook event can't be enqueued due to an error definitions: bad-request: type: object summary: Bad Request description: Validation error with the request properties: code: description: Error code. Refer to the list of [Errors](/#tag/Errors). type: integer message: description: Error message explaining the code. type: string status: type: string enum: - error example: error errors: description: Lists validation errors with the schema or the resource being operated on. type: array minItems: 1 maxItems: 5 items: type: string InternalServerError: $ref: '#/definitions/internal-server-error' Webhook: $ref: '#/definitions/webhook' NotFound: $ref: '#/definitions/not-found' BadRequest: $ref: '#/definitions/bad-request' unauthorized: description: Unauthorized content: application/json: schema: type: object summary: Unauthorized description: Lack of valid authentication credentials for the resource properties: code: description: Error code. Refer to the list of [Errors](/#tag/Errors). type: integer message: description: Error message explaining the code. type: string status: type: string enum: - error example: error errors: description: Displays processing error. type: array minItems: 1 maxItems: 1 items: type: string examples: accessToken: summary: Invalid access token description: Invalid access token value: code: 1005 message: Invalid access token errors: - Invalid access token not-found: type: object summary: Not Found description: Object not found or not owned by the user properties: code: description: Error code. Refer to the list of [Errors](/#tag/Errors). type: integer message: description: Error message explaining the code. type: string status: type: string enum: - error example: error errors: description: Duplicate of the error message type: array items: type: string internal-server-error: type: object summary: Internal Server Error description: Processing Error properties: code: description: Error code. Refer to the list of [Errors](/#tag/Errors). type: integer message: description: Error message explaining the code. type: string status: type: string enum: - error example: error errors: description: Displays processing error. type: array minItems: 1 maxItems: 1 items: type: string rate-limit: description: Too Many Requests content: application/json: schema: type: object summary: Too Many Requests description: Error for too many requests in a given time frame. See [Rate Limits](/#tag/RateLimit) for more information. properties: code: description: Error code. Refer to the list of [Errors](/#tag/Errors). type: integer message: description: Error message explaining the code. type: string status: type: string enum: - error example: error errors: description: Displays processing error. type: array minItems: 1 maxItems: 1 items: type: string examples: rateLimit: summary: Too Many Requests description: Too many requests. Please wait before trying again. value: code: 1015 message: Too many requests. Please wait before trying again. errors: - Too many requests. Please wait before trying again. Unauthorized: $ref: '#/definitions/unauthorized' Forbidden: $ref: '#/definitions/forbidden' webhook: type: object properties: active: description: Displays the webhook status. Inactive webhooks will not have events delivered until they're updated by the owner. type: boolean example: true readOnly: true address: description: The URL for the webhook that will process the event. type: string maxLength: 128 format: uri example: https://www.boxc.com/path/to/script created: description: The date and time the webhook was created. type: string example: '2024-07-18 14:10:01' format: datetime readOnly: true id: description: The unique ID of the webhook. type: integer example: 201921 readOnly: true topic: description: The topic the user wishes to subscribe to. Immutable. type: string enum: - fulfillments_complete - fulfillments_update - manifests_complete - orders_status - shipments_label - shipments_status example: shipments_status updated: description: The date and time the webhook was last updated. type: string example: '2024-07-19 12:16:41' format: datetime readOnly: true RateLimit: $ref: '#/definitions/rate-limit' forbidden: description: Forbidden content: application/json: schema: type: object summary: Forbidden description: Error relating to insufficient permissions for a resource properties: code: description: Error code. Refer to the list of [Errors](/#tag/Errors). type: integer message: description: Error message explaining the code. type: string status: type: string enum: - error example: error errors: description: Displays processing error. type: array minItems: 1 maxItems: 1 items: type: string examples: revoked: summary: Forbidden Authorization Revoked description: 'Forbidden: Authorization revoked' value: code: 1008 message: 'Forbidden: Authorization revoked' errors: - 'Forbidden: Authorization revoked' scope: summary: Forbidden Scope description: 'Forbidden: Missing required scope' value: code: 1009 message: 'Forbidden: Missing required scope' errors: - 'Forbidden: Missing required scope' securityDefinitions: JWT: type: http scheme: bearer bearerScheme: JWT in: header description: All operations require a JSON Web Token after completing an [OAuth2 flow](#tag/Authentication). PrivilegedClient: type: http scheme: bearer bearerScheme: JWT description: Some clients require special privileges to use operations. No additional scope is needed. x-servers: - url: https://api.boxc.com/v1 x-tagGroups: - name: Overview tags: - Introduction - Authentication - RateLimit - Paginate - Changelog - name: Operations tags: - CalculateDuty - Classify - Invoices - Users - ValidateAddress - Webhooks - name: Shipping tags: - Credentials - CustomsProducts - EntryPoints - Estimate - Labels - Manifests - Overpacks - Shipments - Track - name: Fulfillment tags: - Inbound - Orders - Products - Shops - Warehouses - name: Returns tags: - Reshipments - Returns - name: Data tags: - CarrierCredentials - DangerousGoods - Errors - Languages - CarrierParameters - ReturnsProcess - TrackingEvents