Skip to main content
A line is what sends and receives messages. This page lists the ways to get one and who can use each, and describes the operations that take a line from the marketplace or create a shared line. Read it before you write the code that adds a line to your account.

Ways to get a line

The operations that acquire a line take no payment. Two other operations can charge an account: POST /v1/lines/{id}/transfer-ownership charges a direct account that receives an active rented line, and POST /v1/pre-orders/{id}/confirm starts the monthly billing of the line that a direct account ordered, whose first month the account pays in the dashboard. iSnap grants the status of wholesale partner, and no field of any response says whether your account has it. An account without it receives 402 checkout_required from activate and assign, and 402 payment_required from POST /v1/lines/shared. To ask for the status, write to support@isnap.ai. Three other ways have their own page:
  • Pre-orders: order a rented line and state the area codes you prefer.
  • BYOD lines: pair your own Mac and iPhone, or your own Android phone. The line appears, already active, when the device completes pairing.
  • Trials: let a prospect exchange messages with an iSnap line from their own phone.
An isnap_test_ account key is not a separate test environment: it acts on the same account, lines and billing as an isnap_live_ key. A line you get with a test key is a real line, billed like any other. See Test keys.

The marketplace

GET /v1/lines lists the lines that can be acquired now. It needs no credential and ignores one: phone numbers are masked for every caller.
  • What is listed. Only lines whose status is available, that are fully operational, and whose Apple ID is not flagged. A line can leave the list and come back without being acquired. A line that is not in the list cannot be acquired now: read the list again before each reservation.
  • Masked numbers. A North American number reads +1 (415) ***-**23: the area code and the last two digits stay visible. Any other number keeps its country calling code and its last two digits, with asterisks in between. A number that cannot be parsed reads "".
  • Full line objects. Each listed line carries every field of the line object, metadata included. See Metadata at acquisition.
The filters combine. Each one is optional. The list is paged by page number, not by the cursors of the other list operations. page starts at 1 and defaults to 1. limit is 1 to 100 and defaults to 20. The response is { lines, total, page, limit }: lines are ordered by area_code, then by phone_number, and total is the number of lines that match the filters.

Reservations

POST /v1/lines/{id}/reserve reserves an available line for your account for 15 minutes. The response is the line with status: reserved, the full phone number, and expires_at set to the end of the 15 minutes. Any account can reserve a line, and the call checks no payment method. A reserved line is not billed and cannot send. What you do next depends on your account: The rules of a reservation:
  • reserve does not extend a reservation: reserving a line that you have already reserved returns 409 conflict.
  • The API does not limit the number of lines that one account has reserved at the same time.
  • reserve returns 409 whenever the line cannot be taken. The code is conflict when the line is not available or does not exist. It is a code that starts with line_, such as line_apple_id_flagged, when the line is available but cannot be acquired now. The set of line_ codes is open: treat any 409 as “choose another line”, except after a request whose response you did not receive (see Retries). reserve never returns 404.
  • After expires_at, the line returns to available with no owner, and activate returns 409 line_not_reserved. No event is sent.
  • expires_at has a meaning only while status is reserved. Do not read it on a line in another status.
To give a reserved line back before it expires, call POST /v1/lines/{id}/release. The line returns to available immediately and has no owner. The call sends no event. It returns 404 not_found for any line that you have not reserved, an active line included: to end a line that you use, see Ending a line. The release of a line whose payment was started in the dashboard follows the rules of A line paid in the dashboard.

A line paid in the dashboard

A direct account buys a marketplace line in the iSnap dashboard, by card: it reserves the line and pays for it there. Until iSnap has recorded the payment, the line is reserved for the account, and the API shows it as any other reservation, with three differences:
  • Once the payment has started, expires_at is 24 hours after the start of the payment.
  • The line becomes active once iSnap has recorded the successful payment, with the id of its per-line subscription in stripe_subscription_id. The API does not bound the delay between the payment and the activation. A payment that iSnap records after the reservation has ended activates no line: its billing ends, and iSnap refunds the payment to your account. No event announces the activation: read the line with GET /v1/lines/{id}.
  • When the payment has not succeeded 23 hours after it started, the line returns to available with no owner.
A release of such a line depends on its payment. A payment is submitted once the card payment is being processed. A payment that waits for the cardholder’s authentication is not submitted. A release that waits 10 seconds for another payment or release request of your account returns 409 purchase_in_progress: resend it. When iSnap cannot check the payments of the line, the release returns 500 internal_error and releases nothing. A release changes no other billing.

