Webhooks

Receive SIMCOAI workflow events in your own systems as they happen.

Events

What you can subscribe to

Workflow events fire when customer work changes state.

requested

A refund, booking or order query was captured from a call or chat.

approved

A person approved the request in the dashboard.

refunded

A refund was marked as completed.

confirmed

A booking was confirmed.

cancelled

The request was cancelled.

order-updated

An order query changed state.

Delivery

What a delivery looks like

Each delivery carries the event name and a delivery id so you can detect repeats.

POST /your-endpoint HTTP/1.1
X-SIMCOAI-Event: workflow.requested
X-SIMCOAI-Delivery-ID: dlv_01HQ...
Content-Type: application/json

{
  "event": "workflow.requested",
  "type": "refund",
  "status": "pending",
  "verified": false,
  "createdAt": "2026-07-31T16:04:11.000Z"
}
Reliability

Retries and idempotency

Deliveries are retried on failure with exponential backoff and jitter, up to 8 attempts by default (configurable per endpoint, capped at 12). The delay roughly doubles each attempt and is capped at one hour, so a delivery can still land up to several hours after the event if your endpoint is down. After the final attempt the delivery is marked failed and is not retried further — check the endpoint's delivery log in the dashboard and use the manual retry action if you missed one.

Respond 2xx quickly

Acknowledge first, process afterwards. Slow endpoints get retried and cause duplicates.

Deduplicate on delivery id

Store X-SIMCOAI-Delivery-ID and ignore any id you have already handled — the same delivery id is reused across retries of the same event.

Use the idempotency key for the underlying record

X-SIMCOAI-Idempotency-Key identifies the record the event is about, not the delivery attempt — use it if you key your own database on the source record rather than the delivery.

Never trust the body alone

Verify the signature before acting on it — see below.

Security

Verifying a delivery is genuinely from SIMCOAI

Every delivery carries an X-SIMCOAI-Signature header in the form t=<timestamp>,v1=<signature>. The signature is an HMAC-SHA256 of the string timestamp + "." + rawBody, keyed with the signing secret shown when you create the endpoint. Recompute it yourself and compare — do not just check the header is present.

const crypto = require("crypto");

function isValidSimcoaiWebhook(rawBody, signatureHeader, secret) {
  const [tPart, vPart] = signatureHeader.split(",");
  const timestamp = tPart.split("=")[1];
  const signature = vPart.split("=")[1];

  // Reject anything older than 5 minutes to block replay of a captured request.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

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

  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}
Careful. Sign against the exact raw request body, before any JSON parsing or re-serialising — most frameworks re-format JSON when you access req.body, which changes the bytes and breaks the comparison. Read the raw body first, verify, then parse.
Endpoints

Managing endpoints

Create, disable and rotate webhook endpoints under Integrations → Webhooks in the dashboard. Disabling an endpoint stops new deliveries immediately but does not cancel ones already queued for retry. Rotating the signing secret takes effect on the next delivery — deliveries already queued were signed with the previous secret, so verify against both secrets for a short window after a rotation if you cannot guarantee the queue is empty.

See also the CRM bridge if you want SIMCOAI to call out to a third-party system directly rather than receiving events yourself, and the API if you would rather poll than receive pushes.

Production

Reliable event processing pattern

Keep the public receiver small and move business processing behind it.

  1. Verify firstCheck the signature against the untouched request bytes before parsing or storing the event.
  2. Persist the envelopeStore the delivery identifier, event type, received time and payload in a durable queue.
  3. Acknowledge quicklyReturn a successful response after durable acceptance; do not wait for downstream business work.
  4. Process idempotentlyUse the delivery identifier and the resource version or timestamp to ignore duplicates and stale arrivals.
  5. Recover visiblyRetry transient work, move exhausted events to a review queue, and alert on queue age rather than raw delivery count.