Skip to main content

What are webhooks?

Webhooks are a way for Yorlet to send real-time notifications to your server about events that happen in your Yorlet account. When an event occurs, Yorlet sends an HTTP POST request to the webhook’s configured URL with a payload of the event data.

Use cases

Webhooks are useful for a variety of use cases, such as:
  • Sending notifications to your server when events are created in your account.
  • Updating your database when events occur in your account.
  • Triggering actions in thrid party services like Zapier, when events occur in your account.

Events overview

Yorlet generates events for various actions that occur in your account. You can subscribe to specific events to receive notifications about them. For example, you can subscribe to the customer.created event to receive a notification when a new customer is created in your account. See the full list of event types for everything you can subscribe to.

Webhook payloads

Each delivery is an HTTP POST request with a JSON body describing the event:
{
  "id": "evt_1a2b3c4d",
  "object": "event",
  "created": 1718712000,
  "type": "customer.created",
  "data": {
    "object": { "id": "cus_123", "object": "customer" },
    "previous_attributes": null
  },
  "request": {
    "id": "req_abc",
    "idempotency_key": null,
    "from_dashboard": false,
    "customer_portal": false
  }
}
FieldDescription
idUnique identifier for the event.
objectAlways event.
createdTime the event was created, as a Unix timestamp (seconds).
typeThe event type, e.g. customer.created. See the full list.
data.objectThe API resource the event relates to, at the time the event occurred.
data.previous_attributesFor *.updated events, the keys that changed and their previous values. null otherwise.
requestDetails of the API request that triggered the event, including the idempotency_key if one was provided.
accountOnly present on endpoints configured for connected accounts; the ID of the account the event belongs to.
Your endpoint should respond with a 2xx status code as quickly as possible to acknowledge receipt. Any other status code (or a network error) is treated as a failed delivery and is retried — see Retries.

Securing your webhooks

Because your webhook URL is publicly reachable, you should verify that each request genuinely came from Yorlet before acting on it. Every endpoint has a signing secret that Yorlet uses to sign deliveries, letting you confirm both the authenticity and the freshness of each request.

The signing secret

The signing secret is generated automatically when you create an endpoint and begins with whsec_. It is sensitive and is only returned when you create, retrieve, or roll an endpoint — it is never included in list responses, so store it securely when you first receive it.
{
  "object": "webhook_endpoint",
  "id": "we_1a2b3c4d",
  "url": "https://example.com/yorlet/webhooks",
  "signing_secret": "whsec_..."
}

The Yorlet-Signature header

When an endpoint has a signing secret, Yorlet includes a Yorlet-Signature header with each delivery:
Yorlet-Signature: t=1718712000,v1=5257a869e7ec...
The header contains two comma-separated values:
ValueDescription
tThe timestamp the signature was generated, in seconds since the Unix epoch.
v1The signature, an HMAC-SHA256 (hex encoded) of the signed payload.
The signed payload is the timestamp and the raw request body joined with a .:
signed_payload = {t}.{raw_request_body}
signature      = HMAC_SHA256(signing_secret, signed_payload)

Verifying signatures

1

Extract the timestamp and signature

Parse the Yorlet-Signature header to read the t (timestamp) and v1 (signature) values.
2

Recompute the signature

Concatenate the timestamp, a ., and the raw request body (the exact bytes received — do not parse and re-serialize the JSON first, as that can change the payload). Compute an HMAC-SHA256 of this string using your endpoint’s signing secret as the key, and hex encode it.
3

Compare the signatures

Compare your computed signature with the v1 value using a constant-time comparison. If they match, the request is authentic.
4

Guard against replays

Reject requests where the timestamp is outside an acceptable tolerance (for example, more than five minutes from the current time) to protect against replay attacks.
You must read the raw request body to verify the signature. Many frameworks parse the body into an object before your handler runs; re-serializing that object can produce different bytes and cause verification to fail. Configure your framework to expose the raw body for your webhook route.
The following example verifies a signature in Node.js:
import crypto from 'node:crypto';

const TOLERANCE_SECONDS = 60 * 5;

function verifyYorletSignature(rawBody, signatureHeader, signingSecret) {
  const parts = Object.fromEntries(
    signatureHeader.split(',').map((part) => part.split('='))
  );
  const timestamp = Number(parts.t);
  const signature = parts.v1;

  // Reject stale requests to mitigate replay attacks.
  if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > TOLERANCE_SECONDS) {
    return false;
  }

  const expected = crypto
    .createHmac('sha256', signingSecret)
    .update(`${timestamp}.${rawBody}`)
    .digest('hex');

  // Constant-time comparison.
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Rolling your signing secret

If a signing secret is ever exposed, roll it to generate a new one. Rolling immediately invalidates the previous secret, so update your endpoint with the new value as soon as you roll it.
curl https://api.yorlet.com/v1/webhook_endpoints/{id}/roll_secret \
  -X POST \
  -H "Authorization: Bearer {access_token}"
The response includes the endpoint with its new signing_secret.

Retries

If your endpoint does not return a 2xx status code, Yorlet retries the delivery with an exponential backoff over several attempts. Make sure your handler is idempotent: a single event may be delivered more than once, so use the event id to detect and ignore duplicates you have already processed.