Skip to main content
POST /v1/lookup tells whether a handle, a phone number or an email address, can receive iMessage. This page describes the request, the three kinds of answer, how long an answer is kept, which device runs the check, and the limits. A lookup is never required before a send: read this page when your product shows, or decides something on, whether a contact uses iMessage.

The request

The response contains handle in its normalized form: E.164 for a phone number, lower case for an email address. A handle that is neither a valid phone number nor a valid email address returns 400 validation_failed.

The three answers

A call that starts a check waits up to 3 seconds for the device’s answer before it returns 202. probe_id is the id of the check, lkp_ followed by 25 characters. No event announces the result of a check: repeat the request to get it. Each repeat counts against the limits. The SDK resolves lookup.check() the same way on a 200 and on a 202: branch on pending.

How long an answer is kept

iSnap keeps a definite answer, true or false, for 24 hours, and returns it to every caller of iSnap, whatever the account. An answer can therefore be up to 24 hours old, and come from a check that another account started. An unknown result is not kept. It only prevents a new check of that handle for 60 seconds.

Which device checks

A check runs on the device of one of your lines. The device asks Apple whether the handle is registered with iMessage.
  • With from_line_id, the check runs only on that line’s device: when that device cannot run it, the answer is imessage: null unless a definite answer is already kept for the handle, even when another of your lines could run the check. Without it, the check runs on the device of any of your lines that can run checks.
  • The device must be connected, and must support lookups. Rented iMessage lines do. A BYOD line does when lookup_probe is active on GET /v1/lines/{id}/health: see Device features.
  • When none of your lines can run a check, for example when you own only shared lines, which have no device of their own, the answer is imessage: null, unless a definite answer is already kept for the handle.
A line-scoped key can name any line of the account in from_line_id.

Limits

  • Every call that passes validation counts: an answer from the 24-hour store, a 202 and a repeat of a pending check count against every limit that applies to the call. A call refused with 429 lookup_rate_limit_exceeded counts against the limit that refused it and the limits checked before it, in this order: the account limit, the hourly limit of the line, the daily limit of the line. A call refused with 400 or 404 counts against no limit.
  • The two limits per line apply only to calls that give from_line_id.
  • The windows are calendar windows, not rolling ones: they reset at the start of each UTC hour and each UTC day.
  • An isnap_test_ key counts against the same limits as an isnap_live_ key.
Over a limit, the call returns 429 lookup_rate_limit_exceeded, with Retry-After set to the seconds until the next UTC hour or the next UTC day. In the SDK it is a QuotaExceededError, and the SDK does not retry it.

Lookups and sending

  • A lookup is never required before a send, and a send never waits for one.
  • A lookup counts against no sending limit.
  • imessage: true for an email address does not make it a recipient: POST /v1/messages takes a phone number only, and returns 400 bad_request for an email address.
  • The line’s device chooses the service of each message when it sends it: see Services and fallback.

Errors

The refusals of the operation are on its reference page: POST /v1/lookup. The errors that every operation shares are in Errors.

Personal data

The handle you look up is personal data, and so is the answer about it. A definite answer is shared with every caller of iSnap for 24 hours. Look up a handle only when you need the answer. Do not copy handles or answers into logs, tickets or other tools. Refer to a contact by an id of your own.