Webhooks Overview

Webhooks allow app developers to be notified, in near real-time, when specific events occur on a BigCommerce store. For example, your app may need to perform an action when a new order is created, a product’s inventory decreases, or an item is added to a shopper’s cart. When a subscribed event occurs on a store, BigCommerce will POST a payload to your app’s callback URI so your app can take some action based on that event.

Multiple Events Are Triggered during Bulk Data Imports

Bulk data imports will trigger the relevant events for every record affected. For example, if you have a hook on store/product/created, when the merchant imports 2,000 products, we will send 2,000 individual callback events.


Authentication

Webhooks are authenticated using Oauth and support the JSON media type. Basic auth and XML are not supported.

Before you can begin to send and receive requests, you must have the following:

  • A store: You can get a sandbox store by joining the Partner Program.
  • OAuth Client ID: Obtained by creating an API Account.
  • OAuth token: Obtained by creating an API Account.
  • Valid TLS/SSL configuration: Verify your app server’s setup at the following site: https://sslcheck.globalsign.com

Connection Breakers

Any one of the following conditions on your app server will cause a connection failure:

  • Hostname/DNS mismatch.
  • Self-signed certificate.
  • Intermediate certificates not loaded.

Lightweight Callback Payload

When a subscribed event occurs, we send a light payload with only minimum details regarding the event that’s been triggered. This gives you maximum flexibility as to how you want to handle the notification in your application. For instance, if you subscribe to the store/order/statusUpdated event, we’ll send you the order ID when the status is updated. You might want to handle the notification by fetching the full order details via a request to the Orders resource.

Example Lightweight Callback Payload

{
 "store_id":11111,
 "producer":"stores/abcde",
 "scope":"store/order/statusUpdated",
 "data":{
         "type":"order",
         "id":173331
        },
 "hash":"3f9ea420af83450d7ef9f78b08c8af25b2213637"
 }
Name Definition
store_id A numerical identifier that is unique to each store.
producer Will always follow the pattern stores/store_hash. This is the store that created the webhook.
scope The event registered when the webhook was created.
data A lightweight description of the event that triggered the webhook. Will vary depending on the event registered.
hash The payload data json encoded then passed through sh1 encryption.

Request and Response

Never worked with webhooks before? Check out the tutorial on creating webhooks.

All webhooks requests must include the following in their HTTP headers:

Accept: application/json
Content-Type: application/json
X-Auth-Client: <the OAuth client id>
X-Auth-Token: <the OAuth token>

Example Create a Webhook
/POST https://api.bigcommerce.com/stores/{{store_hash}}/v2/hooks

curl -X POST \
  https://api.bigcommerce.com/stores/store_hash/v2/hooks \
  -H 'Accept: application/json' \
  -H 'X-Auth-Client: your-client-id \
  -H 'X-Auth-Token: your-auth-token \
  -d '{
  "scope": "store/cart/lineItem/*",
  "destination": "https://myapp.herokuapp.com/",
  "is_active": true

Example Response 201 Created
/POST https://api.bigcommerce.com/stores/{{store_hash}}/v2/hooks

    {
        "id": 14270456,
        "client_id": "your-client-id",
        "store_hash": "your_store_hash",
        "scope": "store/cart/lineItem/*",
        "destination": "https://779aca97.ngrok.io/webhooks",
        "headers": null,
        "is_active": true,
        "created_at": 1531326542,
        "updated_at": 1531337178
    }
Name Description Type
id A read-only value that uniquely identifies a webhook object. Do not attempt to set this value in a PUT or POST. integer
client_id The OAuth client ID that uniquely identifies your application. BigCommerce returns this name-value pair in the JSON body of its responses. string
store_hash The hash value that uniquely identifies the store. Your application does not need to set this value via the JSON object; instead, you pass it in the path of your API requests. string
scope Value is the event you would like to listen for. See List of Webhook Events for the full list of possibilities. Wild Cards are supported for scope. (Required) string
destination value is the callback’s fully qualified URI. This should be an endpoint configured on your app server to receive webhook payloads. (Required) string
headers The headers object contains one or more name-value pairs, both string values. If you choose to include a headers object, BigCommerce will include the name-value pair(s) in the HTTP header of its POST requests to your callback URI at runtime. While this feature could be used for any purpose, one is to use it to set a secret authorization key and check it at runtime. This provides an additional level of assurance that the POST request came from BigCommerce instead of some other party, such as a malicious actor. (Optional) string
is_active Value specifies whether a webhook is active or inactive. By default, new webhooks will be set to be inactive and will have a blank value. If you want to create a webhook that should be active initially, you can pass the following name-value pair: “is_active”: true. (Optional) boolean
created_at The time at which the webhook was created. date-time Unix Epoch
updated_at The time at which the webhook was last updated. date-time Unix Epock

