Webhook subscriptions

The same subscriptions the dashboard manages, so a plugin can register its own callback URL at install time and remove it at uninstall. For what we send to that URL, see outgoing webhooks.

Paths are relative to https://api.chatboxai.dev/api, so /v1/messages/template means https://api.chatboxai.dev/api/v1/messages/template. Every request needs an API key, see Authentication.

Scope: webhooks:manage for all of these.

Routes

MethodPathWhat it does
GET/v1/webhooks/eventsThe event catalogue, with a sentence each.
GET/v1/webhooksThis workspace's subscriptions.
GET/v1/webhooks/{id}One subscription.
POST/v1/webhooksCreate. The secret in the response is the only copy.
PATCH/v1/webhooks/{id}Change the URL, the event list, or isActive.
DELETE/v1/webhooks/{id}Remove. Call this on uninstall.
GET/v1/webhooks/{id}/deliveriesWhat we tried to send and what came back.

Create a subscription

POST/v1/webhooks
Scopewebhooks:manage
Request
POST /api/v1/webhooks
Content-Type: application/json

{
  "name": "WooCommerce (shop.example.com)",
  "url": "https://shop.example.com/wp-json/chatbox/v1/webhook",
  "events": ["message.delivered", "message.failed", "message.inbound"]
}
Response
{
  "secret": "whsec_3xK9mPq2LvR7tY4bN8wC1aD6fG0hJ5sZ",
  "webhook": {
    "id": "clx9v2m7q0007",
    "tenantId": "clx1a0b2c0000",
    "name": "WooCommerce (shop.example.com)",
    "url": "https://shop.example.com/wp-json/chatbox/v1/webhook",
    "events": ["message.delivered", "message.failed", "message.inbound"],
    "isActive": true,
    "failureStreak": 0,
    "disabledAt": null,
    "disabledReason": null,
    "lastSuccessAt": null,
    "createdAt": "2026-10-17T10:25:00.000Z",
    "updatedAt": "2026-10-17T10:25:00.000Z"
  }
}

Store the secret immediately

secret is encrypted at rest and we cannot show it again. If you lose it, rotate it from the dashboard. You need it to verify every delivery.

  • An empty or omitted events list means every event type.
  • The URL must be https and must resolve to a public address. A http:// URL, localhost, or a private range is refused.

Update or delete

PATCHDELETE/v1/webhooks/{id}
Scopewebhooks:manage

PATCH changes the URL, the event list, or isActive. A subscription switched off after repeated failures is resumed with { "isActive": true }, which also clears the failure counter. DELETE removes it: call this when your plugin is uninstalled.

List deliveries

GET/v1/webhooks/{id}/deliveries
Scopewebhooks:managePaginated

Every attempt is recorded, with the status code and the error. Check here first when something "isn't firing".

200 OK
{
  "items": [
    {
      "id": "clx9w8n3r0011",
      "eventId": "evt_wamid.HBgMOTE5..._delivered",
      "eventType": "message.delivered",
      "status": "FAILED",
      "attempts": 6,
      "responseCode": 502,
      "error": "The endpoint answered 502",
      "deliveredAt": null,
      "createdAt": "2026-10-17T10:31:00.000Z"
    }
  ],
  "total": 214,
  "page": 1,
  "pageSize": 25
}