Skip to the page

Webhooks

Event catalog

Every webhook event BlueBot sends, when it fires, and a full example payload for each.

Every event BlueBot sends to a webhook, with a full example of each. Each one is posted as JSON with the same envelope: id (the event, evt_…, also sent as the webhook-id header, the same on every retry), object: "event", type, api_version (the payload version your endpoint is pinned to, 2026-11-13 today), timestamp, and data. Message events carry the whole message as GET /v1/messages/{id} returns it, metadata included, so you can match an event to the request that caused it.

EventWhen it fires
message.queuedA text was accepted and is waiting for the Mac, or a scheduled text became due.
message.sentMessages on the Mac showed the text sent. Also fires for a text you typed by hand on your Mac or iPhone, with source: "mac".
message.deliverediMessage showed the text delivered to the person’s device.
message.readThe person read the text. Only for people who share read receipts.
message.failedMessages couldn’t send the text, or it was an iMessage-only text to somebody not on iMessage.
message.unconfirmedThe Mac took the text and didn’t say whether it went before its 3-minute lease ran out.
message.expiredThe text was still waiting when its expires_at passed, so it will never go.
message.canceledA queued or scheduled text was canceled: by you, because the person is on your stop list, or when its sequence or broadcast stopped.
message.receivedSomebody texted you. Pictures and voice memos are on the message as files.
message.editedA text was edited in Messages, by you or by the other person.
message.unsentA text was unsent in Messages. Its words are gone from BlueBot too.
reaction.addedSomebody added a tapback (love, like, laugh and so on) to a text, or you did from your Mac or iPhone.
reaction.removedA tapback was taken back.
chat.createdThe Mac saw a chat BlueBot didn’t know: a new group, or a first text with somebody.
contact.createdA person was added: by a send to somebody new, a text from somebody new, an import, the API or the dashboard.
contact.stoppedA person went on your stop list. Their queued texts were canceled.
contact.unstoppedA person came off your stop list: they texted START, or you took them off.
sequence.completedA person reached the end of a sequence, or it stopped early because they replied or stopped.
broadcast.completedEvery text in a broadcast has settled: sent, failed, skipped, expired or canceled.
automation.matchedAn incoming text matched a keyword rule that has the “Send a webhook event” action.
device.onlineThe Mac checked in after being offline. Held texts start going.
device.offlineThe Mac hasn’t checked in for 2 minutes. Texts wait with hold.reason: "device_offline".
device.check_failedOne of the Mac’s setup checks turned needs_you, such as Messages signing out or Full Disk Access being turned off.

Subscribe to the events you need when you make the webhook; an endpoint never receives types it didn’t ask for. To check a handler against these payloads without sending a text, use Send a test event in the dashboard, POST /v1/webhooks/{id}/test, or bluebot listen.

Messages

message.queued

A text was accepted and is waiting for the Mac, or a scheduled text became due.

Its hold says why it is waiting, if anything holds it. A queued text can still be canceled.

message.queued
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.queued",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "queued",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": null,
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": null,
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": null
  }
}

message.sent

Messages on the Mac showed the text sent. Also fires for a text you typed by hand on your Mac or iPhone, with source: "mac".

service says whether it went as an iMessage or a regular text. A text sent with a file that couldn’t be attached is sent with failure set.

message.sent
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.sent",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "sent",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": "imessage",
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": "2026-11-13T19:41:02.000Z",
    "sent_at": "2026-11-13T19:41:05.000Z",
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": null
  }
}

message.delivered

iMessage showed the text delivered to the person’s device.

Regular texts (SMS) never report delivery, so a text that went as SMS stays sent.

message.delivered
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.delivered",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "delivered",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": "imessage",
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": "2026-11-13T19:41:02.000Z",
    "sent_at": "2026-11-13T19:41:05.000Z",
    "delivered_at": "2026-11-13T19:41:06.000Z",
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": null
  }
}

message.read

The person read the text. Only for people who share read receipts.

Most people don’t share read receipts, so don’t wait for this event.

message.read
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.read",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "read",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": "imessage",
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": "2026-11-13T19:41:02.000Z",
    "sent_at": "2026-11-13T19:41:05.000Z",
    "delivered_at": "2026-11-13T19:41:06.000Z",
    "read_at": "2026-11-13T19:43:30.000Z",
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": null
  }
}

