GuidesRecipesAPI Reference

Webhooks

A quick overview of webhooks at Convictional

❗️

Heads up!

Webhooks do not currently support:

  • manual retrying, cancelling or queuing of requests
  • seeing a list of events or the status of individual events
  • authentication

Stability is high but not guaranteed.

Events are currently dispatched every minute.

Webhooks are intended as a way to simplify the implementation of an API integration. It is important to recognize that there is a limit to the guarantees we can make. For example, we can guarantee that there will be at least one delivery attempt per event. There may be instances of multiple delivery attempts from a webhook, it is important to monitor the UUIDs of the events to determine what has been processed. Furthermore, for any data that is critical there must be additional API integration to reconcile data at regular intervals.

Currently if you configure a webhook, our system will send that endpoint the affected piece of data; as well as an "event type" that describes what happened to that data.

For example, a order.fulfilled event denotes that a fulfillment was added to an order.

📘

Limitations of Convictional Events

Events are still subject to the syncing intervals of the platforms from where they came. This means that you will not get inventory updates or fulfillments as they happen but rather a burst of events when our workers run and sync new values from integrated platforms.

For a list of when these workers run please see this table.

Configuring webhooks

There are currently no self-serve methods to configure webhooks exposed by the Convictional API. In order to start using webhooks you must reach out to [email protected] and our Technical Engagement team can work with you to ensure that your desired event types are supported and enter configuration information into our system.

All you need to get started with webhooks currently is:
1. An endpoint that accepts HTTP POST requests
2. Idea of what data changes you want to subscribe to
3. A secret key used for payload validation

You can have a single webhook endpoint receive one or more event types and you can have as many different endpoints as you like.

You can also configure rate and burst limits for your webhooks if necessary.

🚧

Hosting Webhook Receivers

Currently webhook receivers must be publicly accessible endpoints using HTTPS.

Supported events

Since the list of supported events is changing rapidly so if you're interested in finding out more about this please email [email protected]

Request data model

Each request dispatched to your webhook listener function must accept the following data model.

PropertyData TypeNotesExample
idstringInternal UUID of the event. Useful for communicating with support in case of issues.626ca583-e709-4e1a-a876-0bd47c609a40
typestringType of the event. This basically tells you what happened and what the data means.product.selected
createdstringThis is the Date-Time stamp of when the event was created. This is not the time at which the request was sent.2021-10-19T14:48:22.544+00:00
dataobjectThis is the attached data to the event. Usually this will be the same data model that is exposed through our RESTful API. For example, the product.selected event will attach the same model as returned by this endpoint.Please see the API Documentation to see what data would be attached here.

Example:

{
  id: "616e45ce25ecfe1c81de6c02",
  type: "product.selected",
  created: "2021-10-19T14:48:22.544+00:00",
  data: {...}
}

Retrying requests and dealing with outages

While we do not guarantee delivery or only-once delivery we do have a truncated, exponential backoff retry mechanism in case there is an outage, network error or internal error.

Internally we use the following formula to figure out when a request should be retried in case it fails:
Min(2^n + random, max backoff) where max backoff is currently capped at 24 hours. This means that worst case scenario events will be retried once a day. The random part is a value between 0 and 1000 milliseconds that is used to avoid excessive bursting.

🚧

Retrying limitations

We will only retry webhooks for a maximum of 3 days from the creation of the event.

If you experienced an outage for longer than 3 days you can reach out to [email protected] and request for older events to be resent.

Security

❗️

Verifying Request

It is up to your webhook consumer to verify the authenticity of the webhook request.

Each webhook request that sent will have a Convictional-Signature HTTP Header that will contain a hash value used to verify that the payload of the event and the request itself are authentic.

The attached Convictional-Signature header contains a UNIX timestamp and a hash for every active secret you have configured delimited by commas.

📘

Rotating webhook secrets

In order to support no-outage secret rotations we support the ability to have more than one active secret at a time with automatic deactivation at a given time. A hash will be generated for each secret and appended to the header string.

The signature hash is generated by using combining the timestamp supplied in the header earlier with the string of the body separated by a period.

To avoid automatic escaping or parsing of escape sequences we must take the raw body buffer of the request body.
Then you must use SHA256 to encode the timestamp and requestBody delimited by a period and signed with the secret.

For example, if you configured a webhook with a secret of mySecret

Your function receives the following event:

{
  "id": "616e45ce25ecfe1c81de6c02",
  "type": "message.hello",
  "created": "2021-10-19T14:48:22.544+00:00",
  "data": { 
    "message": "hello world"
  }
}

with the following header:

Convictional-Signature: 1634751311,e93fbf11ce896938c6a42b55205bbbf38baec4658b05efc8dc1b6fa59e873f63

You can split that by , to get the timestamp, 1634751311, and the hash e93fbf11ce896938c6a42b55205bbbf38baec4658b05efc8dc1b6fa59e873f63

To validate that you must combine the body with the timestamp delimited by a period.

1634751311.{
  "id": "616e45ce25ecfe1c81de6c02",
  "type": "message.hello",
  "created": "2021-10-19T14:48:22.544+00:00",
  "data": { 
    "message": "hello world"
  }
}

Then generated a hash using the SHA256 algorithm signed with your secret.

If the signature you generate is the same one that is attached to the header then you know that this is a valid request that has not been tampered with and you can proceed to process that information.

You can use this tool to play around with SHA256 encodings: https://www.devglan.com/online-tools/hmac-sha256-online

Troubleshooting

Signatures don't match

If you're running into issues where your program is not generating the same signatures as the ones in the header try using the a raw byte representation of the request body to generate the signature with. Some web frameworks (e.g., Node) will automatically clean, interpret and unescape payloads which can influence the hash generation step.

Sample Code

More Info

If you are looking for more information on Webhooks with Convictional, we also have support documentation here.