Webhooks
Receive signed callback events for execution lifecycle changes and verify HMAC-SHA256 signatures.
When you create an execution with a callback_url, reArray sends signed HTTP POST callbacks as the execution progresses. Use webhooks to update your systems without polling.
Setting up callbacks
Include callback_url when creating an execution:
{
"agent_id": "...",
"task_id": "...",
"callback_url": "https://api.example.com/hooks/rearray"
}
Only https:// (or http://) URLs are accepted. Callbacks are enqueued when execution status changes.
Event types
| Event | When fired |
|---|---|
execution.queued | Execution enters queued status |
execution.started | Execution enters running status |
execution.completed | Execution finishes successfully |
execution.failed | Execution ends with error status |
execution.aborted | Execution ends with aborted or cancelled status |
webhook.test | Test event from the test endpoint or Integrations UI |
Request format
reArray POSTs JSON to your callback_url with these headers:
| Header | Description |
|---|---|
Content-Type | application/json |
X-Webhook-Timestamp | Unix timestamp (seconds) used in signing |
X-Webhook-Signature | HMAC-SHA256 hex digest |
X-Webhook-Event-Id | Unique delivery event ID |
Payload shape
Webhook payloads include the event type and execution context:
{
"event_id": "uuid",
"type": "execution.completed",
"occurred_at": "2026-06-12T10:02:30.000Z",
"request_id": "req_...",
"reference": "ORD-123",
"metadata": { "source": "erp" },
"execution": {
"id": "uuid",
"account_id": "uuid",
"agent_id": "uuid",
"task_id": "uuid",
"task_version_id": "uuid",
"status": "completed",
"result": { "status": "shipped" },
"error_message": null,
"started_at": "2026-06-12T10:00:00Z",
"stopped_at": "2026-06-12T10:02:30Z",
"created_at": "2026-06-12T09:59:55Z",
"updated_at": "2026-06-12T10:02:30Z"
}
}
For webhook.test events, execution is null and the payload includes a message field instead.
Exact fields vary by event type. Failed deliveries include error details in the delivery log.
Signature verification
Verify every webhook before processing. reArray signs the raw JSON body concatenated with the timestamp:
canonical_string = body + timestamp signature = HMAC-SHA256(canonical_string, signing_secret)
The X-Webhook-Signature header contains the hex-encoded digest.
Your workspace administrator provides the webhook signing secret used to verify callbacks from your reArray deployment. Store it alongside your API key in your secrets manager.
Node.js verification example
import { createHmac, timingSafeEqual } from 'crypto';
function verifyWebhook(body, timestamp, signature, secret) {
const canonical = `${body}${timestamp}`;
const expected = createHmac('sha256', secret)
.update(canonical)
.digest('hex');
if (expected.length !== signature.length) return false;
return timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(signature, 'hex'),
);
}
// In your route handler:
const body = await request.text();
const timestamp = request.headers.get('x-webhook-timestamp');
const signature = request.headers.get('x-webhook-signature');
if (!verifyWebhook(body, timestamp, signature, process.env.WEBHOOK_SECRET)) {
return new Response('Invalid signature', { status: 401 });
}
const event = JSON.parse(body);
// Process event...
return new Response('OK', { status: 200 });
Python verification example
import hmac
import hashlib
def verify_webhook(body: str, timestamp: str, signature: str, secret: str) -> bool:
canonical = f"{body}{timestamp}"
expected = hmac.new(
secret.encode(),
canonical.encode(),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)
Respond with 200 OK promptly. reArray retries failed deliveries.
Retries and delivery log
Webhook delivery is durable:
- Failed deliveries (non-2xx, timeout, network error) are retried automatically
- Exhausted retries move to a dead-letter state
- View delivery history in the workspace Integrations page
The delivery log shows event type, target URL, status, response code, and retry count for each attempt.
Testing your handler
API test endpoint
curl -X POST https://your-app.example.com/api/v1/integrations/webhooks/test \
-H "Authorization: Bearer ra_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "callback_url": "https://api.example.com/hooks/rearray" }'
Returns 202 Accepted and enqueues a webhook.test event.
Integrations UI
Use the Test webhook button on the Integrations page to send a signed webhook.test event to a candidate URL before triggering real executions.
Best practices
- Verify signatures on every request β reject unsigned or invalid payloads
- Use
referenceandmetadatafor correlation with your internal systems - Handle duplicate deliveries idempotently (use
X-Webhook-Event-Idorexecution_id+type) - Return
200quickly and process asynchronously if needed - Test with
webhook.testbefore going live