Skip to content
Inkbox

Inkbox

DocsPricingBlogContact
GuidesAPI ReferenceChangelog

Ctrl K

GuidesAPI ReferenceChangelog

Jump to

Webhook Subscriptions

A webhook subscription names one owner — a mailbox, a phone number, or an agent identity — one HTTPS destination URL, and a non-empty list of event types from the webhook catalog. When a matching event fires, Inkbox POSTs the payload to the subscription's URL.

Mail and text subscriptions are owned by the mailbox or phone number. iMessage and call-lifecycle subscriptions are owned by the agent identity, because that traffic can ride shared lines rather than a number you own — see iMessage webhooks and Phone webhooks.

You can attach up to 20 active subscriptions per owner (mailbox, phone number, or agent identity). Each URL receives its own POST per event, independently — one slow receiver doesn't block delivery to the others. A 21st POST /webhooks/subscriptions on the same owner returns 409; delete an existing subscription first.

phone.incoming_call is not subscribable. That event is a synchronous control-plane callback — the response body decides whether Inkbox answers the call — so it can't fan out. Configure it via the incoming_call_webhook_url field on the phone number resource instead.

Auth

CallerVisibility
Admin-scoped API keyEvery subscription in the organization.
Human session via the Inkbox ConsoleEvery subscription in the organization.
Claimed agent-scoped API keyOnly subscriptions whose owning mailbox or phone number belongs to that agent's identity, or whose owner is the identity itself.

Unclaimed agent-scoped API keys are rejected.


Create subscription POST

POST /webhooks/subscriptions

Create a new subscription on a mailbox, a phone number, or an agent identity.

Request body

FieldTypeRequiredDescription
mailbox_idUUIDConditionallyOwning mailbox. Exactly one of mailbox_id / phone_number_id / agent_identity_id must be set.
phone_number_idUUIDConditionallyOwning phone number. Exactly one of the three owner fields must be set.
agent_identity_idUUIDConditionallyOwning agent identity, for iMessage and call-lifecycle subscriptions. Exactly one of the three owner fields must be set.
urlstringYesHTTPS destination for delivered events.
event_typesarray of stringsYesNon-empty, distinct list of event types. Every entry must belong to one channel valid for the owner (mailbox_idmessage.*; phone_number_idtext.*; agent_identity_idimessage.* or call.ended). Channels never mix on one row — call.ended cannot share a subscription with imessage.* events.
context_configobject | nullNoOpt this subscription into per-class conversation context delivered inside received-event payloads. Omit or null for none.

Request example

JSONJSON

Create subscription response

A successful create returns 201 with the created subscription: the shared Subscription object plus a one-time signing_key field that no other endpoint returns.

JSONJSON
FieldTypeDescription
signing_keystring | nullThe owning identity's webhook signing secret, returned once — only on the first subscription you create for an identity that had no key yet. null (or omitted) on every other create. Store it now; it cannot be retrieved again. See Signing keys.

Signing keys are per owning identity, so the secret returned here belongs to this subscription's owning identity (owner_identity_id) and verifies every webhook for that identity. All other fields are the shared Subscription object.

Validation errors

StatusReason
422Body did not specify exactly one of mailbox_id / phone_number_id / agent_identity_id.
422event_types was empty or contained duplicates.
422An event type doesn't belong to a channel valid for the owner (e.g. text.received on a mailbox_id, or imessage.received on a phone_number_id).
422event_types mixed channels — e.g. call.ended together with imessage.* on one identity-owned row. Create one subscription per channel.
422phone.incoming_call was included — managed via the phone-number resource instead.
422context_config was malformed: an unknown class key, an unknown mode, count outside 1–50, hours outside 1–168, or an unexpected field (the object is validated strictly).
403The owner belongs to a different organization than the caller.
404The owner is not visible to the caller (does not exist, or hidden by access scope).
409An active subscription with the same (owner, url) pair already exists.

Code examples


List subscriptions GET

GET /webhooks/subscriptions

List active subscriptions visible to the caller, newest first. Returns an object with a subscriptions array — not a bare array.

Query parameters

ParameterTypeDescription
mailbox_idUUIDFilter by owning mailbox. The three owner filters are mutually exclusive.
phone_number_idUUIDFilter by owning phone number. The three owner filters are mutually exclusive.
agent_identity_idUUIDFilter by owning agent identity. The three owner filters are mutually exclusive.
urlstringFilter by exact destination URL.
event_typestringFilter by event type. phone.incoming_call is rejected — that event isn't stored as a subscription.

Filters AND-combine. Foreign-organization rows are filtered out, so they never appear in results.

Response (200)

JSONJSON

Error responses

StatusReason
422More than one owner filter supplied.
422event_type=phone.incoming_call.

Code examples


Get subscription GET

GET /webhooks/subscriptions/{sub_id}

Path parameters

ParameterTypeDescription
sub_idUUIDUnique subscription identifier.

Response (200)

Returns the subscription object. See Subscription object.

Error responses

StatusReason
404Subscription does not exist or is not visible to the caller. Foreign-organization subscriptions return 404.

