iMessage API
API-first iMessage for AI agents. Use the shared Inkbox iMessage router or attach a dedicated line, then read and send messages, use tapbacks, read receipts, typing indicators, and media, and subscribe to events via webhooks.
API base URL:
Quick start
Create an account and get your API key from the Inkbox console:
All API requests require authentication using an API key:
Three things to know before your first call:
- iMessage is opt-in per identity. Set
imessage_enabled: truewhen creating or updating an identity. - Shared-service conversations start with the human. Recipients connect to a shared identity by texting
connect @your-handleto the router number. - A dedicated line can start conversations. An identity with an attached dedicated line can start new 1:1 conversations and group chats with 2-8 E.164 recipients. Keep the returned
conversation_idas the canonical group key. Group creation is asynchronous, and conversation reads reportgroup_creation_statusascreating,not_created, orready. Existing lists exclude groups unlessinclude_groups=true.
Dedicated lines
Dedicated lines belong to your organization and can be attached to an iMessage-enabled identity. Every dedicated line can start new 1:1 conversations and group chats. Shared service dynamically assigns a line only after someone connects to your agent.
List dedicated lines GET
Returns every dedicated iMessage line owned by the caller's organization, including lines that are not attached to an identity.
Response (200)
| Field | Type | Description |
|---|---|---|
id | UUID | Dedicated-line identifier |
number | string | iMessage number in E.164 format |
type | string | Always dedicated_outbound. This response-only compatibility field is not a capability selector. |
status | string | active; existing numbers may return paused as a read-only compatibility value. This field cannot be set through number or identity update requests. |
agent_identity_id | UUID | null | Attached identity ID, or null when unattached |
agent_handle | string | null | Attached identity handle, or null when unattached |
Claim a dedicated line POST
Claims one unattached dedicated line for the organization. Use an admin API key, or manage dedicated lines from the Inkbox Console.
The request requires a stable key in the Idempotency-Key header:
Request body
Response (201)
Returns one unattached dedicated-line object with the same schema as the list endpoint. Its response-only type field remains "dedicated_outbound" for compatibility.
Idempotency
- Retry the same logical claim with the same key to receive its original result.
- Reusing the key with different input returns
409. - Generate a new key only for a genuinely new claim.
Error responses
| Status | Description |
|---|---|
| 402 | Your organization's quota does not permit another dedicated line. Review billing in the Inkbox Console or contact support@inkbox.ai. |
| 403 | This operation requires an admin API key or the Inkbox Console. |
| 409 | The Idempotency-Key was already used with incompatible input. Use the original input, or use a new key for a genuinely new claim. |
| 422 | The request is invalid, including when Idempotency-Key is missing or the body contains unsupported input. |
| 503 | Inventory is temporarily unavailable. Honor Retry-After: brief contention may return 5 seconds, while depletion may return 3600 seconds. The response may say that a number is expected within 24 hours. |
Attach or detach an organization-owned line through PATCH /api/v1/identities/{agent_handle}. Detaching does not release the line; there is no customer-facing line-release endpoint.
Router
Messaging capability
Messages
Send message
POSTSend 1:1 or group iMessages
List messages
GETList iMessages visible to the caller, newest first
Upload media
POSTUpload a file and get a URL usable in media_urls
Dedicated-line group chats use these same message and conversation routes; there is no separate group-send endpoint.
Conversations
List conversations
GETList conversation summaries with latest-message previews and unread counts
Get conversation
GETGet a single conversation by ID
List connections
GETList recipients currently connected to an agent identity
Mark conversation read
POSTSend a read receipt and mark inbound messages read
Send typing indicator
POSTShow the typing bubble to the conversation's recipient
Tapbacks
Send tapback
POSTReact to a message; a new tapback replaces your previous one
Remove tapback
DELETETake back a tapback your agent sent
Contact rules
Per-identity allow and block rules interpreted against the identity's iMessage filter_mode (blacklist by default, whitelist on demand). Rules stay scoped to the agent identity whether it uses shared service or a dedicated line. See the Contact rules reference and the iMessage guide for semantics.
List contact rules
GETList allow/block rules for an agent identity
Create contact rule
POSTAdd an allow or block rule (E.164 exact match)
Get contact rule
GETFetch a single rule by ID
Update contact rule
PATCHChange a rule's action (admin-only)
Delete contact rule
DELETEDelete a rule (admin-only)
List org iMessage contact rules
GETOrg-wide aggregate list across every identity (admin-only)
Webhooks
Inbound events (imessage.received, imessage.reaction_received) and outbound delivery-lifecycle events (imessage.sent, imessage.delivered, imessage.delivery_failed) are delivered via the Webhook Subscriptions API — attach a subscription to the agent identity with the subset you want. See the iMessage webhooks reference for event types, payload format, and signature verification.
Filtering by date
Date filtering applies to two list endpoints — List messages (GET /messages) and List conversations (GET /conversations). These accept three optional query parameters that filter results by when each record was created (created_at, stored in UTC); other iMessage list endpoints (such as list connections and list contact rules) do not support them. All three are optional and fully backwards-compatible — omit them and the endpoint behaves exactly as before, with no filtering applied.
| Parameter | Type | Default | Description |
|---|---|---|---|
start_datetime | string | — | Inclusive lower bound. A bare date (2026-07-01) starts at 00:00 of that day; a datetime with a Z or offset is used as an exact instant |
end_datetime | string | — | Upper bound, inclusive. A bare date (2026-07-06) covers the whole day; a datetime with a Z or offset is an exact instant, and records created at exactly that instant are included |
tz | string | UTC | IANA time zone (e.g. America/New_York) used to interpret zone-less values. Defaults to UTC |
- A bare date in
end_datetimeis inclusive of the entire day —end_datetime=2026-07-06returns records through the last moment of the 6th. - A datetime with an explicit
Zor offset (2026-07-06T15:30:00Z,2026-07-06T11:30:00-04:00) is an exact instant;tzis ignored for that value. - A naive datetime (
2026-07-01T12:00:00) is interpreted intz(UTC whentzis omitted). - Supply only one side for an open-ended range. Ordering, pagination, and all other filters are unchanged.
- Invalid input returns
422:start_datetimeafterend_datetime, an unparseable date, or an unknown time zone.
A bare-date range (interpreted in UTC):
Interpret those bare dates in a specific zone:
Filter from an exact instant (tz ignored):