message.failed

Messages couldn’t send the text, or it was an iMessage-only text to somebody not on iMessage.

failure.reason is a stable code and failure.detail says what the Mac saw.

message.failed
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.failed",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "failed",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "imessage",
    "service": null,
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": {
      "reason": "not_on_imessage",
      "detail": "Messages couldn’t send this as an iMessage."
    },
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": "2026-11-13T19:41:02.000Z",
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": "2026-11-13T19:41:09.000Z",
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": null
  }
}

message.unconfirmed

The Mac took the text and didn’t say whether it went before its 3-minute lease ran out.

It may have gone. Check the conversation, then settle it with POST /v1/messages/{id}/resolve: mark_sent if it went, send_again if not. BlueBot never sends it again on its own.

message.unconfirmed
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.unconfirmed",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "unconfirmed",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": null,
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": "2026-11-13T19:41:02.000Z",
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": "2026-11-13T19:44:02.000Z",
    "expired_at": null,
    "canceled_at": null,
    "received_at": null
  }
}

message.expired

The text was still waiting when its expires_at passed, so it will never go.

Usually the Mac was away or the text sat behind quiet hours or a daily limit for longer than the expiry setting.

message.expired
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.expired",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "expired",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": null,
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": null,
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": "2026-11-14T19:41:00.000Z",
    "canceled_at": null,
    "received_at": null
  }
}

message.canceled

A queued or scheduled text was canceled: by you, because the person is on your stop list, or when its sequence or broadcast stopped.

cancel_reason says which.

message.canceled
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.canceled",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "message",
    "direction": "out",
    "state": "canceled",
    "to": "+15555550123",
    "from": "+15555550100",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Hi Maria, the showing at 412 Oak St is confirmed for 3 PM.",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": null,
    "sms_retry": false,
    "source": "api",
    "source_ref": null,
    "metadata": {
      "crm_id": "48213"
    },
    "hold": null,
    "send_at": null,
    "expires_at": "2026-11-14T19:41:00.000Z",
    "failure": null,
    "cancel_reason": "opted_out",
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:41:00.000Z",
    "queued_at": "2026-11-13T19:41:00.000Z",
    "sending_at": null,
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": "2026-11-13T19:42:00.000Z",
    "received_at": null
  }
}

message.received

Somebody texted you. Pictures and voice memos are on the message as files.

Fires once the Mac has uploaded the message’s files, or after 2 minutes without them (their status is then waiting). Group texts carry chat_id.

message.received
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.received",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_2Bf8QzD4kJmA6nXwEuTr1c",
    "object": "message",
    "direction": "in",
    "state": "received",
    "to": "+15555550100",
    "from": "+15555550123",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Perfect, see you there!",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": "imessage",
    "sms_retry": false,
    "source": "mac",
    "source_ref": null,
    "metadata": {},
    "hold": null,
    "send_at": null,
    "expires_at": null,
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": null,
    "created_at": "2026-11-13T19:44:12.000Z",
    "queued_at": null,
    "sending_at": null,
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": "2026-11-13T19:44:10.000Z"
  }
}

message.edited

A text was edited in Messages, by you or by the other person.

text is the new words and edited_at when. BlueBot can read edits but can’t make them.

message.edited
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.edited",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_2Bf8QzD4kJmA6nXwEuTr1c",
    "object": "message",
    "direction": "in",
    "state": "received",
    "to": "+15555550100",
    "from": "+15555550123",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": "Perfect, see you there at 3!",
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": "imessage",
    "sms_retry": false,
    "source": "mac",
    "source_ref": null,
    "metadata": {},
    "hold": null,
    "send_at": null,
    "expires_at": null,
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": "2026-11-13T19:44:40.000Z",
    "unsent_at": null,
    "created_at": "2026-11-13T19:44:12.000Z",
    "queued_at": null,
    "sending_at": null,
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": "2026-11-13T19:44:10.000Z"
  }
}

message.unsent

A text was unsent in Messages. Its words are gone from BlueBot too.

text is null and unsent_at says when.

