Edit and Undo Send are iMessage features: they work on messages that went out over iMessage (
channel: "imessage"), and a message that went out by SMS or RCS gets 422 sms_not_supported. Cancel works on any message that hasn’t gone out yet.
message_id is the id from Send a message. Messages sent from the dashboard can be changed too; find them with List messages.
Messages sent through the API never get a link preview card. A link in a message you send with
POST /v1/messages goes out as part of a single text bubble, so the recipient sees the link as text. iBubbl builds a rich preview card only for a message typed in the dashboard (fetching the page for a card would count as a click on a tracked or one-time link). A dashboard message with a link is two bubbles, the text and the card: Unsend takes back both, and Edit changes only the text before the link.Edit a message
- The answer is
202withedit_status: "pending".bodyalready shows the new text. - A few seconds later the edit reaches the recipient.
message.editedfires withdirection: "outbound",edit_statusbecomesedited, andedit_countgoes up by one. - If it doesn’t land,
message.edit_failedfires,edit_statusbecomesfailed, andbodygoes back to the text the recipient has.
- Up to 5 edits, within 14 minutes 30 seconds of
sent_at. iMessage allows 15 minutes; iBubbl stops 30 seconds early so an edit never arrives too late to apply. Then422 edit_window_expiredor422 edit_limit_reached: send a follow-up message instead. - One at a time. A second edit while one is on its way gets
409 edit_in_flight. Wait formessage.edited, then send the next. - Retries are safe. Sending the text the message already has answers
200and doesn’t use up an edit, so you can retry a request that timed out. - Text only. The text of a message can be edited, including a caption beside files; a message that is only files can’t (
422 not_editable). - Not to blocked or opted-out contacts. An edit reaches them as a change, so a one-to-one conversation with a blocked or opted-out contact is refused (
contact_blocked,contact_opted_out).
Undo Send
- The answer is
202withunsend_status: "pending", andbodyis already"". - A few seconds later the message is gone:
message.unsentfires withdirection: "outbound"andscope: "message", andunsend_statusbecomesunsent. - If it doesn’t land,
message.unsend_failedfires,unsend_statusbecomesfailed, andbodycomes back. Calling Unsend again tries once more, while the 110 seconds last.
- Within 110 seconds of
sent_at. iMessage allows 2 minutes; iBubbl stops 10 seconds early. Then422 unsend_window_expired. - One bubble. A text message, or a single file on its own, is unsent whole. A message with files and text, or several files, gets
422 multi_part: unsending part of a message is available in the dashboard only, for now. A dashboard message with a link preview is unsent text and card together. - Retries are safe. Calling again while it’s pending or done answers
200and changes nothing. - Not during an edit. While an edit of the message is on its way,
409 edit_in_flight. - Opt-outs don’t block it. Undo Send only removes content, so it works for any contact.
Cancel a message before it goes out
A message can wait before it’s sent: for the contact’s sending hours or the line’s hourly limit for new contacts (status: "pending", with a held_reason), or behind a capacity hold (status: "queued"). While it waits, you can stop it.
- The answer is
200withstatus: "cancelled", andmessage.cancelledfires. The contact never sees it. Calling again answers200and fires nothing more. - Once your line has picked the message up to send it, it’s too late:
409 message_dispatching, and it goes out. After it’s sent, use Unsend instead. - A message that already went out, failed or expired gets
422 not_cancellable. - Retrying the original send with the same
idempotency_keyreturns the cancelled message; it doesn’t send it. Use a new key to send it after all.
What the recipient sees
What Edit and Undo Send look like depends on the recipient’s software. Apple describes it in Unsend or edit messages on iPhone.
In a group, only members using iMessage see an edit.
edited and unsent mean iMessage accepted the change, not that the recipient’s device applied it. iBubbl can’t see which software version the recipient runs, so edit_status: "edited", unsend_status: "unsent" and their webhooks look the same whether the bubble changed or the recipient still has the original.Webhooks
A failure carries
failed_reason: expired when your line didn’t confirm the change within 3 minutes (for example, it was offline), or rejected when iMessage refused it (usually because the window had passed on its side).
Where it stands
Retrieve a message and List messages show the current state on every message:
A message’s
status doesn’t change when it’s edited or unsent: it stays sent, delivered or read.
Rate limits
Edit, Unsend and Cancel count toward the conversation-actions budget, with tapbacks, mark read and typing: 300 requests per 60 seconds per account, across all your API keys. Over it, you get429 rate_limited with a Retry-After header. See Rate limits.
Next
- Message lifecycle: every status a message moves through.
- Webhook events: the payloads above, in full.
- Tapbacks, read receipts and typing: the other things a person does in a conversation.

