Lines
A line is what sends and receives messages. Every message belongs to one line, and a send names the line it leaves from. A line has an id, astatus, and fields that say what kind of line it is.
The line’s device is the hardware that sends and receives for a line. iSnap hands each message to the line’s device, and the device reports what happened to it. A status such as delivered therefore exists only when the device reports it.
The marketplace is the set of lines that
GET /v1/lines lists: lines you can take now. GET /v1/lines/my lists your own lines whose status is active or reserved.
Line kinds
Five fields of the line object tell the kinds of line apart.capabilities follows the kind, except on a pool line that iSnap created for your account:
An Android line is a line whose
billing_tier is rental_android or byod_android, or a test line whose capabilities include rcs. Every other line is an iMessage line: its device is a Mac, and a shared line sends from the numbers of iSnap’s own iMessage lines. The two have different default sending limits.
These API values contain pool. billing_tier: shared_pool marks a test line or a dedicated pool line, and ownership: pool in GET /v1/attention marks the same lines. pool_line_id and pool_line_number name the pool line of a trial: see Trials. The code pool_line_not_terminable refuses to terminate a dedicated pool line, and pool_line_not_cancellable refuses to cancel a test line or a dedicated pool line. The code line_pool_exhausted means that no number of a shared line, or no pool line, is free.
Line statuses
status takes one of six values.
A send from a line that is neither
active nor suspended returns 400 line_not_active.
What moves a line from one status to another:
Three things to know about these statuses:
- Only iSnap lifts a suspension. Write to support@isnap.ai to ask for it. A suspended line of a wholesale partner still counts on the monthly invoice.
GET /v1/lines/mylists onlyactiveandreservedlines: a line that becomessuspendedorcancelledleaves the list. Read a rented or BYOD line in any status withGET /v1/lines/{id}. Acancelledline keeps its owner. No read operation returns a shared line, a test line or a dedicated pool line that issuspendedorcancelled:GET /v1/lines/mylists it only while it isactiveorreserved, andGET /v1/lines/{id}returns404 not_foundfor it in every status.GET /v1/attentiondoes not list a line for beingsuspended: keep the ids of your lines, and read each withGET /v1/lines/{id}.- No event announces a reservation, its expiry, a release, an activation by
activate, byassignor by a payment in the dashboard, the creation of a shared line, a suspension, the end of a suspension, or the return of a rented line to the marketplace. See What events do not announce, and read the status from the API.
Accounts
Two kinds of account call the API.- A wholesale partner is an account that iSnap bills on one monthly invoice. iSnap grants this status: write to support@isnap.ai to ask for it.
- A direct account is any account that is not a wholesale partner. It pays in the iSnap dashboard, by card: there it buys a marketplace line, pays the first month of a pre-order, buys BYOD slots and hosted macOS sessions, and saves a card. No operation that an API key can call makes these payments. Through the API, a direct account cannot activate a reserved line, assign a line, create a shared line or rent a hosted macOS session. It pays for an active rented line through a per-line subscription, whose id is the line’s
stripe_subscription_id. That field isnullon a rented line that the account received by transfer while the line was notactive.
What a direct account receives on those operations:
The operations table marks every operation that is for wholesale partners only.
Messages
A message is one text, one or more attachments, or both, exchanged between one line and one contact. The contact is the person on the other side. The recipient is theto of a send. A handle is what identifies a contact: a phone number in E.164, or an email address. A send takes a phone number only. An inbound message can come from an email address.
The message object has one shape everywhere: in the response of a send, of a read and of a cancel, in each item of GET /v1/messages, and in the message field of message events.
iSnap deletes every message at least 72 hours after it recorded it, whatever its status: see Retention.
A message carries personal data: the handles in
to and from, the text in body, attachment file names, and whatever you put in metadata. Request it only when needed. Do not copy it into logs, tickets or other tools. Refer to a contact by an id of your own.
Message statuses
status takes one of seven values.
An outbound message moves from
scheduled to queued, then to sent, delivered and read. Around that path:
- A
queuedorscheduledmessage can becomecancelled. - A message in any status except
cancelledcan becomefailed, even afterdeliveredorread. cancellednever changes. Treatfailedas final too: after a failure that the line’s device reported, a late send confirmation can setstatusback tosent, whilefailed_atstays set. A message that has afailed_atfailed.- Nothing is guaranteed to follow
sent,deliveredorread. iSnap learns “delivered” and “read” only from the line’s device and never assumes them: with no report, a message stayssentuntil iSnap deletes it. - An inbound message is
deliveredfrom the start. There is no status for “received”.
status back to sent while delivered_at stays set. A message can become read while delivered_at is still null. Use the timestamps, not only status: a message with a delivered_at was delivered. To build the status from events, apply Building the status from events.
A message becomes failed in four cases: the device reported a failure, the device took the message and never reported an outcome, the message was still waiting 48 hours after iSnap accepted it (a held message included), or the line was terminated while the message was waiting. iSnap never resends a failed message. Sending messages describes each case and what to do.
Services
The service is what the line’s device used to carry a message:iMessage, SMS or RCS. The service field of a message reports it.
- The device chooses the service when it sends. The API cannot choose it.
serviceisnulluntil the device confirms the send. It staysnullwhen the send fails, and when the device does not report the service.channelis a request field ofPOST /v1/messagesthat only takesauto, its default.- In a response,
channelisautoon a message sent through the API. On an inbound message, and on a message typed on the line’s device, it equalsservice. On a reaction it isiMessage.
capabilities: see Line kinds.
Chats
A chat is the exchange between one line and one contact. iSnap creates it at the first message in either direction and uses the same chat for both directions. Its id ischat_ followed by 25 characters.
- The message object has no chat id.
GET /v1/chatsgives the chat ids, and so does thechat_idfield ofmessage.received, ofmessage.sentwithorigin: "device", of themessage.readthat follows your own mark-read call, and of the typing indicator events. - A message that the line receives in a group is recorded in one chat for that group. That chat shows a single
contact_handle, the first sender seen, and nothing marks it as a group. iSnap does not send to groups. - A chat is never deleted. It stays listed after its messages are deleted.
- A chat belongs to its line, not to your account. When a line leaves your account, by a transfer or by a return to the marketplace, its chats stay with the line, with their
contact_handle, and the next owner lists them. When the next owner marks such a chat read, it receives inmessage.readeach of your inbound messages of the chat that iSnap still keeps and that you had not marked read, with its text, the sender’s handle and the names of its files. The events about your earlier messages of the line go to the next owner too. Before you transfer a line or let it return to the marketplace, export what you need from its chats. After you take a line, ignore the chats and the events about messages older than the time the line became yours. Note that time when you get the line: no event announces a transfer. See A chat is never deleted, and Lines that change owner for the rule and for that time.
contact_handle: it is personal data.
Identifiers
An id is a prefix, an underscore and 25 characters from0-9A-Za-z, except the kinds of id that the end of the table lists. Ids are case-sensitive.
A line, message, chat, webhook subscription, delivery, pre-order or hosted macOS session id of another form in a path returns
400 validation_failed. With a line-scoped key, an operation under /v1/lines/{id}/ checks the list first: an id that starts with line_ and is not in the list returns 403 forbidden, before the 400. Send only ids that start with line_: an id of another form returns 403 forbidden, or 500 internal_error when it is not a UUID.
Timestamps
A timestamp in a response is ISO 8601 in UTC, with milliseconds and aZ suffix: 2026-10-08T14:22:57.392Z.
A timestamp in a request is ISO 8601 with a Z suffix. since and until on GET /v1/messages and GET /v1/chats also accept an explicit offset such as +02:00. Pagination gives the rule of each list.
Two values are Unix times in seconds, not ISO 8601: the X-RateLimit-Reset header of a response, and the webhook-timestamp header of a webhook delivery.