Code examples


Update subscription PATCH

PATCH /webhooks/subscriptions/{sub_id}

Update a subscription's destination URL and/or event list in place. The owner FKs are immutable — to move a subscription to a different mailbox, phone number, or agent identity, delete it and create a new one.

Path parameters

ParameterTypeDescription
sub_idUUIDUnique subscription identifier.

Request body

FieldTypeRequiredDescription
urlstringNoNew HTTPS destination. Omit to leave unchanged.
event_typesarray of stringsNoNew non-empty, distinct list of event types. Same channel-coherence rules as create. Omit to leave unchanged.
context_configobject | nullNoTri-state: send an object to replace the stored conversation-context config, null to clear it, or omit the field to leave it unchanged.

Supplying any subset of these is fine. Supplying none no-ops.

Request example

JSONJSON

Response (200)

Returns the updated subscription object. See Subscription object.

Validation errors

StatusReason
422event_types was empty or contained duplicates.
422An event type doesn't belong to the owner's channel.
422phone.incoming_call was included.
404Subscription does not exist or is not visible to the caller.
409The new (owner, url) collides with another active subscription.

Code examples


Delete subscription DELETE

DELETE /webhooks/subscriptions/{sub_id}

Remove a subscription. Inkbox stops delivering events to the URL immediately. Subsequent reads on the same sub_id return 404.

Path parameters

ParameterTypeDescription
sub_idUUIDUnique subscription identifier.

Response (204)

No body.

Error responses

StatusReason
404Subscription does not exist or is not visible to the caller.

Code examples


Subscription object

FieldTypeDescription
idUUIDUnique subscription identifier.
organization_idstringOwning organization (e.g. "org_2abc123def456"). Server-derived from the owner — never read from the request body.
mailbox_idUUID | nullOwning mailbox. Populated when this is a mail subscription; null otherwise.
phone_number_idUUID | nullOwning phone number. Populated when this is a text subscription; null otherwise.
agent_identity_idUUID | nullOwning agent identity. Populated when this is an iMessage or call-lifecycle subscription; null otherwise.
owner_identity_idstring | nullThe agent identity that owns this subscription, resolved from whichever owner is set (mailbox and phone-number subscriptions report their identity; identity-owned subscriptions report themselves). Normally resolved to the owning identity, but can be null for unresolved or legacy rows. When present, it's the stable way to see which identity a subscription belongs to — and thus which signing key verifies it.
urlstringHTTPS destination for delivered events.
event_typesarray of stringsEvent types this subscription delivers. Every value belongs to the owner's channel.
context_configobject | nullPer-class conversation-context configuration, echoing what you set, or null when the subscription requests no context.
statusstringAlways "active" on returned rows. Deleted rows are not returned by any endpoint.
created_atstringISO 8601 timestamp the subscription was created.
updated_atstringISO 8601 timestamp the subscription was last updated.

Event types

event_types is a non-empty list drawn from the same catalog the webhook payload pages document:

ChannelAllowed values
Mail (mailbox_id owner)message.received, message.sent, message.forwarded, message.delivered, message.bounced, message.failed
Phone text (phone_number_id owner)text.received, text.sent, text.delivered, text.delivery_failed, text.delivery_unconfirmed
iMessage (agent_identity_id owner)imessage.received, imessage.reaction_received, imessage.sent, imessage.delivered, imessage.delivery_failed
Call lifecycle (agent_identity_id owner)call.ended

An agent identity can own subscriptions on either identity channel, but a single subscription carries one channel — call.ended and imessage.* never share a row.

phone.incoming_call is not in this list. It is managed via incoming_call_webhook_url on the phone number resource.

Conversation context (context_config)

Set context_config to opt a subscription into conversation context. On received events — message.received, text.received, and imessage.received — the delivered payload then carries a data.context object with recent history, so your handler can act with context without a follow-up API call. Delivery-status events never carry context.

context_config holds up to three independent class keys:

ClassWhat it includes
emailRecent emails: the triggering thread on mail events, or mail exchanged with the matched contact on text/call events.
textsRecent SMS and iMessage, merged into one chronological list.
callsRecent calls, each with its transcript.

Omit a class to leave it unconfigured. Each configured class picks one of two modes:

ModeFieldMeaning
countcount (1–50)The last N items of that class.
windowhours (1–168)Everything from the last H hours, capped at the 50 newest items.

The object is validated strictly: an unknown class key, an unknown mode, a count/hours out of range, or any unexpected field returns 422. An all-empty object is stored as no context (null).

JSONJSON

On update, context_config is tri-state: an object replaces the stored config, null clears it, and omitting the field leaves it unchanged.

The delivered data.context block — its scopes, per-class items, transcript abridgment, skip reasons, and the 256 KB size cap — is documented alongside the payloads on the Mail, Phone, and iMessage webhook pages.

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Inkbox

Copyright © 2026 Inkbox

This site is protected by reCAPTCHA.

Google Privacy Policy and Terms of Service apply.

Website

Y CombinatorBacked by Y Combinator
Webhook Subscriptions