iMessage REST API
A complete reference to the Blooio iMessage REST API — resources, HTTP verbs, authentication, errors, and idempotency.
The Blooio iMessage REST API lets you send and receive iMessages over plain HTTPS. This guide is a practical tour of the API's resources and conventions so you can integrate with any HTTP client — curl, fetch, requests, axios, or anything else.
What is a REST API for iMessage?
Apple does not expose a public iMessage API. Blooio runs real Apple infrastructure and exposes a standard REST interface on top of it, so any app that can speak HTTP can send iMessages. Every request uses plain JSON and returns predictable, documented response shapes.
Key properties:
- HTTPS only — every request goes to
https://backend.blooio.com/v2/api - Stateless — every request carries a Bearer token; no cookies or sessions
- JSON in, JSON out — no XML, no multipart except for file uploads
- Conventional HTTP verbs —
GET,POST,PATCH,DELETEdo what you'd expect - Predictable URLs —
/chats/{chatId}/messages,/contacts/{contactId},/groups/{groupId}/members
Base URL
https://backend.blooio.com/v2/apiAll examples in the docs are relative to this base URL.
Authentication
Every request includes a Bearer token in the Authorization header:
curl -X GET https://backend.blooio.com/v2/api/me \
-H "Authorization: Bearer YOUR_API_KEY"Get an API key from the Blooio dashboard. See Authentication for details on rotating keys and scoping permissions.
Resources
The REST API is organised into a handful of resources. Each resource is a plural noun at a top-level path.
| Resource | Path | What it represents |
|---|---|---|
| Chats | /chats | 1-to-1 or group conversations |
| Messages | /chats/{chatId}/messages | Individual messages inside a chat |
| Contacts | /contacts | People you message |
| Groups | /groups | Multi-party chats |
| Webhooks | /webhooks | HTTP endpoints you register to receive events |
| Numbers | /me/numbers | Phone numbers on your account |
HTTP verbs
Blooio uses the standard REST verb vocabulary. No surprises, no custom verbs.
| Verb | Meaning | Example |
|---|---|---|
GET | Fetch a resource or list | GET /contacts |
POST | Create or perform an action | POST /chats/{id}/messages |
PATCH | Partially update a resource | PATCH /contacts/{id} |
DELETE | Remove a resource | DELETE /webhooks/{id} |
Sending a message
The most common REST call — send an iMessage — is a single POST:
curl -X POST 'https://backend.blooio.com/v2/api/chats/%2B15551234567/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"text": "Hello from the REST API"}'const chatId = encodeURIComponent('+15551234567')
const res = await fetch(
`https://backend.blooio.com/v2/api/chats/${chatId}/messages`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BLOOIO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ text: 'Hello from the REST API' })
}
)
const { message_id } = await res.json()import os, requests
from urllib.parse import quote
chat_id = quote('+15551234567', safe='')
res = requests.post(
f'https://backend.blooio.com/v2/api/chats/{chat_id}/messages',
headers={
'Authorization': f"Bearer {os.environ['BLOOIO_API_KEY']}",
'Content-Type': 'application/json',
},
json={'text': 'Hello from the REST API'},
)
print(res.json()['message_id'])Response:
{
"message_id": "Qm8FhbH3P7R",
"status": "queued"
}Request conventions
URL-encoding phone numbers
Phone numbers contain a + which has special meaning in URLs. Always URL-encode the chatId:
// becomes %2B15551234567
const chatId = encodeURIComponent('+15551234567')Forgetting to encode the + is the single most common REST integration mistake.
Pagination
List endpoints use limit and offset:
curl 'https://backend.blooio.com/v2/api/chats?limit=25&offset=50' \
-H 'Authorization: Bearer YOUR_API_KEY'Defaults: limit=25, offset=0. Maximum limit is 100.
Sorting and filtering
Most list endpoints accept sort (e.g. created_at:desc) and a q search parameter. See each endpoint's reference page for supported fields.
Response shape
Every successful response is a JSON object. List endpoints return:
{
"data": [ ... ],
"count": 42,
"limit": 25,
"offset": 0
}Single-resource endpoints return the resource directly:
{
"id": "msg_abc123",
"text": "Hello",
"status": "delivered",
"created_at": "2026-04-19T12:34:56Z"
}Errors
Errors use standard HTTP status codes and a consistent JSON body:
{
"error": "invalid_request",
"message": "text or attachments is required",
"details": {
"field": "text"
}
}| Code | Meaning | Action |
|---|---|---|
400 | Invalid request body | Fix the payload |
401 | Missing or invalid API key | Check your Bearer token |
403 | Forbidden | The API key lacks permission |
404 | Resource not found | Check the ID or path |
409 | Conflict | Duplicate idempotency key or state mismatch |
422 | Semantically invalid | Payload is valid JSON but logically wrong |
429 | Rate limited | Back off; check Retry-After |
5xx | Server error | Retry with exponential backoff |
See Error handling for retry strategies.
Idempotency
Send the Idempotency-Key header on POST requests to make them safe to retry:
curl -X POST 'https://backend.blooio.com/v2/api/chats/%2B15551234567/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Idempotency-Key: a1b2c3d4-order-123' \
-H 'Content-Type: application/json' \
-d '{"text": "Hello"}'If the same key is sent twice within 24 hours, Blooio returns the original response without creating a duplicate message. See Idempotency for the full rules.
Rate limits
Rate limits are automatically managed per API key. The current limit is returned on every response:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests allowed per window |
X-RateLimit-Remaining | Requests left in this window |
X-RateLimit-Reset | Unix timestamp when the window resets |
On 429, honour the Retry-After header (seconds) before retrying.
Webhooks
The REST API's read side is usually backed by webhooks — Blooio POSTs events to a URL you register. Create a webhook:
curl -X POST 'https://backend.blooio.com/v2/api/webhooks' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"webhook_url": "https://yourapp.com/hooks/blooio",
"webhook_type": "all"
}'Events include message received, delivered, failed, and reactions. See Webhook events for the full catalogue.
If your endpoint is not yet reachable publicly, use a tunnel like ngrok — see Receive webhooks locally.
Code examples
Full end-to-end examples live in message-sending basics. For language-specific walkthroughs see:
Next steps
- Quickstart — send your first iMessage in under five minutes
- Authentication — API key management and rotation
- Webhook signatures — verify event authenticity
- API reference — every endpoint, every field