An HTTP 201 response indicates that the webhook was set successfully.

One-Minute Timeout

Following the creation of a webhook, it can take up to one minute for BigCommerce to start sending POST requests to your callback URI.

Example Get All Webhooks
/GET https://api.bigcommerce.com/stores/{{store_hash}}/v2/hooks

//Response 200 OK

[
    {
        "id": 14270466,
        "client_id": "your-client-id",
        "store_hash": "your_store_hash",
        "scope": "store/product/created",
        "destination": "https://779aca97.ngrok.io/webhooks",
        "headers": null,
        "is_active": true,
        "created_at": 1531326542,
        "updated_at": 1531337178
    },
    {
        "id": 14270713,
        "client_id": "your-client-id",
        "store_hash": "your_store_hash",
        "scope": "store/product/updated",
        "destination": "https://779aca97.ngrok.io/webhooks",
        "headers": null,
        "is_active": false,
        "created_at": 1531338589,
        "updated_at": 1531338589
    }
]

Example Get a Single Webhook
/GET https://api.bigcommerce.com/stores/{{store_hash}}/v2/hooks/{{id}}

{
    "id": 14270466,
    "client_id": "your-client-id",
    "store_hash": "your_store_hash",
    "scope": "store/product/created",
    "destination": "https://779aca97.ngrok.io/webhooks",
    "headers": null,
    "is_active": false,
    "created_at": 1531326542,
    "updated_at": 1531337178
}


Example Update a Webhook
https://api.bigcommerce.com/stores/{{store_hash}}/v2/hooks/{{id}}

Update a webhook using the id. Once the webhook is created all the fields below can be changed via an update request.

{
 "scope": "store/product/updated",
 "destination": "https://779aca97.ngrok.io/webhooks",
 "is_active": false
}


//Response 200 OK

{
    "id": 14270466,
    "client_id": "ejoftto9hv8xlip01cckcg53v7g3lrl",
    "store_hash": "jrah6gmn",
    "scope": "store/product/created",
    "destination": "https://779aca97.ngrok.io/webhooks",
    "headers": null,
    "is_active": false,
    "created_at": 1531326542,
    "updated_at": 1531337178
}

Example Delete a Webhook
https://api.bigcommerce.com/stores/{{store_hash}}/v2/hooks/{{id}}

//Response 200 OK
{
    "id": 14270466,
    "client_id": "ejoftto9hv8xlip01cckcg53v7g3lrl",
    "store_hash": "jrah6gmn",
    "scope": "store/product/created",
    "destination": "https://779aca97.ngrok.io/webhooks",
    "headers": null,
    "is_active": false,
    "created_at": 1531326542,
    "updated_at": 1531337178
}

There is not a way to delete all webhooks on a store. Run a GET request for the webhook id, then send a request to the delete URI to remove each one. It returns a 200 OK for the response with the deleted hook. When requesting a list of hook, the hook id is not available.

If webhooks are no longer being used, either delete them or set is_active:false.


Receiving the Callback

You’ll need to build an application and configure your server to receive the callback we send when events are triggered.

Need to set up a quick destination URL for testing? See Tools for Debugging and Testing Webhooks.


Respond to Webhook Callbacks

You’ll need to build an application and configure your server to receive the callback we send when events are triggered.

To acknowledge that you received the webhook without issue, your server should return a 200 HTTP status code. Any other information you return in the request headers or request body will be ignored. Any response code outside the 200 range, including 3_xx_ codes, will indicate to us that you did not receive the webhook. When a webhook is not received (for whatever reason), we will retry the callback as described below.

Need to set up a quick destination URL for testing? See Tools for testing webhooks.


Callback Retry Mechanism

The webhooks service will do its best to deliver events to your callback URI. It is best practice for your application to respond to the callback before taking any other action that would slow its response to our service. If an app server responds to a webhook payload with anything other than a 2_xx_ response, or times out and indicates the payload has not been received, the following process will determine whether your URI gets blacklisted.

Our webhook service may send many payloads to a single URI in quick succession. Because of this, we use a sliding scale across a 2 minute window to calculate a callback response success rate for each remote destination. When the webhooks service recieves a 2_xx_ in response to a webhook payload, we raise your success count. When we do not receive a response or the remote server times out, we increment your failure count. Based on this count, the service calculates your URI’s success rate.

