requested
A refund, booking or order query was captured from a call or chat.
Receive SIMCOAI workflow events in your own systems as they happen.
Workflow events fire when customer work changes state.
A refund, booking or order query was captured from a call or chat.
A person approved the request in the dashboard.
A refund was marked as completed.
A booking was confirmed.
The request was cancelled.
An order query changed state.
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"
}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.
Acknowledge first, process afterwards. Slow endpoints get retried and cause duplicates.
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.
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.
Verify the signature before acting on it — see below.
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));
}req.body, which changes the bytes and breaks the comparison. Read the raw body first, verify, then parse.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.
Keep the public receiver small and move business processing behind it.