How to Send iMessage from an API (Without Jailbreaking)
April 15, 2026 · Noa
How to Send iMessage from an API (Without Jailbreaking)
Apple does not publish a public iMessage API. There is no endpoint, no SDK, no developer program for it. But you can still send iMessages programmatically — through real Apple hardware, with no jailbreak, no simulator, and no grey-market exploit.
senderZ makes this work by routing messages through a proprietary iMessage bridge running on dedicated Apple hardware. Your application calls the senderZ REST API. senderZ handles the queue, compliance checks, phone selection, and delivery. The dedicated device sends a real iMessage through Apple’s servers, indistinguishable from a message typed by hand.
This guide covers exactly how the routing works, how to send your first iMessage from code, how auto-routing handles non-iMessage recipients, how to detect iMessage capability before sending, and what happens when delivery fails.
How senderZ Routes iMessage
The infrastructure has three layers: your application, senderZ’s cloud workers, and senderZ’s dedicated Apple hardware.
Here is what happens when you call the API:
- Your app sends a POST request to
https://api.senderz.com/v1/messageswith the recipient’s phone number, a message body, andchannel: "auto". - The API worker (running on Cloudflare Workers at the edge) validates your API key, creates a message record in the database, and places the message into a Cloudflare Queue.
- The router worker picks up the message from the queue. Before doing anything else, it runs compliance checks: is this number opted out? Is it within quiet hours? Has the phone hit its daily new-contact limit for warming purposes?
- Phone selection happens next. If you have a dedicated phone number on a Growth or Scale plan, the router uses that phone. On pooled plans, it selects the phone with the lowest message count for the day across the pool, balancing load automatically.
- The router calls senderZ’s iMessage engine over a secure tunnel. The engine communicates with the dedicated Apple device and instructs it to send the iMessage.
- The device sends the message through Apple’s iMessage servers. From Apple’s perspective, this is a normal iMessage from a normal device. There is no protocol manipulation.
- Delivery confirmation flows back through the iMessage engine to the router worker. senderZ updates the message status in the database and fires a webhook to your application with the delivery result.
The entire flow from API call to message delivered typically takes 1-2 seconds. Your app gets an immediate response (under 100ms) with a message_id for tracking, and the actual delivery happens asynchronously.
You never need to manage any hardware or configure anything on the device side. senderZ handles all of that. For more on the architecture, see the quickstart documentation.
Send Your First iMessage
Using curl
curl -X POST https://api.senderz.com/v1/messages \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+15551234567",
"channel": "auto",
"body": "Your order has shipped and will arrive tomorrow."
}'
Using TypeScript
const response = await fetch("https://api.senderz.com/v1/messages", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
to: "+15551234567",
channel: "auto",
body: "Your order has shipped and will arrive tomorrow.",
}),
})
const result = await response.json()
console.log(result)
The Response
Both examples return the same JSON shape:
{
"data": {
"message_id": "msg_01HQ3K5V7XJNM2PRWT9F8YDCA6",
"status": "queued",
"channel": "auto",
"to": "+15551234567",
"created_at": "2026-04-15T14:30:00.000Z"
}
}
The status field starts as "queued". It moves to "sent" when the device dispatches the message, then to "delivered" when Apple confirms delivery. If the recipient has read receipts enabled, you will also see "read".
To check the current status of any message, call GET /v1/messages/{message_id}. For real-time updates, register a webhook and senderZ will POST status changes to your endpoint as they happen.
You can find complete API reference and examples in Python, PHP, Ruby, and Go at the send message documentation.
Auto-Routing: iMessage, RCS, and SMS
The channel field controls how senderZ delivers your message. Setting it to "auto" enables the full fallback chain:
- iMessage — tried first. If the recipient’s phone number is registered with Apple’s iMessage servers, the message goes as iMessage. Delivery takes about 1 second, and you get delivery receipts.
- RCS — if iMessage is not available and the recipient supports RCS (Rich Communication Services), senderZ routes through RCS. This gives you read receipts and richer formatting on Android devices.
- SMS — the final fallback. If neither iMessage nor RCS is available, the message goes as a standard SMS through the device’s cellular connection.
You can also force a specific channel:
// Force iMessage only — returns an error if recipient doesn't have iMessage
{ channel: "imessage" }
// Force SMS — bypasses iMessage and RCS detection
{ channel: "sms" }
// Let senderZ pick the best channel (recommended)
{ channel: "auto" }
When using "auto", the webhook delivery notification tells you exactly which channel was used:
{
"event": "message.delivered",
"data": {
"message_id": "msg_01HQ3K5V7XJNM2PRWT9F8YDCA6",
"channel_used": "imessage",
"delivered_at": "2026-04-15T14:30:01.200Z"
}
}
This matters for analytics. You can track what percentage of your audience receives iMessage versus SMS and adjust your messaging strategy accordingly. iMessage messages have significantly higher engagement: blue bubbles create trust, delivery is near-instant, and there are no carrier filtering issues that sometimes eat SMS messages.
For most applications, "auto" is the right choice. You get the best possible delivery experience for each recipient without writing any detection logic yourself. See our pricing page for plan details.
iMessage Capability Detection
Sometimes you want to know whether a number supports iMessage before sending — for example, to show users a “Sending via iMessage” or “Sending via SMS” indicator in your UI, or to segment contacts by channel for different campaign strategies.
The capability detection endpoint checks whether a phone number is registered with Apple’s iMessage service:
curl https://api.senderz.com/v1/capabilities/+15551234567 \
-H "Authorization: Bearer YOUR_API_KEY"
Response:
{
"data": {
"phone_number": "+15551234567",
"imessage": true,
"sms": true,
"rcs": false,
"checked_at": "2026-04-15T14:25:00.000Z",
"cached": false
}
}
The imessage field tells you whether this number can receive iMessages. The sms field indicates SMS availability (almost always true for valid US phone numbers). The rcs field shows RCS support status.
senderZ caches capability results for 24 hours. If you query the same number again within that window, cached will be true and the response will be instant. After 24 hours, the cache expires and senderZ performs a fresh check.
A few things to know about capability detection:
- It works by checking whether the phone number is registered with Apple’s iMessage servers, similar to what your iPhone does when it decides whether to send a blue or green bubble.
- The result can change. If someone switches from iPhone to Android, they lose iMessage capability. The 24-hour cache means there is a window where the cached result may be stale, but
channel: "auto"handles this gracefully — if iMessage delivery fails, the router falls back to SMS automatically. - Checking capability does not send a message. It is a read-only operation.
For bulk capability checking across a contact list, call the endpoint in parallel. Rate limits are generous (see your plan’s API call quota on the pricing page).
When iMessage Fails
iMessage delivery can fail for several reasons: the recipient switched to Android, their phone is off, they have no internet connection, or Apple’s iMessage servers are experiencing issues. Here is how senderZ handles each scenario.
Recipient is not on iMessage. When you send with channel: "auto", the router detects this during the send attempt. The iMessage engine reports that the message was sent as SMS instead of iMessage (green bubble instead of blue). senderZ records channel_used: "sms" and the message still reaches the recipient. No retry is needed — the fallback is automatic and immediate.
Recipient’s phone is off or disconnected. Apple queues the iMessage on their servers for a period of time (typically several days). If the recipient comes back online, the message delivers. If not, Apple eventually drops it. senderZ reports the final status through your webhook. If you need guaranteed delivery for time-sensitive messages, consider using channel: "sms" as a forced fallback after a configurable timeout.
The iMessage engine is temporarily offline. The message stays in the Cloudflare Queue. The router retries with exponential backoff — first after 10 seconds, then 30, then 60, up to 5 minutes between attempts. If the infrastructure comes back within the retry window, the message sends without you doing anything. If retries are exhausted, the message moves to "failed" status and your webhook receives a failure notification with a reason field explaining what happened.
Apple flags the sending Apple ID. This is the most serious failure mode. If Apple detects unusual sending patterns (too many messages to new contacts in a short period), they may temporarily restrict or ban the Apple ID. senderZ mitigates this with phone warming — new phones start with conservative daily limits (10 new contacts per day in the first week, ramping up to 50 after two weeks). If a phone does get flagged, the router automatically routes around it to other phones in the pool.
In all cases, your webhook receives a status update with the outcome. A typical failure webhook looks like this:
{
"event": "message.failed",
"data": {
"message_id": "msg_01HQ3K5V7XJNM2PRWT9F8YDCA6",
"status": "failed",
"reason": "imessage_unavailable",
"fallback_attempted": true,
"fallback_channel": "sms",
"fallback_status": "delivered"
}
}
This tells you: iMessage was not available, the router automatically fell back to SMS, and the SMS was delivered successfully. Your application does not need to implement retry logic — senderZ handles it end to end.
For integration patterns around failure handling, the Claude Code MCP integration lets you monitor delivery status conversationally, without writing webhook consumers.
FAQ
Is there an official Apple iMessage API?
No. Apple has never published a public API for iMessage and has shown no indication they plan to. iMessage is a closed, proprietary protocol that Apple controls entirely. Previous attempts to reverse-engineer the protocol (like Beeper in 2023) were shut down by Apple within days. The approach senderZ uses is different: it sends messages through real Apple hardware using Apple’s own apps and servers. There is no reverse engineering, no protocol spoofing, and no jailbreaking involved. Apple has no mechanism to distinguish these messages from ones typed by hand.
Do I need to jailbreak anything?
No. The entire senderZ stack runs on unmodified Apple hardware with stock devices and normal Apple IDs. No jailbreaking, no sideloading, no developer profiles, no MDM enrollment. No device needs to be modified in any way.
What happens if the recipient does not have iMessage?
When you send with channel: "auto", senderZ automatically falls back to SMS. The recipient receives a standard text message. Your webhook notification includes channel_used: "sms" so you know which channel delivered the message. No code changes are required on your side — the fallback is built into the routing layer.
How fast is iMessage delivery?
Typically under 2 seconds from API call to delivery on the recipient’s device. The API responds to your HTTP request in under 100 milliseconds with a queued status. The actual iMessage delivery — from queue pickup through senderZ’s iMessage engine to Apple’s servers to the recipient’s phone — takes 1-2 seconds in normal conditions. SMS fallback is slightly slower at 3-5 seconds due to carrier network latency.
Does this work outside the US?
senderZ currently supports US phone numbers only. The sending devices use US carriers, and the phone numbers are US-based. International expansion is on the roadmap but does not have a confirmed timeline. If you need to send to US numbers from an application hosted outside the US, that works — the API is accessible globally, only the phone numbers themselves are US-based.