Events

Events reference

Every event shares one envelope. Subscribe per endpoint to the types you need; see Webhooks for signatures and retries.

Envelope#

Every event
{
  "id": "evt_2kQ9x…",
  "type": "message.received",
  "apiVersion": "2026-10-01",
  "created": 1790000000,
  "appId": "cmg…",
  "data": {}
}

id is unique per event and stays the same across retries and replays — dedupe on it. created is Unix seconds.

message.received#

A user sent your app a message. A user's first message is also their opt-in (you'll get consent.updated with source user_initiated).

message.received data
{
  "id": "cmg4r7k2d0003ab12cd34ef56",
  "from": "u_4f9XkQ2bT7mN1pR8sV0wYz",
  "type": "text",
  "text": "Where is my order?",
  "media": [],
  "context": {
    "messageId": "cmg4r2x0p0001ab12cd34ef56"
  },
  "timestamp": "2026-10-01T09:31:02.000Z"
}
message.received data fields
FieldTypeNotes
idrequiredstring
fromrequiredstringPer-app user id, e.g. u_4f9XkQ2bT7mN1pR8sV0wYz · pattern ^u_[0-9A-Za-z]{22}$
typerequiredstring
textrequiredstring | null
mediarequiredobject[]
media[].idrequiredstringGET /media/:id
media[].mimeTyperequiredstring | null
media[].fileNamerequiredstring
media[].sizerequiredinteger
contextobjectPresent when the user replied to a message
context.messageIdrequiredstring
timestamprequiredstring (date-time)

message.status#

A message you sent changed state: sent, delivered (reached a device), read, or failed.

message.status data
{
  "id": "cmg4r2x0p0001ab12cd34ef56",
  "appUserId": "u_4f9XkQ2bT7mN1pR8sV0wYz",
  "status": "read",
  "timestamp": "2026-10-01T09:30:41.000Z",
  "clientReference": "order-1042"
}
message.status data fields
FieldTypeNotes
idrequiredstring
appUserIdrequiredstringPer-app user id, e.g. u_4f9XkQ2bT7mN1pR8sV0wYz · pattern ^u_[0-9A-Za-z]{22}$
statusrequired"sent" | "delivered" | "read" | "failed"
timestamprequiredstring (date-time)
clientReferencestring

A user opted in, stopped your messages, or blocked you. On opted_out or blocked, stop messaging them — sends will fail with consent_required. reason account_deleted means the account is gone.

consent.updated data
{
  "appUserId": "u_4f9XkQ2bT7mN1pR8sV0wYz",
  "status": "opted_in",
  "source": "opt_in_link",
  "ref": "store-42"
}
consent.updated data fields
FieldTypeNotes
appUserIdrequiredstringPer-app user id, e.g. u_4f9XkQ2bT7mN1pR8sV0wYz · pattern ^u_[0-9A-Za-z]{22}$
statusrequired"opted_in" | "opted_out" | "blocked"
source"user_initiated" | "profile_allow" | "opt_in_link" | "sandbox_tester"
refstringThe opt-in link ref, for source opt_in_link
reason"account_deleted"

app.status_changed#

Your app moved on the access ladder: approved, suspended, reinstated, or dropped to internal_live when verification is revoked.

app.status_changed data
{
  "status": "internal_live",
  "previousStatus": "sandbox"
}
app.status_changed data fields
FieldTypeNotes
statusrequiredstring
previousStatusrequiredstring
reasonstring

webhook.test#

Sent only by Send test event, to that endpoint. Data: { message, subscriptionId, nonce }.