Activation

POST /v1/lines/{id}/activate turns a line that you reserved, within its 15 minutes, into an active line. Wholesale partners only: any other account receives 402 checkout_required. A direct account buys a line in the iSnap dashboard: see A line paid in the dashboard. The activated line has no per-line subscription: it is billed on the monthly invoice of the wholesale partner. The response has expires_at: null and anniversary_at set. The body is optional: When the line is not reserved by your account within the 15 minutes, activate returns 409 line_not_reserved: the reservation expired or was released, the line was never reserved, or the id is unknown. When the reserved line can no longer be acquired, activate returns 400 with one of the line_ codes of reserve: release the line and choose another one.

Assignment

POST /v1/lines/assign makes one available line yours and activates it, in one call. Wholesale partners only: any other account receives 402 checkout_required once the body passes validation, before any line is looked at. The line comes back active, with no per-line subscription. When several lines match, the API does not specify which one it chooses. When none matches, it returns 409 no_matching_line. With as_test_line: true, the line is assigned first and converted second. When the conversion alone fails, the call returns the error and the line stays assigned to you as a rented line. Before you retry a failed call that carried as_test_line, read GET /v1/lines/my: if the line is there, convert it with POST /v1/lines/{id}/convert-to-test and do not assign again. Always send an Idempotency-Key with this call: see Retries.

Shared lines

A shared line has no hardware and no number of its own. Each contact is served by a number that iSnap binds to them: the first message to a contact creates the binding, and later messages to that contact use the same number. The binding ends when no message was exchanged with the contact for 90 days, a setting of iSnap, and the API then sends binding.released. For what a send from a shared line returns, see Sending messages. POST /v1/lines/shared creates one shared line per call and returns 201 with the line, already active. Wholesale partners only: any other account receives 402 payment_required.
  • The body is optional, and metadata is its only field.
  • The new line has shared: true, phone_number: "", capabilities: ["imessage"], inbound_only: false and stripe_subscription_id: null.
  • The API does not limit the number of shared lines that an account creates. Every call creates one more billable line: always send an Idempotency-Key, as described in Retries.
  • GET /v1/lines/{id} returns 404 not_found for a shared line, even to its owner. Read your shared lines with GET /v1/lines/my.

Retries

POST /v1/lines/assign and POST /v1/lines/shared honor Idempotency-Key. Without a key, every retry takes or creates one more billable line: always send one, and reuse it only to retry the same request. The API remembers the key for 24 hours: after that, the same request with the same key takes or creates another line. The rules are in Lines and hosted macOS sessions. reserve, activate and release ignore the header. When the response to one of them is lost, do not resend the call blindly: read GET /v1/lines/my, which lists a line that you have reserved with status: reserved and a line that you activated with status: active. By default, the SDK sends an Idempotency-Key of its own with every write, and reuses it only on the automatic retries of that one call. Two calls to lines.assign get two keys, and can take two lines. To retry a call yourself, pass the key of the first attempt in idempotencyKey, as the samples on this page do.

Metadata at acquisition

metadata is an object of your own keys that stays on the line: see Metadata for its limits and its reserved keys. Each way to get a line treats it differently: A line that returns to the marketplace keeps its metadata: a release, an expired reservation and the end of a per-line subscription do not clear it. A line that you get through reserve can therefore carry keys that an earlier owner left. After you get a line this way, read its metadata and remove the keys you do not know with PATCH /v1/lines/{id}. A line from the marketplace also keeps its chats. You list the chats of its earlier owners, and you can receive events about their messages. Ignore the chats and the events about messages from before you got the line: see A chat is never deleted.
Line metadata is readable by anyone who holds the line id, and it stays on a line that returns to the marketplace, where GET /v1/lines lists it, and filters lines by it, without a credential. Never put personal data or secrets in line metadata. Refer to a contact, or to an account in your own system, by an id of your own.

Line-scoped keys

A line-scoped key cannot get a new line:
  • POST /v1/lines/assign and POST /v1/lines/shared return 403 forbidden to every line-scoped key.
  • reserve, activate and release return 403 forbidden for any line that is not in the list of the key.
Use a key with no list of lines to get a line.

Events

None of the operations on this page sends an event. No event announces a reservation, its expiry, a release, an activation, or the creation of a shared line. See What events do not announce. To know the state of a line, read it: GET /v1/lines/my returns your active and reserved lines, and GET /v1/lines/{id} returns one rented or BYOD line in any status.

Next steps