message.unsent
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "message.unsent",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "msg_2Bf8QzD4kJmA6nXwEuTr1c",
    "object": "message",
    "direction": "in",
    "state": "received",
    "to": "+15555550100",
    "from": "+15555550123",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "text": null,
    "text_deleted": false,
    "files": [],
    "service_requested": "auto",
    "service": "imessage",
    "sms_retry": false,
    "source": "mac",
    "source_ref": null,
    "metadata": {},
    "hold": null,
    "send_at": null,
    "expires_at": null,
    "failure": null,
    "cancel_reason": null,
    "resolution": null,
    "resolved_at": null,
    "resent_message_id": null,
    "reply_to_id": null,
    "reactions": [],
    "edited_at": null,
    "unsent_at": "2026-11-13T19:45:00.000Z",
    "created_at": "2026-11-13T19:44:12.000Z",
    "queued_at": null,
    "sending_at": null,
    "sent_at": null,
    "delivered_at": null,
    "read_at": null,
    "failed_at": null,
    "unconfirmed_at": null,
    "expired_at": null,
    "canceled_at": null,
    "received_at": "2026-11-13T19:44:10.000Z"
  }
}

Reactions

reaction.added

Somebody added a tapback (love, like, laugh and so on) to a text, or you did from your Mac or iPhone.

direction says whose it was. BlueBot can read tapbacks but can’t send them.

reaction.added
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "reaction.added",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "rxn_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "reaction",
    "kind": "love",
    "emoji": null,
    "from": "+15555550123",
    "direction": "in",
    "added_at": "2026-11-13T19:45:00.000Z",
    "message_id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "removed_at": null
  }
}

reaction.removed

A tapback was taken back.

The reaction has the id reaction.added gave it.

reaction.removed
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "reaction.removed",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "rxn_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "reaction",
    "kind": "love",
    "emoji": null,
    "from": "+15555550123",
    "direction": "in",
    "added_at": "2026-11-13T19:45:00.000Z",
    "message_id": "msg_1Hq2LxW9cVbN3mKpRtYs0a",
    "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
    "chat_id": null,
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "removed_at": "2026-11-13T19:46:00.000Z"
  }
}

Chats

chat.created

The Mac saw a chat BlueBot didn’t know: a new group, or a first text with somebody.

A group chat’s id is what chat_id takes on a send.

chat.created
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "chat.created",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "chat_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "chat",
    "name": "Oak St closing",
    "is_group": true,
    "participants": [
      "+15555550123",
      "+15555550187"
    ],
    "service": "imessage",
    "last_message_at": "2026-11-13T19:41:00.000Z",
    "created_at": "2026-11-13T19:41:00.000Z"
  }
}

Contacts

contact.created

A person was added: by a send to somebody new, a text from somebody new, an import, the API or the dashboard.

created_via says how.

contact.created
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "contact.created",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "contact",
    "handle": "+15555550123",
    "kind": "phone",
    "first_name": "Maria",
    "last_name": "Alvarez",
    "company": null,
    "tags": [
      "buyer"
    ],
    "custom_fields": {},
    "stopped": false,
    "stopped_at": null,
    "stop_source": null,
    "last_service": "imessage",
    "first_message_at": null,
    "last_message_at": null,
    "created_via": "api",
    "created_at": "2026-11-13T19:41:00.000Z"
  }
}

contact.stopped

A person went on your stop list. Their queued texts were canceled.

stop_source: "reply" means they texted a stop word such as STOP. BlueBot won’t text them again until they text START or you take them off the list.

contact.stopped
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "contact.stopped",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "contact",
    "handle": "+15555550123",
    "kind": "phone",
    "first_name": "Maria",
    "last_name": "Alvarez",
    "company": null,
    "tags": [
      "buyer"
    ],
    "custom_fields": {},
    "stopped": true,
    "stopped_at": "2026-11-13T19:50:00.000Z",
    "stop_source": "reply",
    "last_service": "imessage",
    "first_message_at": "2026-11-13T19:41:00.000Z",
    "last_message_at": "2026-11-13T19:41:00.000Z",
    "created_via": "api",
    "created_at": "2026-11-13T19:41:00.000Z"
  }
}

contact.unstopped

A person came off your stop list: they texted START, or you took them off.

Texts to them go again from now on. Texts canceled while they were stopped stay canceled.

