Skip to content

Webhooks

Webhooks deliver real-time event notifications to your server via HTTP POST. Cortex signs every delivery so you can verify authenticity.

Base path: /api/webhooks

All endpoints require Authorization: Bearer <token>.


Events

EventTriggered when
task.createdA new kanban task is created
task.completedA task reaches done status
task.status_changedA task moves to any new status
agent.spawnedAn agent execution starts
agent.completedAn agent execution finishes successfully
agent.failedAn agent execution ends in error

Payload Verification

Every delivery includes these HTTP headers:

HeaderDescription
X-Cortex-Signaturesha256=<hmac> — HMAC-SHA256 of the raw body using your webhook secret
X-Cortex-EventEvent name (e.g. task.created)
X-Cortex-DeliveryUnique delivery ID
X-Cortex-TimestampUnix timestamp of delivery

Verification example (Node.js):

ts
import crypto from 'crypto';

function verify(secret: string, rawBody: string, signature: string): boolean {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

Replay protection

Always validate X-Cortex-Timestamp and reject deliveries older than 5 minutes to prevent replay attacks.


Register Webhook

POST /api/webhooks/register

Request body:

json
{
  "url": "https://your-server.com/hooks/cortex",
  "events": ["task.created", "task.completed", "agent.failed"],
  "secret": "your-signing-secret"
}
FieldTypeRequiredDescription
urlstringYesHTTPS URL that will receive POST deliveries
eventsstring[]YesOne or more event names to subscribe to
secretstringNoShared secret for HMAC signing (recommended)

Response: 201 Created

json
{
  "success": true,
  "data": {
    "id": "wh_01J...",
    "url": "https://your-server.com/hooks/cortex",
    "events": ["task.created", "task.completed", "agent.failed"],
    "active": true,
    "createdAt": "2026-04-03T12:00:00Z"
  }
}

curl:

bash
curl -X POST "https://api.cortex.acrobi.com/api/webhooks/register" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/hooks/cortex",
    "events": ["task.created", "agent.completed"],
    "secret": "your-signing-secret"
  }'

List Webhooks

GET /api/webhooks

Response:

json
{
  "success": true,
  "data": [
    {
      "id": "wh_01J...",
      "url": "https://your-server.com/hooks/cortex",
      "events": ["task.created", "agent.completed"],
      "active": true,
      "lastDeliveryAt": "2026-04-03T11:58:00Z",
      "createdAt": "2026-04-03T12:00:00Z"
    }
  ]
}

Get Webhook

GET /api/webhooks/:id

Response: Full webhook object (secret is never returned).


Delete Webhook

DELETE /api/webhooks/:id

Response:

json
{ "success": true }

Send Test Payload

Sends a synthetic test delivery to the registered URL. Useful for verifying your server can receive and verify webhooks.

POST /api/webhooks/:id/test

Request body:

json
{
  "event": "task.created"
}

Response: 200 OK

json
{
  "success": true,
  "data": {
    "deliveryId": "dlv_01J...",
    "httpStatus": 200,
    "responseBody": "ok",
    "durationMs": 89
  }
}

curl:

bash
curl -X POST "https://api.cortex.acrobi.com/api/webhooks/wh_01J.../test" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"event": "task.created"}'

Delivery History

GET /api/webhooks/:id/deliveries

Returns recent delivery attempts with status and response.

Query parameters: limit (default 20), offset

Response:

json
{
  "success": true,
  "data": [
    {
      "id": "dlv_01J...",
      "event": "task.completed",
      "httpStatus": 200,
      "durationMs": 112,
      "deliveredAt": "2026-04-03T11:58:00Z",
      "redelivery": false
    },
    {
      "id": "dlv_00J...",
      "event": "agent.failed",
      "httpStatus": 500,
      "durationMs": 3021,
      "deliveredAt": "2026-04-03T11:42:00Z",
      "redelivery": false,
      "error": "Connection refused"
    }
  ],
  "pagination": { "limit": 20, "offset": 0, "total": 48 }
}

Automatic retries

Failed deliveries (non-2xx or timeout) are retried up to 3 times with exponential backoff: 5 min, 30 min, 2 hours.


Example Payload

task.status_changed delivery body:

json
{
  "event": "task.status_changed",
  "deliveryId": "dlv_01J...",
  "timestamp": "2026-04-03T12:01:00Z",
  "data": {
    "task": {
      "id": "tk_01J...",
      "title": "Add rate limiting",
      "previousStatus": "in_progress",
      "status": "qa_review",
      "assignedAgent": "qa-tester",
      "projectId": "proj_01J..."
    }
  }
}

Built by Acrobi