Blooio API Reference

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

Base URL

https://backend.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://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.

ResourcePathWhat it represents
Chats/chats1-to-1 or group conversations
Messages/chats/{chatId}/messagesIndividual messages inside a chat
Contacts/contactsPeople you message
Groups/groupsMulti-party chats
Webhooks/webhooksHTTP endpoints you register to receive events
Numbers/me/numbersPhone numbers on your account

HTTP verbs

Blooio uses the standard REST verb vocabulary. No surprises, no custom verbs.

VerbMeaningExample
GETFetch a resource or listGET /contacts
POSTCreate or perform an actionPOST /chats/{id}/messages
PATCHPartially update a resourcePATCH /contacts/{id}
DELETERemove a resourceDELETE /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"
  }
}
CodeMeaningAction
400Invalid request bodyFix the payload
401Missing or invalid API keyCheck your Bearer token
403ForbiddenThe API key lacks permission
404Resource not foundCheck the ID or path
409ConflictDuplicate idempotency key or state mismatch
422Semantically invalidPayload is valid JSON but logically wrong
429Rate limitedBack off; check Retry-After
5xxServer errorRetry 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:

HeaderMeaning
X-RateLimit-LimitRequests allowed per window
X-RateLimit-RemainingRequests left in this window
X-RateLimit-ResetUnix 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

On this page