contact.unstopped
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "contact.unstopped",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "contact",
    "handle": "+15555550123",
    "kind": "phone",
    "first_name": "Maria",
    "last_name": "Alvarez",
    "company": null,
    "tags": [
      "buyer"
    ],
    "custom_fields": {},
    "stopped": false,
    "stopped_at": null,
    "stop_source": null,
    "last_service": "imessage",
    "first_message_at": "2026-11-13T19:41:00.000Z",
    "last_message_at": "2026-11-13T19:41:00.000Z",
    "created_via": "api",
    "created_at": "2026-11-13T19:41:00.000Z"
  }
}

Automations

sequence.completed

A person reached the end of a sequence, or it stopped early because they replied or stopped.

state and stop_reason say which.

sequence.completed
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "sequence.completed",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "enr_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "enrollment",
    "sequence_id": "seq_1Hq2LxW9cVbN3mKpRtYs0a",
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "handle": "+15555550123",
    "contact": {
      "id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
      "object": "contact",
      "handle": "+15555550123",
      "kind": "phone",
      "first_name": "Maria",
      "last_name": "Alvarez",
      "company": null,
      "tags": [
        "buyer"
      ],
      "custom_fields": {},
      "stopped": false,
      "stopped_at": null,
      "stop_source": null,
      "last_service": "imessage",
      "first_message_at": "2026-11-13T19:41:00.000Z",
      "last_message_at": "2026-11-13T19:41:00.000Z",
      "created_via": "api",
      "created_at": "2026-11-13T19:41:00.000Z"
    },
    "state": "stopped",
    "stop_reason": "replied",
    "completed_at": "2026-11-13T19:41:00.000Z"
  }
}

broadcast.completed

Every text in a broadcast has settled: sent, failed, skipped, expired or canceled.

counts has the totals.

broadcast.completed
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "broadcast.completed",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "bc_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "broadcast",
    "name": "Open house Saturday",
    "state": "completed",
    "recipient_count": 42,
    "counts": {
      "sent": 12,
      "delivered": 27,
      "failed": 1,
      "skipped": 2
    },
    "completed_at": "2026-11-13T19:41:00.000Z"
  }
}

automation.matched

An incoming text matched a keyword rule that has the “Send a webhook event” action.

Fires once per incoming text, for the first rule that matched. message is the text that matched. A stop word never matches a rule, so it never fires for one.

automation.matched
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "automation.matched",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "object": "automation_match",
    "rule_id": "kw_1Hq2LxW9cVbN3mKpRtYs0a",
    "rule_name": "Pricing",
    "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
    "actions": [
      "reply",
      "tag",
      "webhook"
    ],
    "message": {
      "id": "msg_2Bf8QzD4kJmA6nXwEuTr1c",
      "object": "message",
      "direction": "in",
      "state": "received",
      "to": "+15555550100",
      "from": "+15555550123",
      "chat_id": null,
      "contact_id": "ct_1Hq2LxW9cVbN3mKpRtYs0a",
      "conversation_id": "conv_1Hq2LxW9cVbN3mKpRtYs0a",
      "text": "PRICING",
      "text_deleted": false,
      "files": [],
      "service_requested": "auto",
      "service": "imessage",
      "sms_retry": false,
      "source": "mac",
      "source_ref": null,
      "metadata": {},
      "hold": null,
      "send_at": null,
      "expires_at": null,
      "failure": null,
      "cancel_reason": null,
      "resolution": null,
      "resolved_at": null,
      "resent_message_id": null,
      "reply_to_id": null,
      "reactions": [],
      "edited_at": null,
      "unsent_at": null,
      "created_at": "2026-11-13T19:44:12.000Z",
      "queued_at": null,
      "sending_at": null,
      "sent_at": null,
      "delivered_at": null,
      "read_at": null,
      "failed_at": null,
      "unconfirmed_at": null,
      "expired_at": null,
      "canceled_at": null,
      "received_at": "2026-11-13T19:44:10.000Z"
    },
    "matched_at": "2026-11-13T19:41:00.000Z"
  }
}

Your Mac

device.online

The Mac checked in after being offline. Held texts start going.

Also fires the first time a newly connected Mac checks in.

