Skip to content
imessageapi

How do I send an iMessage programmatically?

Short answer

Pick one of three routes: call a hosted provider's REST API (fastest, costs money), run a self-hosted bridge on a Mac you own (free, you operate it), or script Messages.app with AppleScript (free, fragile, no inbound). All three are shown below with working shapes.

8 min readUpdated August 24, 2026Building

This is the most common form of the question, and it has a clean answer once you know that Apple publishes no API. You are choosing between three routes, and the choice is mostly about who operates the hardware.

Viable routes
3Viable routes
To first send, hosted
~1hrTo first send, hosted
Cost of the self-hosted route
$0Cost of the self-hosted route
Official Apple endpoints
0Official Apple endpoints

Route 1 — a hosted provider's REST API

The fastest path, and what most people should use. You POST a phone number and a body; the provider's infrastructure sends the actual iMessage. Every vendor's API is a variation on this shape.

Sending through a hosted provider
# Illustrative shape. Endpoints and field names differ per vendor —
# always check the provider's live docs.
curl -X POST https://api.example-provider.com/v1/messages \
-H "Authorization: Bearer $IMESSAGE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "+15551234567",
"text": "Your appointment is confirmed for Tuesday at 2pm. Reply STOP to opt out.",
"send_style": "default"
}'
The same thing in TypeScript, wrapped so you can switch vendors
// Write to your own interface from day one. When you change providers —
// and in this category you might — this is the only file that moves.
type SendResult = { id: string; channel: "imessage" | "sms" };
 
export async function send(to: string, text: string): Promise<SendResult> {
const res = await fetch("https://api.example-provider.com/v1/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.IMESSAGE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ to, text }),
});
 
if (!res.ok) {
// Treat 429 and 5xx as retryable; 4xx as a bug in your call.
throw new Error(`send failed: ${res.status} ${await res.text()}`);
}
 
const data = await res.json();
return { id: data.id, channel: data.channel ?? "imessage" };
}

Wrap the vendor on day one

That send() function is thirty seconds of work and it is the difference between a provider migration taking an afternoon and taking a sprint. Given how young most vendors in this category are, treat it as mandatory. More in switching providers.

Route 2 — a self-hosted bridge

You run a Mac. Software like BlueBubbles watches the local Messages database and exposes a REST API on your own network. No third party holds your Apple ID, no per-line fee, and no vendor to go out of business.

Sending through a local bridge
# The bridge runs on your Mac; the API is yours, on your network.
curl -X POST "http://your-mac.local:1234/api/v1/message/text" \
-H "Content-Type: application/json" \
-d '{
"password": "'"$BRIDGE_PASSWORD"'",
"chatGuid": "iMessage;-;+15551234567",
"message": "Your appointment is confirmed for Tuesday at 2pm."
}'

The trade is straightforward: you swap a monthly bill for an operational responsibility. That Mac must stay awake, stay signed in, stay updated, and stay on a connection. For an internal tool that is nothing. For customer-facing messaging it is a real job.

Route 3 — AppleScript

The floor of the category. Twelve lines, no dependencies, no account, no cost. Also no inbound messages, no delivery confirmation, and it breaks whenever Apple changes Messages.app.

AppleScript, driven from Node
import { execFile } from "node:child_process";
import { promisify } from "node:util";
 
const run = promisify(execFile);
 
export async function sendLocal(phone: string, text: string) {
// Passing values as argv keeps quotes and apostrophes from breaking
// the script — never string-concatenate user text into AppleScript.
const script = `
on run argv
set phone to item 1 of argv
set msg to item 2 of argv
tell application "Messages"
set svc to 1st account whose service type = iMessage
send msg to participant phone of svc
end tell
end run`;
 
await run("osascript", ["-e", script, phone, text]);
}

Which route to pick

If this is trueUseWhy
You are messaging customers and it mattersHosted providerDelivery signal, inbound webhooks, SMS fallback, someone else's account risk
You want blue bubbles with no monthly bill and you own a MacSelf-hosted bridgeFull control, no vendor, no per-line fee
You need a script to text you when a job finishesAppleScriptZero setup, and none of the missing features matter
You need an officially sanctioned channelApple Messages for BusinessThe only Apple-approved route — grey bubble, inbound-initiated

Three things that will bite you

  1. Not every recipient is on iMessage. Roughly half of US mobile users are on Android. Without SMS fallback, those messages silently do not arrive. Confirm fallback behaviour before you launch.
  2. Links in texts get scrutinised. A bare shortened URL from an unknown number reads as a scam. Use your own domain and tag it — the UTM builder generates the links, and link shorteners and spam filters explains why the shortener matters.
  3. Consent is not optional. You need it before the first message, and an opt-out path in every campaign. Consent before you text covers what that means in practice.

Language-specific walkthroughs: Node.js and Python. The plain-HTTP framing of the same thing is in is there a third-party POST API. To go end to end from nothing, start at your first iMessage from code.

Related questions

Can I send an iMessage from a server?
Not directly through Apple. You send it through a hosted iMessage provider's REST or gRPC API, or through a bridge running on a Mac you control.
What is the fastest way to send an iMessage from code?
A hosted provider with published pricing and a sandbox. You can typically get a message delivered within an hour of signing up, with no Mac involved.

Still deciding?

Compare the services that can actually send this on the providers page, see what each one costs, or read the step-by-step guides.