BluetickedDeveloper docs

Webhooks

6 endpoints, each with examples that open in the console prefilled.

All resourcesGuide: Webhooks
POST/api/v1/webhookswebhooks:writeTry in console

Create webhook subscription

Subscribe an https endpoint to events. The API returns the signing secret only in this answer; an owner can show it again in the dashboard after a password check.

Body parameters
urlrequiredstring
eventsrequiredstring[]
descriptionstring
  • Store the secret: the API returns it only in this answer. An owner or admin can show it again in the dashboard (Developers → Webhooks, Show secret) after confirming it's them.
  • A retry with the same Idempotency-Key returns the same webhook without its secret field: the secret is shown once. If the first response was lost, rotate it, or have an owner show it again in the dashboard.
  • PATCH /api/v1/webhooks/{id} updates url/events/is_active, or pass rotate_secret: true to issue a new signing secret.
  • DELETE /api/v1/webhooks/{id} removes the subscription.
curl -X POST "https://app.blueticked.com/api/v1/webhooks" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: change-me-per-request-0001" \
  -d '{
  "url": "https://api.example.com/blueticked/events",
  "events": [
    "message.delivered",
    "message.failed",
    "message.received"
  ],
  "description": "Production event handler"
}'
Response
{
  "webhook": {
    "description": null,
    "auto_disabled_at": null,
    "auto_disabled_reason": null,
    "created_at": "2026-10-11T08:00:00.000Z",
    "updated_at": "2026-10-11T08:00:00.000Z",
    "id": "9a342329-d651-4da0-a2d6-b24e4d3599b5",
    "url": "https://api.example.com/blueticked/events",
    "events": [
      "message.delivered",
      "message.failed",
      "message.received"
    ],
    "is_active": true,
    "secret": "whsec_..."
  },
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
POST/api/v1/webhooks/{id}/testwebhooks:writeTry in console

Send test webhook

Fire a signed sample event (payload carries test: true) at the subscription.

Body parameters
eventstring
  • Omit event to use the subscription's first subscribed event.
  • For message.* events, pass channel (whatsapp or sms) so the sample reflects the channel you are wiring; it defaults to whatsapp.
  • Pass media: true with event message.received (whatsapp) to receive the media-bearing sample instead: a photo with no caption (body "" with media {type: "image", filename: null}). It exists because this is the one inbound shape you cannot otherwise rehearse over the wire without a real handset; a consumer that treats an empty body as an empty message silently drops real photos.
curl -X POST "https://app.blueticked.com/api/v1/webhooks/{id}/test" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "event": "message.delivered"
}'
Response
{
  "delivery": {
    "id": "702e6079-28a9-48f1-a18a-7ddd140b0b85",
    "event": "message.delivered",
    "created_at": "2026-05-22T10:30:00.000Z"
  },
  "queued": true,
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
POST/api/v1/webhooks/{id}/replay-failedwebhooks:writeTry in console

Replay failed deliveries since a time

After your endpoint was down, queue a fresh attempt for every delivery of this subscription that failed for good since a time.

Body parameters
sincestring
  • since is an ISO 8601 time, at most 7 days ago. Deliveries that failed for good (status=failed) created at or after it are replayed, oldest first.
  • At most 100 replays per call; remaining counts the rest, so call again until it is 0. more: true means more failed deliveries exist than one call reads: move since forward past the last one replayed and call again, since the same since re-reads the same oldest deliveries.
  • A delivery that already has a replay is skipped, so calling again never sends one event twice; so is one whose payload was removed (90-day retention or a contact's erasure). Concurrent bulk replays of this webhook are refused with 409 conflict and Retry-After: 60 while its replay lock is held. Retry after the first finishes; it skips the deliveries already replayed. If the lock service is unavailable, the call answers 503 service_unavailable. Local development without Redis skips the lock and logs a warning.
  • Each replay is sent to the subscription's current URL and signed with its current secret, with replay=true and replay_of=<original delivery id> in the payload.
  • The subscription must exist and be active. Limited to 10 calls an hour per workspace, shared with the dashboard. Send Idempotency-Key so a network retry replays the first answer.
curl -X POST "https://app.blueticked.com/api/v1/webhooks/{id}/replay-failed" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: change-me-per-request-0001" \
  -d '{
  "since": "2026-08-04T08:00:00.000Z"
}'
Response
{
  "replayed": 2,
  "queued": 2,
  "remaining": 0,
  "more": false,
  "skipped": {
    "already_replayed": 1,
    "payload_removed": 0
  },
  "delivery_ids": [
    "d49ba6e2-574d-4a83-addb-be039dc32170",
    "5bbde510-16f6-4485-aa59-b299cab0e909"
  ],
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
GET/api/v1/webhookswebhooks:readTry in console

List webhook subscriptions

List the workspace's webhook subscriptions. Secrets are never returned.

  • The list never carries a signing secret: the API returns it only when the webhook is created. An owner or admin can show it again in the dashboard (Developers → Webhooks, Show secret).
  • available_events lists every event you can subscribe to, the same set the create/update endpoints accept.
curl -X GET "https://app.blueticked.com/api/v1/webhooks" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "data": [
    {
      "description": null,
      "auto_disabled_at": null,
      "auto_disabled_reason": null,
      "created_at": "2026-05-22T10:30:00.000Z",
      "updated_at": "2026-10-11T08:00:00.000Z",
      "id": "9a342329-d651-4da0-a2d6-b24e4d3599b5",
      "url": "https://api.example.com/blueticked/events",
      "events": [
        "message.delivered",
        "message.failed"
      ],
      "is_active": true
    }
  ],
  "available_events": [
    "message.received",
    "message.sent",
    "message.delivered",
    "message.read",
    "message.failed",
    "email.opened",
    "email.clicked",
    "email.bounced",
    "email.complained",
    "contact.created",
    "contact.updated",
    "suppression.created",
    "suppression.removed",
    "suppression.imported",
    "flow.submitted",
    "channel.connected",
    "agent.run.completed",
    "ticket.created",
    "ticket.assigned",
    "ticket.updated",
    "ticket.reopened",
    "ticket.resolved",
    "commerce.order.paid",
    "commerce.order.fulfilled",
    "commerce.order.refunded",
    "commerce.order.abandoned",
    "table_row.created",
    "table_row.status_changed"
  ],
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
PATCH/api/v1/webhooks/{id}webhooks:writeTry in console

Update a webhook subscription

Update a subscription's url, subscribed events, or active flag.

Body parameters
eventsstring[]
is_activeboolean
  • Subscribable events: message.received, message.sent, message.delivered, message.read, message.failed, email.opened, email.clicked, email.bounced, email.complained, contact.created, contact.updated, suppression.created, suppression.removed, suppression.imported, flow.submitted, channel.connected, agent.run.completed, ticket.created, ticket.assigned, ticket.updated, ticket.reopened, ticket.resolved, commerce.order.paid, commerce.order.fulfilled, commerce.order.refunded, commerce.order.abandoned, table_row.created, table_row.status_changed.
  • suppression.created / suppression.removed fire on every do-not-contact change (STOP, unsubscribe, START resubscribe, dashboard or API add/remove) with { identifier, channel, message_type, reason, business_id, contact_id }.
  • suppression.imported fires ONCE per bulk opt-out import as a digest with { channel, message_type, reason, business_id, added, skipped, invalid, note }. Re-pull GET /api/v1/suppression to sync the individual rows.
curl -X PATCH "https://app.blueticked.com/api/v1/webhooks/{id}" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "events": [
    "message.delivered",
    "message.read",
    "message.failed"
  ],
  "is_active": true
}'
Response
{
  "webhook": {
    "description": null,
    "auto_disabled_at": null,
    "auto_disabled_reason": null,
    "created_at": "2026-10-11T08:00:00.000Z",
    "updated_at": "2026-10-11T08:00:00.000Z",
    "id": "9a342329-d651-4da0-a2d6-b24e4d3599b5",
    "url": "https://api.example.com/blueticked/events",
    "events": [
      "message.delivered",
      "message.read",
      "message.failed"
    ],
    "is_active": true
  },
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
PATCH/api/v1/webhooks/{id}webhooks:writeTry in console

Rotate a webhook secret

Issue a new signing secret for a webhook subscription. The new secret is returned once.

Body parameters
rotate_secretboolean
  • Update your destination system with the new secret. For 24 hours deliveries are also signed with the old secret (x-blueticked-signature-previous, and a second v1 in x-blueticked-signature-v2), so verification keeps working while you roll it out; after that only the new secret verifies.
  • Use rotation when a secret is lost, exposed, or an integration owner leaves.
  • Only the current and the previous secret verify: rotating again inside those 24 hours ends the older secret immediately.
curl -X PATCH "https://app.blueticked.com/api/v1/webhooks/{id}" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "rotate_secret": true
}'
Response
{
  "webhook": {
    "description": null,
    "auto_disabled_at": null,
    "auto_disabled_reason": null,
    "created_at": "2026-10-11T08:00:00.000Z",
    "updated_at": "2026-10-11T08:00:00.000Z",
    "id": "9a342329-d651-4da0-a2d6-b24e4d3599b5",
    "url": "https://api.example.com/blueticked/events",
    "events": [
      "message.delivered",
      "message.read",
      "message.failed"
    ],
    "is_active": true,
    "secret": "whsec_..."
  },
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}
DELETE/api/v1/webhooks/{id}webhooks:writeTry in console

Delete a webhook subscription

Remove a webhook subscription. No further deliveries are attempted.

  • Past deliveries remain in the delivery log for audit and replay.
curl -X DELETE "https://app.blueticked.com/api/v1/webhooks/{id}" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY"
Response
{
  "deleted": true,
  "id": "9a342329-d651-4da0-a2d6-b24e4d3599b5",
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}