device.online
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "device.online",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "dev_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "device",
    "status": "online",
    "name": "Dana’s MacBook Air",
    "number": "+15555550100",
    "app_version": "1.0.0",
    "macos_version": "15.1",
    "last_seen_at": "2026-11-13T19:41:00.000Z",
    "last_sync_at": "2026-11-13T19:41:00.000Z",
    "offline_since": null,
    "paired_at": "2026-11-01T15:00:00.000Z",
    "checks": {
      "messages": {
        "state": "ok",
        "detail": null
      },
      "full_disk_access": {
        "state": "ok",
        "detail": null
      },
      "forwarding": {
        "state": "ok",
        "detail": null
      },
      "awake": {
        "state": "ok",
        "detail": null
      },
      "filevault": {
        "state": "ok",
        "detail": null
      }
    },
    "checks_ok": true,
    "transcription": false,
    "held_count": 0,
    "queued_count": 0,
    "unconfirmed_count": 0,
    "paused_until": null,
    "today": {
      "sent": 14,
      "new_people": 3,
      "new_people_limit": 50,
      "daily_limit": 1000,
      "resets_at": "2026-11-14T05:00:00.000Z"
    },
    "failed_checks": []
  }
}

device.offline

The Mac hasn’t checked in for 2 minutes. Texts wait with hold.reason: "device_offline".

The owner is emailed once if it stays away 10 minutes.

device.offline
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "device.offline",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "dev_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "device",
    "status": "offline",
    "name": "Dana’s MacBook Air",
    "number": "+15555550100",
    "app_version": "1.0.0",
    "macos_version": "15.1",
    "last_seen_at": "2026-11-13T19:41:00.000Z",
    "last_sync_at": "2026-11-13T19:41:00.000Z",
    "offline_since": "2026-11-13T19:39:00.000Z",
    "paired_at": "2026-11-01T15:00:00.000Z",
    "checks": {
      "messages": {
        "state": "ok",
        "detail": null
      },
      "full_disk_access": {
        "state": "ok",
        "detail": null
      },
      "forwarding": {
        "state": "ok",
        "detail": null
      },
      "awake": {
        "state": "ok",
        "detail": null
      },
      "filevault": {
        "state": "ok",
        "detail": null
      }
    },
    "checks_ok": true,
    "transcription": false,
    "held_count": 2,
    "queued_count": 2,
    "unconfirmed_count": 0,
    "paused_until": null,
    "today": {
      "sent": 14,
      "new_people": 3,
      "new_people_limit": 50,
      "daily_limit": 1000,
      "resets_at": "2026-11-14T05:00:00.000Z"
    },
    "failed_checks": []
  }
}

device.check_failed

One of the Mac’s setup checks turned needs_you, such as Messages signing out or Full Disk Access being turned off.

failed_checks names them and each check’s detail says what the Mac saw.

device.check_failed
{
  "id": "evt_1Hq2LxW9cVbN3mKpRtYs0a",
  "object": "event",
  "type": "device.check_failed",
  "api_version": "2026-11-13",
  "timestamp": "2026-11-13T19:41:00.000Z",
  "data": {
    "id": "dev_1Hq2LxW9cVbN3mKpRtYs0a",
    "object": "device",
    "status": "online",
    "name": "Dana’s MacBook Air",
    "number": "+15555550100",
    "app_version": "1.0.0",
    "macos_version": "15.1",
    "last_seen_at": "2026-11-13T19:41:00.000Z",
    "last_sync_at": "2026-11-13T19:41:00.000Z",
    "offline_since": null,
    "paired_at": "2026-11-01T15:00:00.000Z",
    "checks": {
      "messages": {
        "state": "needs_you",
        "detail": "Messages isn’t signed in to iMessage."
      },
      "full_disk_access": {
        "state": "ok",
        "detail": null
      },
      "forwarding": {
        "state": "ok",
        "detail": null
      },
      "awake": {
        "state": "ok",
        "detail": null
      },
      "filevault": {
        "state": "ok",
        "detail": null
      }
    },
    "checks_ok": false,
    "transcription": false,
    "held_count": 0,
    "queued_count": 0,
    "unconfirmed_count": 0,
    "paused_until": null,
    "today": {
      "sent": 14,
      "new_people": 3,
      "new_people_limit": 50,
      "daily_limit": 1000,
      "resets_at": "2026-11-14T05:00:00.000Z"
    },
    "failed_checks": [
      "messages"
    ]
  }
}