iMessage
An iMessage here is one sent from your iMessage line, in the same conversations as your regular texts. You need an iMessage line on your account. Test keys (rsms_test_) can make every GET call here. Every call that sends or changes something is refused with 403.
#Send an iMessage
Sends one iMessage in a conversation. Each message you send or get back on your iMessage line is billed per segment at your iMessage price, counted as a regular text would be (pricing).
Parameters
conversation_idinteger- The conversation to reply in. Send this or
to. Get it from List conversations or Find a contact’s conversation. tostring- A phone number in E.164, like
+15551234567. Use it instead ofconversation_idto text someone with no conversation yet, like a new booking: Ready starts the conversation, and the contact, if there isn’t one. messagestringRequired- Up to 5000 characters.
from_linestring- One of your iMessage lines, in E.164. Leave it out and Ready picks the line for this conversation.
Idempotency-Keystring, headerRecommended- Unique per send; reuse only to retry (Idempotency).
Returns
data.message_idinteger- The message you sent. This is Ready’s own number for it. Delivery webhooks and
GET /v1/messagesidentify an iMessage by the carrier’s string id, so don’t match this value against them. data.channelstring- Always
imessage.
If it sent but Ready couldn’t save it, you get 200 with "recorded": false and "code": "imessage_sent_not_recorded". Don’t send it again.
Fall back to a text. When a refusal carries "fallback": "sms", nothing was sent and the same message can go out as a regular text with Send a message. That happens when the contact isn’t on iMessage, iMessage isn’t on for your account, or the send failed before it left. A regular text also works when the line is being retired, iMessage is paused for the account, or the line hit its new-contact limit.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | empty_message | The message is blank. |
| 400 | missing_recipient | Neither conversation_id nor to was sent. |
| 400 | invalid_phone | to isn’t a valid phone number. |
| 400 | line_not_found | from_line isn’t one of your iMessage lines. Nothing was sent. |
| 402 | insufficient_balance | Your balance can’t cover the text. Nothing sent, not charged. Top up in Billing, or turn on Auto top-up (Billing and pricing). |
| 403 | imessage_not_enabled | iMessage isn’t on for your account. Nothing was sent. Buy an iMessage line to turn it on; it is billed monthly at your line price. |
| 403 | account_suspended | Sending is paused on your account. |
| 403 | global_blocklist | This contact can’t be messaged. |
| 404 | conversation_not_found | No such conversation on your account. |
| 409 | opted_out | The contact opted out. Nothing was sent. |
| 409 | imessage_awaiting_reply | They haven’t replied to your last 2 iMessages. Nothing was sent, and there is no text fallback. Wait for a reply. |
| 409 | imessage_attachment_before_reply | Photos and voice notes can go only after they’ve replied. Send a text first. |
| 409 | imessage_line_draining | This iMessage line is being retired and can’t start new conversations. |
| 422 | not_on_imessage | The contact isn’t on iMessage. |
| 429 | imessage_new_contact_limit | Your iMessage lines reached their limit of new people for now, so nothing was sent. People you already talk to still get iMessage. Send it as a text, try again later, or add another iMessage line at your monthly line price to reach 50 more new people a day. Add lines automatically does it for you. |
| 429 | rate_limited | Too many sends in a short time. Wait and try again. |
| 502 | imessage_outcome_unknown | We couldn’t confirm it went out. Check the conversation before you send again. |
| 502 | imessage_send_failed | It didn’t send. Safe to try again. |
| 503 | imessage_line_unpaid | iMessage is paused on our side; it isn’t about your bill. Nothing was sent and our team has been told. When the response has fallback: "sms", send it as a regular text with Send a message. |
#Voice messages
Send a voice note from your iMessage line, and list the ones you sent and got back. First upload the audio with POST /v1/media (a multipart form with the file in file, an m4a or a wav). The upload takes files up to 20 MB, but a voice note can be at most 6 MB: a bigger one is refused when you send it. It answers with a url. Then send that url as media_url here. A voice note is billed like an iMessage, at your iMessage price.
Parameters
tostring- A phone number in E.164. Send this or
conversation_id. conversation_idinteger- The conversation to send it in.
media_urlstringRequired- The
urlfromPOST /v1/media. It has to be an audio file. A voice note carries no text. from_linestring- One of your iMessage lines, in E.164. Leave it out and Ready picks the line.
Idempotency-Keystring, headerRecommended- Unique per send; reuse only to retry.
Returns
The same answer and errors as Send an iMessage, plus 400 not_audio when media_url isn’t an audio file you uploaded, and 400 imessage_media_too_large when the file is over 6 MB. Nothing was sent in either case.
List voice messages
GET /v1/voice-messages lists the voice notes you sent and got back, newest first. Voice notes you sent before mid-November 2026 aren’t in it. It takes the same filters and paging as List messages (direction, to, from, limit, before_id), and each row’s media_url plays the audio. To hear about a new one as it comes in, subscribe your webhook to voice_message_received.
#React to a message
Puts a tapback (heart, thumbs up and the rest) on a message the contact sent you. Free.
Parameters
message_idintegerRequired- A message the contact sent you.
reactionstringRequired- One of
love,like,dislike,laugh,emphasizeorquestion. Putremove_in front to take one back, likeremove_love.
Sending the same reaction twice is safe. A reaction isn’t a message, so it doesn’t show up as one in the conversation.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_field | That isn’t one of the six reactions (in error_code). |
| 400 | imessage_tapback_not_theirs | You can only react to a message the contact sent you. |
| 400 | imessage_tapback_not_imessage | That message wasn’t an iMessage. |
| 404 | message_not_found | No such message on your account. |
| 404 | imessage_tapback_target_gone | iMessage can’t find that message any more. |
| 409 | opted_out | The contact opted out. |
| 502 | imessage_tapback_failed | It didn’t go through. Safe to try again. |
#Show typing dots
Shows or hides the typing dots on the contact’s phone. Free.
Parameters
conversation_idintegerRequired- The conversation to show it in.
statestringRequiredstartto show the dots,stopto hide them.
Nothing is saved. Send stop if you start the dots and then don’t reply.
Errors
| HTTP | Code | When |
|---|---|---|
| 404 | conversation_not_found | No such conversation on your account. |
| 409 | opted_out | The contact opted out. |
| 429 | imessage_typing_throttled | You started the dots in this conversation a moment ago. Wait a few seconds. |
| 429 | rate_limited | More than 300 typing updates in a minute. |
| 502 | imessage_typing_failed | It didn’t go through. Safe to try again. |
#Start a group
Creates a real iMessage group from your iMessage line and sends its first message. Everyone in it sees each other and every reply, and all the replies come back into one group thread in Ready. Each message you send into a group is billed once, per segment, at your iMessage price, not once per member, and each reply is billed the same way. For a green group text from a regular number, use group: true on Send to many.
Parameters
phonesstring[]Required- 2 to 31 phone numbers, E.164 recommended, each on iMessage. Everyone is checked before anything sends: if one member opted out, is blocked or isn’t on iMessage, the whole send is refused and the error names them.
messagestringRequired- The first message, up to 4000 characters.
namestring- A group name, up to 60 characters.
Idempotency-Keystring, headerRecommended- Unique per send; reuse only to retry (Idempotency).
Returns
data.group_idinteger- Use it to send into the group and read its messages.
data.message_idinteger- The first message.
Now and then iMessage sends the first message but doesn’t confirm the group yet. You get 200 with "recorded": false, "code": "imessage_group_unconfirmed" and no group_id. The message went out: don’t send it again. The group shows up in List groups once someone replies.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_field | phones has fewer than 2 entries. |
| 400 | imessage_group_too_small | Fewer than 2 people are left once repeated or invalid numbers are taken out. |
| 400 | imessage_group_too_big | More than 31 people. |
| 400 | empty_message | The message is blank. |
| 402 | insufficient_balance | Your balance can’t cover the text. Nothing sent, not charged. Top up in Billing, or turn on Auto top-up (Billing and pricing). |
| 403 | imessage_group_no_line | There’s no iMessage line on your account. |
| 403 | imessage_not_enabled | iMessage isn’t on for your account. Nothing was sent. Buy an iMessage line to turn it on; it is billed monthly at your line price. |
| 403 | account_suspended | Sending is paused on your account. |
| 403 | global_blocklist | A member can’t be messaged. Take them out of the group. |
| 409 | opted_out | A member opted out. Nothing was sent. |
| 422 | not_on_imessage | A member isn’t on iMessage. Take them out, or send it as a group text. |
| 429 | rate_limited | Too many sends in a short time. Wait and try again. |
| 502 | imessage_outcome_unknown | We couldn’t confirm it went out. Check the group before you send again. |
| 502 | imessage_send_failed | It didn’t send. Safe to try again. |
#Send a message to a group
Sends one message into a group you started or were added to. It’s billed once, per segment, at your iMessage price, not once per member.
Parameters
idinteger, pathRequired- The
group_id. messagestringRequired- Up to 4000 characters.
Idempotency-Keystring, headerRecommended- Unique per send; reuse only to retry (Idempotency).
If it sent but Ready couldn’t save it, you get 200 with "recorded": false and "code": "imessage_sent_not_recorded". Don’t send it again.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | empty_message | The message is blank. |
| 402 | insufficient_balance | Your balance can’t cover the text. Nothing sent, not charged. Top up in Billing, or turn on Auto top-up (Billing and pricing). |
| 403 | imessage_not_enabled | iMessage isn’t on for your account. Nothing was sent. Buy an iMessage line to turn it on; it is billed monthly at your line price. |
| 403 | account_suspended | Sending is paused on your account. |
| 403 | global_blocklist | A member can’t be messaged. Take them out of the group. |
| 404 | imessage_group_unknown | No such group, or your iMessage line left it. |
| 409 | opted_out | A member opted out. Nothing was sent. |
| 429 | rate_limited | Too many sends in a short time. Wait and try again. |
| 502 | imessage_outcome_unknown | We couldn’t confirm it went out. Check the group before you send again. |
| 502 | imessage_send_failed | It didn’t send. Safe to try again. |
#List groups
Your groups, newest activity first, with their members. Returns a list of groups in data.
Returns
data[].idinteger- The
group_id. data[].namestring- The group name.
data[].last_message_atISO 8601 string- When the newest message was sent or received.
data[].last_message_previewstring- A preview of the newest message.
data[].unread_countinteger- Unread messages. Reading the group marks it read.
data[].created_atISO 8601 string- When the group was started.
data[].members[]object[]- The members, each with
contact_id,phone,first_nameandlast_name.
#List messages in a group
The latest 200 messages in a group, oldest first. Reading a group marks it read. Returns a list of messages in data.
Parameters
idinteger, pathRequired- The
group_id.
Returns
data[].idinteger- The message id.
data[].directionenuminboundoroutbound.data[].bodystring- The message text.
data[].statusstring- The message status, such as
sent. data[].created_atISO 8601 string- When it was created.
data[].sent_atISO 8601 string- When it was sent.
data[].media_urlstring- The attachment’s URL.
data[].contact_idinteger- On a reply: the member who wrote it.
data[].first_namestring- On a reply: the member’s first name.
data[].last_namestring- On a reply: the member’s last name.
data[].sender_phoneE.164 string- On a reply: the member’s phone.
Errors
| HTTP | Code | When |
|---|---|---|
| 400 | invalid_field | The id isn’t a number (in error_code). |
| 404 | no code | No such group on your account. |
See also: the guide to doing this in the app.