iMessage Detection

Check if a phone number supports iMessage before sending with the Capabilities API.

The Capabilities API lets you check whether a phone number supports iMessage before you send a message. This is useful when you want to customize your messaging logic based on the recipient’s capabilities — for example, sending rich iMessage content to Apple users and a plain SMS fallback to everyone else.

How Detection Works

When you query a phone number’s capabilities, senderZ checks the number against Apple’s iMessage registration system through the iMessage engine on the dedicated Apple hardware. The result tells you whether the number is registered for iMessage.

Results are cached for 24 hours. Subsequent queries for the same number within that window return the cached result instantly without hitting the detection backend.


Check a Number

GET /v1/capabilities/:number

Check iMessage capability for a phone number.

number string Required

Phone number in E.164 format (e.g. +15551234567). Passed as a URL path parameter.

curl https://api.senderz.com/v1/capabilities/+15551234567 \
  -H "Authorization: Bearer sz_live_YOUR_KEY"
const number = '+15551234567'
const res = await fetch(
  `https://api.senderz.com/v1/capabilities/${encodeURIComponent(number)}`,
  {
    headers: {
      'Authorization': 'Bearer sz_live_YOUR_KEY',
    },
  }
)
const data = await res.json()

if (data.data.imessage) {
  // Send rich iMessage content
} else {
  // Fall back to SMS
}

Response: iMessage Available

200 OK
{
  "data": {
    "number": "+15551234567",
    "imessage": true,
    "sms": true,
    "cached": false,
    "checked_at": "2026-04-15T10:30:00Z",
    "cache_expires_at": "2026-04-16T10:30:00Z"
  }
}

Response: SMS Only

200 OK
{
  "data": {
    "number": "+15559876543",
    "imessage": false,
    "sms": true,
    "cached": false,
    "checked_at": "2026-04-15T10:31:00Z",
    "cache_expires_at": "2026-04-16T10:31:00Z"
  }
}

Response Fields

FieldTypeDescription
numberstringThe phone number that was checked
imessagebooleantrue if the number is registered for iMessage
smsbooleantrue if the number can receive SMS (almost always true for valid numbers)
cachedbooleantrue if this result came from the 24-hour cache
checked_atstringISO 8601 timestamp of when the check was performed
cache_expires_atstringISO 8601 timestamp of when the cached result expires

Caching Behavior

Detection results are stored in the recipient_capabilities table and cached for 24 hours. Here is how the cache lifecycle works:

  1. First query: senderZ checks the number via the iMessage engine, stores the result, and returns cached: false.
  2. Subsequent queries within 24 hours: senderZ returns the stored result with cached: true. No additional detection call is made.
  3. After 24 hours: The cache entry expires. The next query performs a fresh check.

The 24-hour window balances accuracy against performance. A user who switches from Android to iPhone (or vice versa) will be detected within a day.

Relationship to channel: “auto”

When you send a message with channel: "auto", senderZ runs the same iMessage detection internally. The key difference:

ApproachWhen to Use
GET /v1/capabilities/:numberYou want to make routing decisions before sending — e.g., customizing the message body for iMessage vs. SMS recipients
channel: "auto" on /v1/messagesYou want senderZ to handle routing automatically at send time

Both approaches use the same detection mechanism and the same 24-hour cache. If you call the Capabilities API and then send with channel: "auto", the send operation will use the cached result from your earlier check.

Batch Checking

There is no batch endpoint for capability checks. If you need to check multiple numbers, call the endpoint for each number individually. Cached responses return instantly, so the main latency cost is only for the first check of each number.

For large lists, consider using campaigns with channel: "auto" instead. The campaign system performs iMessage detection internally for each recipient as part of the delivery pipeline.

Error Responses

StatusCodeDescription
400INVALID_PHONE_NUMBERThe phone number is not in valid E.164 format
401INVALID_API_KEYBad or missing API key
429RATE_LIMIT_EXCEEDEDToo many requests
503DETECTION_UNAVAILABLEiMessage detection backend is temporarily unreachable