Webhooks
What Are Webhooks?#
Webhooks let Strata push real-time event notifications to your own servers the moment something significant happens — an order is created, a job completes, or an invoice is paid. Instead of polling the API, your endpoint receives an HTTP POST with a signed JSON payload as soon as the event fires.
Available Events#
Subscribe to any combination of the events below. Strata will deliver a payload to your endpoint for each event you have enabled.
| Name | Type | Required | Description |
|---|---|---|---|
order.created | string | No | Fires when a client submits an intake form and Strata creates a new Order record with status pending. |
order.delivered | string | No | Fires when the operator posts a delivery and the Order status advances to delivered. The payload includes the delivery URL. |
order.completed | string | No | Fires when the client confirms acceptance and the Order status advances to completed. Triggers invoice generation if one has not been issued. |
order.cancelled | string | No | Fires when an operator or client cancels an order before delivery. Required before a refund can be processed. |
job.started | string | No | Fires when the agent job associated with an order is dequeued and begins execution. |
job.completed | string | No | Fires when the agent job finishes successfully. The payload includes the job output metadata. |
job.failed | string | No | Fires when the agent job exhausts all retries and enters a failed state. Check the Logs panel for the full error trace. |
invoice.created | string | No | Fires when Strata generates a new Invoice record, either automatically on order completion or manually by the operator. |
invoice.paid | string | No | Fires when the Stripe payment for an invoice is confirmed. The payload includes the Stripe payment intent ID. |
Setting Up a Webhook#
Open the webhook configuration panel
In your Strata dashboard, navigate to Settings > Integrations > Webhooks, then click Add Endpoint to open the new endpoint form.
Paste your endpoint URL
Enter the publicly reachable HTTPS URL where Strata should deliver event payloads. The URL must respond to POST requests and return a 2xx status within 5 seconds.
Select events to subscribe to
Check each event you want to receive. You can subscribe to individual events (e.g. order.created only) or enable all events for full coverage. Changes take effect immediately.
Copy your webhook secret for signature verification
After saving, Strata generates a unique signing secret for this endpoint. Copy it now — it is shown only once. Store it securely in your environment variables and use it to verify the X-Strata-Signature header on every incoming request.
Payload Structure#
Every webhook delivery shares the same envelope: an event name, an ISO 8601 timestamp, and a data object whose shape is specific to the event type. The raw request body is the string Strata signs — preserve it exactly as received before parsing.
{
"event": "order.created",
"timestamp": "2026-01-01T00:00:00Z",
"data": {
"orderId": "ord_xxx",
"serviceId": "svc_xxx",
"status": "pending"
}
}Signature Verification#
Strata signs every delivery by computing HMAC-SHA256 over the raw request body using your endpoint's webhook secret. The result is sent in the X-Strata-Signature header as a hex digest. Verify this on every request before acting on the payload.
1import crypto from 'node:crypto';
2
3/**
4 * Verify a Strata webhook signature.
5 * @param rawBody - The raw, unparsed request body string (do NOT parse JSON first).
6 * @param signature - The value of the X-Strata-Signature request header.
7 * @param secret - Your endpoint's webhook secret from Settings > Integrations > Webhooks.
8 * @returns true if the signature is valid, false otherwise.
9 */
10function verifyWebhookSignature(
11 rawBody: string,
12 signature: string,
13 secret: string,
14): boolean {
15 const expected = crypto
16 .createHmac('sha256', secret)
17 .update(rawBody, 'utf8')
18 .digest('hex');
19
20 // Use timingSafeEqual to prevent timing attacks.
21 const expectedBuf = Buffer.from(expected, 'hex');
22 const receivedBuf = Buffer.from(signature, 'hex');
23
24 if (expectedBuf.length !== receivedBuf.length) return false;
25 return crypto.timingSafeEqual(expectedBuf, receivedBuf);
26}
27
28// ── Express example ──────────────────────────────────────────────────────────
29// Use express.raw() (not express.json()) so rawBody is a Buffer.
30app.post('/webhooks/strata', express.raw({ type: 'application/json' }), (req, res) => {
31 const signature = req.headers['x-strata-signature'] as string;
32 const rawBody = req.body.toString('utf8');
33
34 if (!verifyWebhookSignature(rawBody, signature, process.env.STRATA_WEBHOOK_SECRET!)) {
35 return res.status(401).json({ error: 'Invalid signature' });
36 }
37
38 const event = JSON.parse(rawBody);
39 // Handle event.event ...
40 res.status(200).json({ received: true });
41});Retry Logic#
Strata retries failed deliveries automatically. An attempt is considered failed if your endpoint does not return a 2xx HTTP status within 5 seconds, or if a network error occurs. Retries follow an exponential backoff schedule: first retry after 1 second, second after 5 seconds, third after 25 seconds — three retries in total after the initial attempt. If all attempts fail, the delivery is marked as failed and recorded in the webhook logs. No further retries are made; re-trigger manually from Settings > Integrations > Webhooks > Logs if needed.
Webhook Logs#
Every delivery attempt — success or failure — is recorded in the webhook log. Navigate to Settings > Integrations > Webhooks > Logs to inspect the full request payload, the HTTP response status your endpoint returned, response time, and whether the signature was valid. Use the log to debug integration issues or to manually re-trigger a failed delivery.