BetaThe V4 API is in beta — endpoints and functionality may change.

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://api.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 verbsGET, POST, PATCH, DELETE do what you'd expect
  • Predictable URLs/chats/{chatId}/messages, /contacts/{contactId}, /groups/{groupId}/members

Base URL

https://api.blooio.com/v2/api

All 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://api.blooio.com/v2/api/me \
  -H "Authorization: Bearer YOUR_API_KEY"
Try it

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

curl -X POST 'https://api.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"}'
Try it

Node.js

const chatId = encodeURIComponent('+15551234567')

const res = await fetch(
  `https://api.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()

Python


from urllib.parse import quote

chat_id = quote('+15551234567', safe='')

res = requests.post(
    f'https://api.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://api.blooio.com/v2/api/chats?limit=25&offset=50' \
  -H 'Authorization: Bearer YOUR_API_KEY'
Try it

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://api.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"}'
Try it

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://api.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"
  }'
Try it

Events include message received, delivered, failed, and reactions. See Webhook events for the full catalogue.

Note

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