The webhook service flow is as follows:

  1. Once a webhook is triggered, the service checks if your callback URI is on the blacklist
  2. If it’s not, we calculate a success ratio for your remote server based on your success/failure count in a 2 minute window
  3. If at any point in the two minute window your success/failure ratio dips below 90%, your URI will be blacklisted
  4. Your domain will be blacklisted for 3 minutes
  5. Webhook events triggered during this time are sent to our retry queues to be executed later when the domain is no longer blacklisted and once the retry queue time has elapsed.

100 response count threshold

The initial 100 responses your remote server sends to our webhook service do not count towards your success rate.


After an initial blacklist period, we will send the webhook notification to the retry queue immediately.

The webhook dispatcher will then attempt several retries (at increasing intervals) until the maximum retry limit is reached.

Retries Based on Subscriber Domain, Not by Specific Hooks

The webhook dispatcher determines whether retries are needed based on responses from the subscribed domain as a whole, not by specific hooks. For example, domain.com/webhook-1 and domain.com/webhook-2 will affect each other for failures and retries.

Retry Intervals

  • 60 seconds after the most recent failure
  • 180 seconds after the most recent failure
  • 180 seconds after the most recent failure
  • 300 seconds after the most recent failure
  • 600 seconds after the most recent failure
  • 900 seconds after the most recent failure
  • 1800 seconds after the most recent failure
  • 3600 seconds after the most recent failure
  • 7200 seconds after the most recent failure
  • 21600 seconds after the most recent failure
  • 50400 seconds after the most recent failure
  • 86400 seconds (24 hours) after the most recent failure

After the final retry attempt (cumulatively, 48 hours after the first delivery attempt), the webhook will automatically be deactivated, and we will send an email to the developer’s email address registered on the subscribing app. You can reactivate the webhook by setting the is_active flag back to true via a /PUT request to the hooks resource.


Webhook Security

To ensure that webhook payloads are secure against activity by a malicious actor, we take a three-pronged approach:

  • Webhook payloads contain minimal information about the store and event, for example the ID identifying the order or cart. To access potentially sensitive information on a store, a malicious actor would need to be fully authenticated against that store’s API in order to request full details.
  • Webhook payloads are sent over a TLS-encrypted connection.
  • For added security, you can include custom headers in your webhook creation request, and these headers will be sent in the payload when an event you subscribe to occurs. If your app endpoint is secured by basic authentication, you could set your own basic auth headers to authenticate the payload at runtime.

Example Webhook Customer Header

{
"scope": "store/cart/lineItem/*",
  "destination": "https://myapp.herokuapp.com/",
  "is_active": true,
  "headers": {
  	"User-Name": "Hello",
  	"Password": "Goodbye"
  }
}

Troubleshooting

Why am I not receiving event payloads to my callback URI?

If your app does not return an HTTP 2_xx_ to BigCommerce after receiving the webhook event payload, BigCommerce considers it a failure. BigCommerce will keep trying for a little over 48 hours. At the end of that time, BigCommerce sends an email to the email address set during app registration and disables the webhook by setting the is_active flag to false.

You can proactively check to make sure that everything is OK by periodically making a GET request and checking the is_active flag.

If you receive an email or discover that the is_active flag has been flipped to false, try the following:

Check to see if your app is responding to the event payload with something other than HTTP 200. Check to make sure that your server has a valid TLS/SSL setup. One way to do this is by visiting the following website: https://sslcheck.globalsign.com. Any of the following will cause the TLS/SSL handshake to fail: Self-signed certificate. Host name of the certificate does not match the server’s DNS. Your server’s key or trust store has not been loaded up with the intermediate certificates necessary to establish the chain of trust. Once you have resolved the issue preventing the connection, send a PUT request to flip the is_active flag back to true. This will cause BigCommerce to start sending the event payloads to your callback URI again.

Why am I not receiving a 201 response after creating a webhook?

After sending a POST request to create a webhook, you should get an HTTP 201 back. If you do not, check your TLS/SSL setup and be sure that your request contains the following headers:

 Accept: application/json
 Content-Type: application/json
 X-Auth-Client: <the OAuth client id>
 X-Auth-Token: <the OAuth token>

Tools for Debugging and Testing Webhooks

ngrok
As you are building your integration, you might want to test webhooks on your local dev machines.

We suggest using ngrok, which you can use to easily set up tunnels between a server running on localhost and a public URL. This will enable you to send our webhooks to your localhost environments via a public URL. No production push is required.

Need help on ngrok and webhooks see our tutorial.

Webhook Tester
This allows for webhooks to be quickly tested or checked.


Resources