Handling a Webhook Event

If you've gone through our Webhooks Quickstart, you should be able to receive events. Here, we'll talk about the events you'll receive and ways you might want to use them.

Event properties

Webhook events have a JSON body that always has as few top-level properties. Here's an example of the event that gets fired when a customer is created:

{
    "event_type": "customer.new",
    "idempotency_key": "733114a667199d09714d72d2bf55d69d",
    "data": {
        "vendor_name": "antler_db_inc",
        "customer_name": "test_customer"
    }
}

Note that there are three top-level properties:

  1. event_type is a string identifier for this type of event. Event types can be used to filter for the sorts of events you care about handling in your webhook endpoint.
  2. idempotency_key is a unique hash of this particular event. While we try to send events only once, we may resend events in a number of exceptional circumstances, such as if we are unsure if your endpoint received the event.
  3. data: the identifying information for records related to this event. For the time being, our payloads contain information that can be used to query additional information from our API, like a customer's unique name in the example above. Should you need more information on this customer, you can query for it using our HTTP API.

🚧

Webhook endpoints should be idempotent when possible

Since it is very hard to guarantee only-once delivery of webhook events, it is possible for your webhook endpoint to receive the same event more than once. Whenever possible, your webhook endpoint should be able to be called with the same event multiple times. We include an idempotency key to help uniquely identify an event, which can help identify the same event if it appears multiple times.

Signature

Octane signs every webhook event with an Octane-Signature header. This hash can be used to validate that the events came from Octane, and that they haven't somehow been tampered with in transit. For an added layer of security, you can validate the signature of messages received from Octane.

This signature is the hash of the entire payload. To generate this hash, we use a unique webhook secret, which we expose on the Credentials tab on the Settings page in our web portal.

Assuming you have your webhook secret, validating an event looks like this:

import hmac
import hashlib


def validate_event(secret: str, payload_body: str, signature: str) -> bool:
    """Validate the body of a webhook event
  
    Keyword arguments:
    secret         -- the webhook secret key for the account that owns the event
    paload_body   -- the body of the webhook event
    signature      -- the hash sent in the event's `Octane-Signature` header
  
    Returns true if the event is valid, false otherwise.
    """
  
    secret_bytes = secret.encode("utf-8")
    payload_bytes = payload_body.encode("utf-8")
    payload_hash = hmac.new(secret_bytes, payload_bytes, hashlib.sha256).hexdigest()
    return signature == payload_hash
const crypto = require("crypto");

/**
  Validate the body of a webhook event
  
  @param secret        -- the webhook secret key for the account that owns the event
  @param payloadBody   -- the body of the webhook event
  @param signature     -- the hash sent in the event's `Octane-Signature` header
  
  Returns true if the event is valid, false otherwise.
*/
function validateEvent(secret, payloadBody, signature) {
    const hash = crypto.createHmac("sha256", secret)
            .update(payloadBody)
            .digest("hex")
    
    return signature === hash;
}

Did this page help you?