Skip to content

Webhooks

Get events pushed to your HTTPS endpoint instead of polling. Needs webhooks:manage. Subscribing an endpoint to an event also needs that record's read scope: lead.created needs leads:read, call.completed needs calls:read, booking.created needs bookings:read, outbound_call.completed needs outbound:write, every chat.* event needs chats:read, and chat.lead_captured also needs leads:read.

Each delivery is a POST with a JSON body {"id", "type", "created_at", "data"} and these headers: Vocenya-Event (the event type), Vocenya-Delivery (the event id; use it to ignore duplicates) and Vocenya-Signature: t=<unix time>,v1=<hex>. To verify, compute HMAC-SHA256 of "<t>.<raw body>" with your endpoint's secret, compare it to v1 in constant time, and reject timestamps more than 5 minutes old.

Answer with any 2xx within 10 seconds. Anything else is retried with backoff (1 min, 5 min, 15 min, 1 h, 3 h, 6 h, 12 h) for up to 8 attempts. Payloads carry ids, statuses, times and contact details, never conversation content, except chat.message.created, which carries the message so your system can answer it. HIPAA-mode accounts get ids only. Fetch the full record from the API when you need more.

Events: lead.created, call.completed, booking.created, outbound_call.completed, and for website live chat chat.started, chat.message.created, chat.lead_captured, chat.handoff_requested, chat.handed_off and chat.closed.

Live chat events share a chat object: {"id", "status", "page_url", "handed_off_at", "closed_at", "created_at"}. chat.message.created adds message: {"id", "sender", "role", "author", "body", "via_api", "created_at"}, where sender is visitor, ai, agent, owner or system and role is what the widget shows (visitor, ai, team or system); skip via_api: true, your own replies. chat.lead_captured adds lead (the lead.created fields). chat.handoff_requested adds requested_by (visitor or ai) when a person is asked for; chat.handed_off also fires when your team takes a chat over by replying. chat.closed adds chat.lead_id and chat.message_count. Example chat.message.created:

JSON
{"id": "9f0c...", "type": "chat.message.created", "created_at": "2026-10-02T14:03:30+00:00",
 "data": {"chat": {"id": 205, "status": "ai", "page_url": "https://www.example.com/contact",
   "handed_off_at": null, "closed_at": null, "created_at": "2026-10-02T14:03:11+00:00"},
  "message": {"id": 4410, "sender": "visitor", "role": "visitor", "author": "Visitor",
   "body": "Hi, do you have any openings this week?", "via_api": false,
   "created_at": "2026-10-02T14:03:30+00:00"}}}

The same event for a HIPAA-mode account: {"chat": {"id": 205}, "message": {"id": 4410}}.

List webhook endpoints

GET/webhook-endpoints

Needs the webhooks:manage scope

Returns

Array of WebhookEndpointResource

  • dataarray of objectsRequired

Responses

  • 200Array of WebhookEndpointResource
  • 401The API key is missing, invalid, expired or revoked.
  • 403The key does not have the webhooks:manage scope.
  • 429Too many requests for this key. Wait for the Retry-After seconds.
curl https://vocenya.com/api/public/v1/webhook-endpoints \
  -H "Authorization: Bearer $VOCENYA_API_KEY"
Response 200
{
  "data": [
    {
      "id": 1,
      "livemode": true,
      "url": "https://hooks.example.com/vocenya",
      "description": "string",
      "events": [
        "lead.created"
      ],
      "enabled": true,
      "created_at": "2026-10-02T14:03:11+00:00"
    }
  ]
}

Create a webhook endpoint

POST/webhook-endpoints

Needs the webhooks:manage scope

Add an endpoint. The response includes its signing secret: store it now, it is not shown again.

Request body

  • urlstring (uri)Required

    A public HTTPS URL.

    Up to 2048 characters

  • eventsarray of stringsRequired

    The events to send, at least one. The key needs the read scope of each event's record: lead.created needs leads:read, call.completed needs calls:read, booking.created needs bookings:read, outbound_call.completed needs outbound:write, every chat.* event needs chats:read, and chat.lead_captured also needs leads:read.

    One oflead.createdcall.completedbooking.createdchat.handed_offoutbound_call.completedchat.startedchat.message.createdchat.lead_capturedchat.handoff_requestedchat.closed

    At least 1 items

  • descriptionstring | nullOptional

    Up to 255 characters

