Webhooks

This guide is for setting up Webhooks to receive data from Shopmonkey.

Why use Webhooks

Webhooks are a powerful way to receive updates about events that occur in Shopmonkey. Webhooks allow you to automate responses to specific events without the need for continuous polling. This document will guide you through setting up and using webhooks effectively.

To enable webhook events, you need to register webhook endpoints. After registration, Shopmonkey will push real-time event data to your webhook endpoint when events happen in your Shopmonkey account. Shopmonkey uses HTTPS to send webhook events to your app as a JSON payload that includes an Event object (see below).

Receiving webhook events is useful for receiving asynchronous event notifications such as when a new Order is created.

Events

The Webhook Event is a JSON encoded payload and a set of HTTP headers.

HTTP Headers

The following headers are sent with every webhook:

  • Content-Type: Will always be application/json
  • User-Agent: Will always be Shopmonkey (+https://shopmonkey.io)
  • X-Attempt: The attempt number (starting at 1) for delivery of this webhook
  • X-Request-Id: A unique identifier for this delivery
  • webhook-id: A unique identifier for this webhook delivery attempt
  • webhook-signature: The webhook security signature for this delivery (see Secure your Webhook below)
  • webhook-timestamp: The webhook timestamp in seconds since epoch
  • webhook-version: The Shopmonkey webhook version specification. Currently, will be 3.

POST Body

The payload has the following top level JSON properties:

  • apiVersion: Matches the webhook-version HTTP Header value
  • operation: Will be one of: INSERT, UPDATE or DELETE
  • table: Will be the table name (snake case) that triggered the webhook
  • data: The payload of the object
  • diff: Only available in UPDATE operations. An array of strings which indicate the changes at the top-level object that triggered the update

All Webhooks will be sent as an HTTP POST.

HTTP responses status codes should be one of the following:

200
Successful request
201
Successful request
202
Successful request
429
Indicates a rate limit request which will be retried
500
An error on your side which will be retried

After a certain number of redelivery failures, the Event will be marked failed and your Webhook will be temporarily disabled. Once your API endpoint issue is resolved, you can manually re-enable your webhook in the Shopmonkey Webhook settings.

Event Types

In the Shopmonkey system, certain objects are normalized into multiple tables. To make it easier to generalize which Events you can subscribe to, we have aggregated them together for definition, however, you will receive different events based on different internal tables. In this documentation, we use the term table and object interchangeably.

The following events are supported:

Get Started

To get started, navigate to the Webhooks section inside Settings. You must have permission to view the Settings to get access to Webhooks.

webhook step1

Give your webhook a name, enter your endpoint API url and select one or more events for delivery.

webhook step2

Once you have deliveries, you will see them in the application:

webhook step3

Testing your Webhook

For testing, we recommend one of the following services to test webhook delivery payloads:

Secure your Webhook

We use the Webhook Standard specification for Webhook security.

To verify the authenticity of webhooks delivered by Shopmoneky we use an HMAC signature with pre-shared secret key which is only known to you and Shopmonkey (and configurable by you per configured Webhook).

Signature scheme

We sign the webhook payload POST body, webhook-id HTTP header and the webhook-timestamp HTTP header together as a concatenated string in the format: HMAC256(msgId.timestamp.payload,secret).

For example, if the msgId was 1234 and the timestamp was 1609459200 and the body was body, you would concatenate as follows: 1234.1609459200.body and use that as the input to the HMAC256 hashing algorithm along with the shared secret.

We set the HTTP header webhook-signature to the format: v1,signed where signed is the value from the HMAC in base64 encoded string.

If you rotate your secret, we will include all your previous keys up to 30 days after rotatation as space separated signatures.

For example: v1,Xxaz73AZiDcuUod3JbYZgy0yoinN16Vv/84NVgsWpvE= v1,T0rreKeTl3LzQ6MN1af1D611lg/05WnPUcKC6J3fBqc= would contain 2 signatures for 2 different secrets.

After the secret rotation has expired, we will no longer send this secret. This affords you the opportunity to continue validating old signatures for a period of time will migrating your API endpoint.

Validation

You should re-compute the HMAC signature by combining the strings your receive above from Shopmonkey and comparing the value with the value from the HTTP header webhook-signature. If they do not match, you must discard this webhook and not process it further.

There are a few considerations:

  • Use a constant time comparison function to compare the calculated with the expected signature. Failing to do so can expose you to timing-attacks and turn them into signing oracles.
  • Make sure to verify the webhook-timestamp HTTP header has a timestamp that is within some allowable tolerance of the current timestamp to prevent replay attacks.
  • Use the webhook-id HTTP header as an idempotency key to prevent accidentally processing the same webhook more than once (e.g. save the IDs in redis for 5 minutes).

Best Practices

The following are some suggested best practices for working with Webhooks:

  • Timeouts: Ensure your API endpoint responds quickly. If processing takes time, acknowledge receipt of the webhook and handle processing asynchronously. We will cancel the Webhook delivery if your API endpoint takes longer than 55 seconds to respond.
  • Retries & Duplicates: We will retry sending the webhook in case of a failure. Implement idempotency in your handling logic to prevent duplicate processing of the same event.
  • Minimize Events: Configure your webhook endpoints to receive only the types of events required by your integration. Listening for extra events (or all events) puts undue strain on your server and ours and we don't recommend it.
  • Rotate Shared Key: Rotate your shared secret periodically.
  • Keep Shared Key Private: Your shared secret is like a password. Make sure your store it securely and do not hard code this value in your code.
  • Validate Webhooks: A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, Shopmonkey includes a timestamp in the webhook-signature HTTP header. Because this timestamp is part of the signed payload, it's also verified by the signature, so an attacker can't change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.