πŸ‘Ύ

Enabling Webhooks

Send an email to [email protected] or schedule a call to find out more about your use case and timeline and we can get you started and walk you through the process of using our webhook solution.

We support one webhook per account and can call your webhook for the following events.

Event Resource

Event Name

Description

item

item.create

A new Item was created

item

item.status_change

The status of an Item has changed

Payload Structure

You will receive a JSON payload with the following structure.

{
  "company_id":"53e47d2e-a82c-4dca-9cf2-45af6040bc6c",
  "event_name":"item.create",
  "event_resource":"item",
  "object_id":"f116a4bb-ea1e-4578-ba82-af22c435b108"
}

Field

Description

company_id

The company the resource belongs to

event_name

The name of the event (e.g. item.status_change)

event_resource

The resource of the event (e.g. item)

object_id

The ID of the resource

Requirements

Your endpoint needs to do the following:

  1. Use HTTPS
  2. Respond within 1 second with a 200 ok status code
  3. There is no body in the response
  4. There are no cookies in the response headers
  5. If the webhook does not pass our signature verification, a 401 unauthorized status code is returned

Signature Verification

The Routable-Signature is generated with HMAC-SHA256 on an input and a secret.

The input is generated by concatenating the Routable-Signature-Timestamp, a . and the webhook request payload.

The Routable-Signature-Timestamp in the header and as part of the signature, prevents replay attacks. And timestamp over 5 minutes must be disregarded.

Steps

  1. Create the input by concatenating the Routable-Signature-Timestamp, a . and the webhook request payload.
  2. Compute the HMAC with SHA-256 using your webhook secret as the key and the input as the message. Convert to a string in base-16, hexadecimal format.
  3. Compare the expected signature with the Routable-Signature header. If the values are not equal, then the webhook is invalid.
  4. Compare the current time against the Routable-Signature-Timestamp header. If it's past 5 minutes, then the webhook is invalid.
  5. Compare the company_id in the JSON payload against the known company_id linked to the Routable-Signature. If the values are not equal, then the webhook is invalid.

Sample

We've included some sample implementations below...

import hashlib
import hmac
from datetime import datetime, timezone
import json


def is_routable_webhook_valid(routable_signature, routable_signature_timestamp, request_body):
    secret = "4fda696dda01568182a60b8d639db3c48a926f0021e336211f64c59267919be5"

    # Check signature
    message = bytes(f"{routable_signature_timestamp}.", "utf-8") + request_body
    key = bytes(secret, "utf-8")
    our_signature = hmac.new(key, message, hashlib.sha256).hexdigest()
    if our_signature != routable_signature:
        return False

    # Check timestamp
    now = datetime.now(timezone.utc)
    timestamp = datetime.fromisoformat(routable_signature_timestamp)
    if ((now - timestamp).total_seconds() / 60.0) > 5:
        return False

    # Verify company id
    try:
        request_json = json.loads(request_body)
        my_company_id = "3f8fe2e9-d80e-45b9-8655-060a8b60fef5"
        if "company_id" not in request_json or request_json["company_id"] != my_company_id:
            return False
    except:
        return False

    return True
const crypto = require('crypto');

const hmac = crypto.createHmac('sha256', secret);

// Ingest the timestamp from the Routable-Signature-Timestamp header
hmac.update("2021-05-25T20:34:17.042353+00:00");

// Add a period between them
hmac.update(".");

// Ingest the body
hmac.update('{"company_id": "bf24af31-531f-41a0-abc3-11c92958c31b", "event_name": "item.create", "event_resource": "item", "object_id": "f116a4bb-ea1e-4578-ba82-af22c435b108"}');

// Compute the signature
const signature = hmac.digest("hex");

Pausing and Disabling

🚧

If your webhooks are paused or disabled...

You will stop receiving web hooks and must contact support to re-enable.

If you return something other than the following status codes, your webhooks will be paused:

  • 200 ok
  • 502 bad gateway
  • 503 service unavailable
  • 504 gateway timeout

A few things will disable your endpoint:

  • Having a webhook not return a 200 ok for all the retries
  • Not following the configuration guidelines above

Retries

Attempt

Time since first attempt

1

0

2

1 minute

3

15 minutes

4

1 hour

5

3 hours

6

6 hours

7

12 hours

8

24 hours

9

48 hours


Did this page help you?