# iMessage

Try iMessage on the sandbox line today. Ordering a dedicated sender is not available yet; this page also covers opt-in links, pacing rules for new contacts and rich iMessages.

> **Not available yet:**
> 
> Ordering an iMessage sender and registering one you already hold are not available yet: [`POST /v1/imessage/senders/order`](https://pozy.ai/docs/api/orderImessageSender) and [`POST /v1/imessage/senders`](https://pozy.ai/docs/api/registerImessageSender) answer `403` with `code: "feature_not_available"`. You can try iMessage on the [sandbox](#sandbox) line in the meantime. The rest of this page describes senders as they will work.

To use iMessage you order a sender of your own, registered with Apple, from the API or the dashboard. When it is ready it shows up as an `imessage` account, and its chats live in the [Inbox](https://pozy.ai/docs/inbox) next to WhatsApp, SMS and social DMs. People without iMessage still get your message, as SMS or RCS from the same number.

This page is the platform summary. Numbers, porting and compliance for other channels are in [Phone, SMS & voice](https://pozy.ai/docs/telephony).

## What you can do

| Feature | Supported | Where |
| --- | --- | --- |
| Order a sender (US or UK number, or an email address) | Not available yet | [Connect](#connect) |
| Free shared test line | Yes | [Sandbox](#sandbox) |
| Opt-in links that open Messages with prefilled text | Yes | [Bring contacts in](#bring-contacts-in) |
| Message people who never wrote to you | Yes, paced and warmed up | [New contacts](#new-contacts) |
| Text, media, voice notes, location, contact card | Yes | [Sending messages](#sending-messages) |
| Effects, subject line, replies, reactions | Yes | [Sending messages](#sending-messages) |
| Edit and unsend | Within Apple's windows | [Limits](#limits) |
| Group chats | Yes | [Inbox](#inbox) |
| SMS and RCS fallback | Yes, on ordered numbers | [Sending messages](#sending-messages) |
| Publishing, analytics | No | Messaging only |

## Connect

> **Not available yet:**
> 
> Ordering and registering senders are not available yet. Both calls below answer `403` with `code: "feature_not_available"`.

A sender is one dedicated number (or email address) on one profile. iMessage cannot run on a number you already have elsewhere, because Apple only registers numbers hosted for this service. You need a payment method on file and usage-based billing first.

```bash cURL
curl -X POST https://api.pozy.ai/v1/imessage/senders/order \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profileId": "66a1f0c2a4b9d3e8f1a2b3c4",
    "kind": "phone",
    "region": "US",
    "displayName": "Acme Support",
    "purchaseIntentId": "order-acme-support-1"
  }'
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/imessage/senders/order", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    profileId: "66a1f0c2a4b9d3e8f1a2b3c4",
    kind: "phone",
    region: "US",
    displayName: "Acme Support",
    purchaseIntentId: "order-acme-support-1",
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.sender.id, data.sender.status);
```
```python Python
import os, requests

resp = requests.post(
    "https://api.pozy.ai/v1/imessage/senders/order",
    headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
    json={
        "profileId": "66a1f0c2a4b9d3e8f1a2b3c4",
        "kind": "phone",
        "region": "US",
        "displayName": "Acme Support",
        "purchaseIntentId": "order-acme-support-1",
    },
)
sender = resp.json()["sender"]
print(sender["id"], sender["status"])
```

> **Always send purchaseIntentId:**
> 
> An order is never retried for you. Repeating the call with the same `purchaseIntentId` returns the existing order instead of buying a second number.

You get `202` back, with the sender `ordering` or `activating`. Activation finishes later on its own: check [Get iMessage sender status](https://pozy.ai/docs/api/getImessageSender) from time to time, or listen for the `account.connected` webhook, which includes the new account id. You are billed from the moment it is active.

| Option | How |
| --- | --- |
| A number that activates instantly | List the pool with [List instantly available iMessage numbers](https://pozy.ai/docs/api/listImessageAvailableNumbers) and pass the item's `id` as `availableNumberId`. Hold one for 3 minutes with [Reserve](https://pozy.ai/docs/api/reserveImessageAvailableNumber). The pool can be empty for a region |
| A number near an area (US) | Leave out `availableNumberId` and send `zipCode`. The carrier assigns a number, usually within hours |
| An email sender | `kind: "email"` with `emailName` and `emailDomain`. API only |
| A sender you already hold | [Register an iMessage sender](https://pozy.ai/docs/api/registerImessageSender) attaches it to a profile |

[Update an iMessage sender](https://pozy.ai/docs/api/updateImessageSender) sets the display name and the contact card (name and square photo) people see when they save the number. [Cancel](https://pozy.ai/docs/api/cancelImessageSender) takes the sender offline at once and stops the next month's charge. One sender per profile.

## Sandbox

Before you order, try iMessage on the shared sandbox line for free:

1. Add your own phone number or Apple ID email with [Add an iMessage sandbox contact](https://pozy.ai/docs/api/addImessageSandboxContact). It starts `pending`.
2. From that phone, send the returned `joinText` (for example `JOIN 4821`) to the sandbox line. `joinLink` opens Messages with it filled in.
3. The contact turns `active`. Everything you send to the line now arrives in your inbox and fires your webhooks.

The handle must be the one your device starts new conversations from (iPhone: Settings, Apps, Messages, Send & Receive). Sandbox rules: up to 5 contacts per user, a 24-hour reply window after the contact's last message, 50 messages a day, no starting conversations, no groups, and no verification codes, prices or marketing. It is free and does not count as a connected account.

## Bring contacts in

The safest way to start is to let the contact write first. It needs no pacing, has no content rules and records consent.

- Each sender has an `optInLink` (an `imessage://` link with prefilled text) and an `imessageLink` web page that opens Messages from any Apple device, useful in email.
- [Create a tracked iMessage opt-in link](https://pozy.ai/docs/api/createImessageOptInLink) returns `imessage`, `sms` and `whatsapp` links plus a hosted `url` that picks the right one for the device. When the contact sends the message, `message.received` carries `metadata.optIn: true` and your parameters in `metadata.optInParameters`, so you can attribute the conversation. Unused links expire after 24 hours.

An inbound STOP (also STOPALL, UNSUBSCRIBE, CANCEL, END, QUIT) opts the contact out and skips automations for that message. START, UNSTOP or SUBSCRIBE opts them back in. [List iMessage audience](https://pozy.ai/docs/api/listImessageAudience) lists everyone who has messaged your senders with their `subscribed` state, and [Subscribe or opt out](https://pozy.ai/docs/api/setImessageSubscription) changes it on your side.

## New contacts

An ordered sender can message someone who never wrote to it, with [Create conversation](https://pozy.ai/docs/api/createInboxConversation). Apple shows these messages with a Report Junk button, and reports can block a sender for good, so Pozy enforces the rules before anything is sent.

```json
{
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "participantId": "+13105551234",
  "message": "Hi Chris, this is Sam from Northwind Builders. I build websites for contractors. Would you like to see a couple of examples?"
}
```

| Rule | Value |
| --- | --- |
| First message | An introduction to one person. No links or bare domains, emails, phone numbers, prices or attachments. Breaking this returns `400` `invalid_content` and the message is not sent |
| Follow-ups before a reply | At most 2, at least 24 hours apart, held to the same content rule. A fourth message returns `409` `recipient_must_message_first` |
| Spacing | One new conversation every 15 minutes per sender |
| Warm-up: new conversations allowed in 24 hours | 2 on days 1 and 2, 5 on days 3 and 4, 10 on days 5 to 7, 20 on days 8 to 14, 30 on days 15 to 21, then 50 |
| Contacts silent for 24 hours | Each sender waits at least 2 minutes between messages to them |

A send past a limit gets `429` `new_contact_limit`, together with the time you may try again. Write like a person talking to one other person. Sales pitches, made-up deadlines and anything that looks like a mass mailing get flagged by recipients. Watch your reply rate, and stop writing to someone who has left three messages unanswered. As soon as a contact answers, the limits no longer apply to that chat.

## Sending messages

Replies use the same [Send message](https://pozy.ai/docs/api/sendInboxMessage) call as every channel, with the sender's `accountId`:

```json
{
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "message": "Your table for four is confirmed for *Friday at 8pm*.",
  "subject": "Booking confirmed",
  "effect": "confetti"
}
```

| Feature | How |
| --- | --- |
| Text | `message`, under 10,000 characters. `*bold*`, `_italic_`, `__underline__` and `~strikethrough~` render as rich text |
| Attachments | 10 per message at most, each given as a public HTTPS URL no longer than 256 characters |
| Voice note | Send audio (mp3, wav, m4a, caf or aac) as an attachment and set `voiceNote: true` |
| Contact card | `contactCard: true` shares the sender's card. Set it on the sender first |
| Subject | `subject` shows as a bold line above the text |
| Effects | `effect`: `slam`, `loud`, `gentle`, `invisibleInk`, `echo`, `spotlight`, `balloons`, `confetti`, `love`, `lasers`, `fireworks`, `shootingStar`, `celebration` |
| Link previews | On by default. `linkPreview: false` sends plain links |
| Channel | Set `channel` to `imessage`, `sms`, `rcs` or `whatsapp` to force one for this send; without it Pozy chooses for each contact |
| Replies | `replyTo` with the message id |

`subject`, `effect`, `contactCard` and `channel` only work on iMessage and return `400` elsewhere. Typing indicators and read receipts work inside an active two-way conversation.

## Limits

| Limit | Value |
| --- | --- |
| Text | Under 10,000 characters |
| Attachments | 10 per message |
| Edit window | 15 minutes after sending ([Edit message](https://pozy.ai/docs/api/editInboxMessage)) |
| Unsend window | 2 minutes after sending ([Delete message](https://pozy.ai/docs/api/deleteInboxMessage)) |
| Unique contacts | 1,000 per sender per day |
| Senders | 1 per profile |
| Regions | US and UK numbers |

Past the edit or unsend window, the calls return `409` `edit_window_expired` or `unsend_window_expired`.

## Inbox

Inbound messages fire `message.received`. `metadata` includes the channel the message arrived on, the message type, the reply thread id, a detected language, the transcript of a voice message and any rich-text markup as `markdownText`. Inbound media is copied to Pozy storage so the links keep working. Apple's six tapbacks render natively, other emoji are sent as custom tapbacks (iOS 18 and later), and inbound reactions arrive as `reaction.received`.

Group threads arrive as their own conversation with `isGroup: true`. Start one with [Start an iMessage group chat](https://pozy.ai/docs/api/createImessageGroup) (asynchronous; the thread appears with the first group webhook), and rename it or add and remove people with the group endpoints.

## Pricing

A sender has a flat monthly fee, charged at activation and on the 1st of each month while it is active, with no per-message fee. Its `imessage` account also counts as a connected account. The first month and any month already started are not refundable. See [Pricing](https://pozy.ai/docs/billing) for current prices.

## Errors you may see

| Status | Code | Meaning | Fix |
| --- | --- | --- | --- |
| `400` | `invalid_content` | The opening message contains a link, an email address, a phone number, a price or an attachment | Take it out; the error names what was caught |
| `429` | `new_contact_limit` | Spacing, warm-up or follow-up limit | Retry after the time in the error |
| `409` | `recipient_must_message_first` | You sent three messages that got no answer, or this sender is not allowed to start chats | Wait until they reply, or send them an opt-in link |
| `409` | `recipient_opted_out` | The contact asked to stop | Only their START lets you write again |
| `400` | `sender_unavailable` | The sender is not active yet, or you sent `contactCard` before setting up a card | Check the sender's status, or set up the card first |
| `400` | `recipient_unreachable` | Not a mobile, or the contact blocks all messages | Check the handle |
| `402` | `payment_method_required` | No card on file | Add a payment method |
| `422` | `usage_billing_required` | Billing is not usage-based | Turn on usage-based billing for the workspace |
| `409` | `imessage_sender_conflict` | Another profile already has this sender | Cancel that sender before ordering again |
| `403` | `imessage_sender_limit` | Your sender cap is reached | Cancel a sender you no longer use |

[Errors](https://pozy.ai/docs/getting-started/errors) covers the error format.

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/imessage/senders`](https://pozy.ai/docs/api/listImessageSenders) | List iMessage senders |
| [`POST /v1/imessage/senders`](https://pozy.ai/docs/api/registerImessageSender) | Register an iMessage sender (not available yet) |
| [`GET /v1/imessage/senders/order`](https://pozy.ai/docs/api/listImessageSenderOrders) | List iMessage sender orders |
| [`POST /v1/imessage/senders/order`](https://pozy.ai/docs/api/orderImessageSender) | Order a new iMessage sender (not available yet) |
| [`GET /v1/imessage/senders/{senderId}`](https://pozy.ai/docs/api/getImessageSender) | Get iMessage sender status |
| [`PATCH /v1/imessage/senders/{senderId}`](https://pozy.ai/docs/api/updateImessageSender) | Update an iMessage sender |
| [`DELETE /v1/imessage/senders/{senderId}`](https://pozy.ai/docs/api/cancelImessageSender) | Cancel an iMessage sender |
| [`GET /v1/imessage/audience`](https://pozy.ai/docs/api/listImessageAudience) | List iMessage audience |
| [`GET /v1/imessage/sandbox/contacts`](https://pozy.ai/docs/api/listImessageSandboxContacts) | List iMessage sandbox contacts |
| [`POST /v1/imessage/sandbox/contacts`](https://pozy.ai/docs/api/addImessageSandboxContact) | Add an iMessage sandbox contact |
| [`DELETE /v1/imessage/sandbox/contacts/{contactId}`](https://pozy.ai/docs/api/removeImessageSandboxContact) | Remove an iMessage sandbox contact |
| [`POST /v1/imessage/audience/subscription`](https://pozy.ai/docs/api/setImessageSubscription) | Subscribe or opt out an iMessage contact |
| [`POST /v1/imessage/senders/{senderId}/opt-in-links`](https://pozy.ai/docs/api/createImessageOptInLink) | Create a tracked iMessage opt-in link |
| [`GET /v1/imessage/senders/available-numbers`](https://pozy.ai/docs/api/listImessageAvailableNumbers) | List instantly available iMessage numbers |
| [`POST /v1/imessage/senders/available-numbers/{numberId}/reserve`](https://pozy.ai/docs/api/reserveImessageAvailableNumber) | Reserve an available iMessage number |
| [`POST /v1/imessage/groups`](https://pozy.ai/docs/api/createImessageGroup) | Start an iMessage group chat |
| [`GET /v1/imessage/groups/{conversationId}`](https://pozy.ai/docs/api/getImessageGroup) | Get an iMessage group |
| [`PATCH /v1/imessage/groups/{conversationId}`](https://pozy.ai/docs/api/updateImessageGroup) | Rename an iMessage group or change its photo |
| [`POST /v1/imessage/groups/{conversationId}/participants`](https://pozy.ai/docs/api/addImessageGroupParticipant) | Add a participant to an iMessage group |
| [`DELETE /v1/imessage/groups/{conversationId}/participants`](https://pozy.ai/docs/api/removeImessageGroupParticipant) | Remove a participant from an iMessage group |

## Webhook events

| Event | When it fires |
| --- | --- |
| [`account.connected`](https://pozy.ai/docs/webhooks/events#account-connected) | Account connected. |
| [`message.received`](https://pozy.ai/docs/webhooks/events#message-received) | Message received. |
| [`conversation.started`](https://pozy.ai/docs/webhooks/events#conversation-started) | Conversation started. |
| [`message.sent`](https://pozy.ai/docs/webhooks/events#message-sent) | Message sent. |
| [`message.edited`](https://pozy.ai/docs/webhooks/events#message-edited) | Message edited. |
| [`message.deleted`](https://pozy.ai/docs/webhooks/events#message-deleted) | Message deleted. |
| [`message.delivered`](https://pozy.ai/docs/webhooks/events#message-delivered) | Message delivered. |
| [`message.read`](https://pozy.ai/docs/webhooks/events#message-read) | Message read. |
| [`message.played`](https://pozy.ai/docs/webhooks/events#message-played) | Message played. |
| [`message.failed`](https://pozy.ai/docs/webhooks/events#message-failed) | Message delivery failed. |
| [`reaction.received`](https://pozy.ai/docs/webhooks/events#reaction-received) | Reaction received. |
