Skip to main content
Webhooks let Audienceful notify your server when things happen in a workspace. Each webhook endpoint is an HTTPS URL subscribed to one or more events. Deliveries are HMAC-signed and retried with backoff. Managing endpoints requires the webhooks:read scope (to read) and webhooks:write scope (to create, update, or delete).
1

Create an endpoint

Create a webhook endpoint with your HTTPS URL and the events you care about. The response includes the signing secret — this is the only time it’s returned, so store it.
2

Verify the signature

On each incoming request, verify the X-Audienceful-Signature header against the raw request body using your secret. See Verifying signatures for the scheme and code examples.
3

Respond 2xx

Return a 2xx status to acknowledge the delivery. Non-2xx responses are retried.

Available events

Fetch the current event vocabulary from GET /webhook-events. Events are grouped by area: Contacts
EventFires when
person.createdA new contact is added to your workspace.
person.updatedA contact’s details change — email, name, custom fields, subscription status, etc. Automatic engagement counters (open/click counts, last activity) are excluded, so ingestion never spams you.
person.deletedA contact is deleted from your workspace.
person.unsubscribedA contact unsubscribes or is marked unsubscribed (the unsubscribed state goes from unset to set). A single unsubscribe also emits person.updated — subscribe to whichever you want.
Email
EventFires when
bulk_email.sentA bulk email finishes sending. Exactly one summary event per send, with the subject and a summary of the recipients.
Audiences
EventFires when
audience.member_addedA contact enters an audience.
audience.member_removedA contact leaves an audience.
Real-time changes only. Events fire for real-time, per-contact activity — a form signup, an API call, a manual edit, a single delete. High-volume bulk operations are intentionally webhook-silent so a large job can’t emit tens of thousands of deliveries at once:
  • CSV imports and bulk upserts don’t fire person.created, person.updated, or audience.member_*.
  • Mass deletes don’t fire person.deleted.
  • A full-audience resync (e.g. after an import) doesn’t fire audience.member_added / audience.member_removed.
person.updated replaces the former person.changed event, and now fires on any meaningful change to a contact (not just audience-relevant fields). Existing endpoints subscribed to person.changed were migrated automatically.

Payload format

Every delivery is JSON with an event name and a data object:
{
  "event": "person.created",
  "data": { "...": "..." }
}
The shape of data depends on the event.
These three events share the same contact payload. extra_data is keyed by each custom field’s data_name.
{
  "event": "person.updated",
  "data": {
    "email": "[email protected]",
    "created_at": "2026-07-04T12:00:00Z",
    "extra_data": { "plan": "pro" },
    "audiences": ["Newsletter"],
    "tags": ["vip"],
    "double_opt_in": "not_required"
  }
}
The deleted contact is gone, so the payload is a minimal identifier.
{
  "event": "person.deleted",
  "data": {
    "id": "jQKdwqp3YRRtTrwqUJEp7d",
    "email": "[email protected]",
    "workspace_id": "wRk2sPq7Yb1nKq8Zs4pLm"
  }
}
A summary of the completed send. recipients is the recipient count. draft is null for sends with no associated draft (e.g. SMS).
{
  "event": "bulk_email.sent",
  "data": {
    "task_id": "tSk3nKq8Zs4pLm9vRb2xJc",
    "sent_at": "2026-07-04T12:00:00Z",
    "subject": "Our July newsletter",
    "preheader": "What's new this month",
    "recipients": 4820,
    "audiences": ["Newsletter"],
    "excluded_audiences": ["Bounced"],
    "draft": {
      "id": "dRa3ftPq7Yb1nKq8Zs4pLm",
      "title": "July Newsletter",
      "description": "Monthly update"
    }
  }
}
One delivery per contact–audience pair. If a single recompute changes several audiences for a contact, you receive one delivery per audience.
{
  "event": "audience.member_added",
  "data": {
    "person": {
      "id": "jQKdwqp3YRRtTrwqUJEp7d",
      "email": "[email protected]"
    },
    "audience": {
      "id": "aUd3nKq8Zs4pLm9vRb2xJc",
      "name": "Newsletter"
    }
  }
}

Delivery headers

Every delivery carries these headers:
Content-Type: application/json
X-Audienceful-Event: person.created
X-Audienceful-Delivery-Id: wYt3nKq8Zs4pLm9vRb2xJc
X-Audienceful-Signature: t=1751630400,v1=<hex hmac-sha256>
Always verify the signature before trusting a delivery’s contents — see that page for the scheme and code examples in Python, TypeScript, and PHP.

Delivery, retries & auto-disable

  • Deliveries are retried on any non-2xx response or network error, with exponential backoff — roughly 30s, 1m, 2m, 4m, 8m, … (each interval jittered ±15% and capped at 4 hours), up to 8 retries over about 2 hours.
  • Respond 2xx to acknowledge. Respond 410 Gone to permanently unsubscribe — the endpoint is disabled with disabled_reason: "410_gone".
  • After 20 consecutive failed deliveries (each counted only once its retries are exhausted) an endpoint auto-disables with disabled_reason: "too_many_failures". Re-enable it with PATCH { "is_active": true }, which also clears its failure state.
  • You can inspect recent attempts via the delivery log and send a test event with ping. Delivery log rows are retained for 30 days.

Delivery rate limit

Each endpoint is capped at 10 deliveries per second. When a burst of events exceeds that (say, a few hundred contacts edited in quick succession), the excess deliveries are automatically re-queued and delivered a moment later — they are never dropped. Being throttled does not count as a failed attempt, so a busy endpoint can never trip the auto-disable threshold on rate limiting alone. Sustained throughput averages the cap.

Automation “Send Webhook” action

Automations can include a Send Webhook step. When a contact reaches that step, Audienceful POSTs to the configured URL. This is separate from the webhook endpoints described here (it fires from inside an automation, not from an event subscription), but uses the same signing scheme.
{
  "event": "automation.webhook",
  "automation": { "id": "auto_...", "name": "Welcome series" },
  "person": {
    "id": "jQKdwqp3YRRtTrwqUJEp7d",
    "email": "[email protected]",
    "extra_data": { "plan": "pro" }
  },
  "event_properties": { "...": "..." }
}
Any keys configured on the action’s extra payload are merged in at the top level. The request carries the same X-Audienceful-Signature and X-Audienceful-Event (automation.webhook) headers, signed with the action’s own secret (shown in the action config) — verify it the same way. Delivery is fire-and-forget with retries: a slow or failing endpoint never blocks or stalls the contact’s progress through the automation.