Skip to main content
A request carries its credential in the Authorization header. This page describes the three kinds of key, the order in which iSnap checks a request, the response to each refused request, and two helpers that send the header and apply the retry rules.
The word Bearer is case-insensitive. Every operation is served at https://api.isnap.ai, whatever the key. A plain HTTP request is not served: it returns 301 to the HTTPS URL. Call the API from a server. iSnap does not grant cross-origin browser access to other websites, and a key in browser code is public.

API keys

An API key is isnap_live_ or isnap_test_ followed by 64 lowercase hexadecimal characters: 75 characters in all. You create, list and revoke API keys in the iSnap dashboard. The full key is shown once, when you create it. iSnap cannot show it again: store it in a secret manager, and read it from the environment as ISNAP_API_KEY.

Test keys

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 request sent with an isnap_test_ account key sends real messages to real recipients, causes real webhook deliveries, counts against the same limits and is billed the same way. There is no simulated send.
The prefix follows a label chosen when the key is created: live, the default, or test. The label changes nothing else. Use it to tell your own keys apart. To test an integration, send to a phone number of your own.

Trial keys

A trial key is the key of one trial. It is isnap_test_ followed by 43 URL-safe base64 characters: 54 characters in all. Its length tells it apart from an API key. Trials explains how you obtain it. Read it from the environment as ISNAP_TRIAL_KEY. A trial key is accepted while its trial is active or dormant, and by three operations only: Every other operation that needs a credential returns 401 unauthorized to a trial key. The operations without a credential ignore it.

Line-scoped keys

A line-scoped key is an API key created with a list of lines. On the operations of Where the list applies, it is limited to those lines. A key with no list reaches the whole account. A line id that is not one of your account’s lines grants nothing.

Where the list applies

Inside its list, a line-scoped key can do everything an unscoped key can, terminating and transferring a line included.

Where the list does not apply

A line-scoped key is not a boundary for the operations of Where the list does not apply: on them it acts on the whole account. Do not use a line-scoped key to separate one system or one team from the rest of your account.

How a request is checked

iSnap checks a request in this order. The first check that fails decides the response.
1

Request rate

A caller over the request-rate limit gets 429 rate_limit_exceeded. The limit is counted per network address, before the key is read: see Rate limits. The message-operations limit of POST and GET /v1/messages is counted between step 2 and step 3, also before the key is read.
2

Authorization header on a write

On POST, PATCH, PUT and DELETE, a request whose Authorization header is absent, or does not start with Bearer isnap_live_ or Bearer isnap_test_, gets 403 forbidden, not 401. A request that carries X-Requested-With: XMLHttpRequest skips this check and gets 401 instead. Paths under /v1/webhooks are the exception: they return 401 unauthorized.
3

Credential

A missing, malformed, unknown or revoked credential gets 401 unauthorized.
4

Line scope and idempotency key

On an operation under /v1/lines/{id}/, a line-scoped key whose list does not hold that line gets 403 forbidden. On POST /v1/lines/assign, POST /v1/lines/shared and POST /v1/macos-sessions/rent, the Idempotency-Key header is read at this step: see Idempotency.
5

Query, path, headers and body

The query is validated first, then the path, then the headers, then the body. The first invalid part gets 400 validation_failed, and error.issues lists every problem of that part.
6

The operation's own rules

The operation applies its rules and returns its own codes, such as 404 not_found or 409 conflict.
Three consequences:
  • A 429 can come before a 401: a refused key still counts against the request-rate limit.
  • A wrong key with an invalid body gets 401, not 400.
  • An invalid query hides an invalid body: fix the query, then resend the request to see the next problem.

Refusals

Every refusal uses the error format. Branch on error.code. error.message is text for a person and can change. The body of a 401:
A 403 has the same shape, with "status": 403 and "code": "forbidden".

Operations without a credential

Seven operations need no credential. They count against the request-rate limit like any other request.

Make your first call

To make a first call, follow the Quickstart.

Helpers

Put the header and the retry rules in one place. These two helpers do it, and the samples of Pagination and Idempotency import them. Each sends the Authorization header and applies the retry rules of Errors and rate limits:
  • Retry a 429 after Retry-After seconds. Retry a 500 or a 503 up to 2 times, with exponential backoff. Do not retry any other 4xx: fix the request.
  • Retry a write only on an operation that honors Idempotency-Key, with the key of the first attempt.
What the helpers do, and what they leave to you: The five codes of QuotaExceededError, which the SDK does not retry, are new_contact_quota_exceeded, known_contact_quota_exceeded, total_message_quota_exceeded, queue_full and lookup_rate_limit_exceeded. The SDK pages describe its retries and errors in full: see SDK errors. Never retry GET /v1/trial/status automatically: the first read within 1 hour after pairing returns the trial key, and no later read returns it. Call it with { maxRetries: 0 } in TypeScript, and with requests directly in Python. isnap_request reads the standard response envelope. Call GET /v1/health without it: that operation returns its body without the envelope. To call with a trial key, pass it to the helper: isnap_request("GET", "/v1/trial/activity", api_key=os.environ["ISNAP_TRIAL_KEY"]). In TypeScript, create a second client with the trial key: a client holds one credential.

Troubleshooting

If no row explains the response, report it. Write to support@isnap.ai with the trace_id and request_id of the response.

If a key leaks

Anyone who holds an API key acts on your account, your lines and your billing. Treat a key that appeared in a log, a ticket, a repository or a client-side bundle as leaked.
  1. Create another key in the iSnap dashboard, and deploy it. The last-use date of the new key in the dashboard moves when your systems use it.
  2. Revoke the leaked key in the dashboard. The revocation takes effect on the next request and cannot be undone.
To disable a leaked trial key, revoke its trial with POST /v1/trial/{trial_id}/revoke: the key then returns 401 unauthorized. Never log request headers: the Authorization header holds the key.