Returns

The endpoint and its signing secret.

  • dataobjectRequired
  • secretstringRequired

Responses

  • 201The endpoint and its signing secret.
  • 401The API key is missing, invalid, expired or revoked.
  • 403The key lacks the read scope of a subscribed event, for example leads:read for lead.created (missing_scope).
  • 422Validation failed, the URL is not a public HTTPS address (unsafe_url), or the account already has 10 endpoints (too_many_endpoints).
  • 429Too many requests for this key. Wait for the Retry-After seconds.
curl -X POST https://vocenya.com/api/public/v1/webhook-endpoints \
  -H "Authorization: Bearer $VOCENYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://hooks.example.com/vocenya",
  "events": [
    "lead.created"
  ],
  "description": "Our CRM"
}'
Response 201
{
  "data": {
    "id": 3,
    "url": "https://hooks.example.com/vocenya",
    "description": "Our CRM",
    "events": [
      "lead.created"
    ],
    "enabled": true,
    "created_at": "2026-09-27T15:04:05+00:00"
  },
  "secret": "whsec_4hW0cB1m9GqS7pXvL2eYt8Kz3nRd6FjA5uVo0iQs"
}

Delete a webhook endpoint

DELETE/webhook-endpoints/{webhookEndpoint}

Needs the webhooks:manage scope

Delete an endpoint. Queued deliveries to it are dropped.

Path parameters

  • webhookEndpointintegerRequired

    The endpoint id.

Responses

  • 204Deleted.
  • 401The API key is missing, invalid, expired or revoked.
  • 403The key does not have the webhooks:manage scope.
  • 404No record with that id belongs to your account.
  • 429Too many requests for this key. Wait for the Retry-After seconds.
curl -X DELETE https://vocenya.com/api/public/v1/webhook-endpoints/3 \
  -H "Authorization: Bearer $VOCENYA_API_KEY"

Send a test event

POST/webhook-endpoints/{webhookEndpoint}/test

Needs the webhooks:manage scope

Send a signed webhook.test event to this endpoint, with {"message": "..."} as its data. Pass event to get a sample of a real event instead (for example chat.message.created), with made-up data and "sample": true, cut down to ids for HIPAA-mode accounts like the real thing. It is delivered in the background like any other event, even when the endpoint is paused.

Shell
curl -X POST https://vocenya.com/api/public/v1/webhook-endpoints/3/test \
  -H "Authorization: Bearer $VOCENYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"event": "chat.message.created"}'

Path parameters

  • webhookEndpointintegerRequired

    The endpoint id.

Request body

  • eventstring | nullOptional

    Send a sample of this event (made-up data plus "sample": true) instead of webhook.test.

    One oflead.createdcall.completedbooking.createdchat.handed_offoutbound_call.completedchat.startedchat.message.createdchat.lead_capturedchat.handoff_requestedchat.closed

Returns

The queued delivery.

  • dataobjectRequired

Responses

  • 202The queued delivery.
  • 401The API key is missing, invalid, expired or revoked.
  • 403The key does not have the webhooks:manage scope.
  • 404No record with that id belongs to your account.
  • 422Validation error
  • 429Too many requests for this key. Wait for the Retry-After seconds.
curl -X POST https://vocenya.com/api/public/v1/webhook-endpoints/3/test \
  -H "Authorization: Bearer $VOCENYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "event": "chat.message.created"
}'
Response 202
{
  "data": {
    "id": 1,
    "livemode": true,
    "event_id": "string",
    "event": "lead.created",
    "webhook_endpoint_id": 1,
    "status": "pending",
    "attempts": 1,
    "response_status": 1,
    "last_error": "string",
    "next_attempt_at": "2026-10-02T14:03:11+00:00",
    "delivered_at": "2026-10-02T14:03:11+00:00",
    "created_at": "2026-10-02T14:03:11+00:00"
  }
}