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

EventWhen fired
execution.queuedExecution enters queued status
execution.startedExecution enters running status
execution.completedExecution finishes successfully
execution.failedExecution ends with error status
execution.abortedExecution ends with aborted or cancelled status
webhook.testTest event from the test endpoint or Integrations UI

Request format

reArray POSTs JSON to your callback_url with these headers:

HeaderDescription
Content-Typeapplication/json
X-Webhook-TimestampUnix timestamp (seconds) used in signing
X-Webhook-SignatureHMAC-SHA256 hex digest
X-Webhook-Event-IdUnique 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 reference and metadata for correlation with your internal systems
  • Handle duplicate deliveries idempotently (use X-Webhook-Event-Id or execution_id + type)
  • Return 200 quickly and process asynchronously if needed
  • Test with webhook.test before going live