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
/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
{
"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
{
"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
| Field | Type | Description |
|---|---|---|
number | string | The phone number that was checked |
imessage | boolean | true if the number is registered for iMessage |
sms | boolean | true if the number can receive SMS (almost always true for valid numbers) |
cached | boolean | true if this result came from the 24-hour cache |
checked_at | string | ISO 8601 timestamp of when the check was performed |
cache_expires_at | string | ISO 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:
- First query: senderZ checks the number via the iMessage engine, stores the result, and returns
cached: false. - Subsequent queries within 24 hours: senderZ returns the stored result with
cached: true. No additional detection call is made. - 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:
| Approach | When to Use |
|---|---|
GET /v1/capabilities/:number | You want to make routing decisions before sending — e.g., customizing the message body for iMessage vs. SMS recipients |
channel: "auto" on /v1/messages | You 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
| Status | Code | Description |
|---|---|---|
| 400 | INVALID_PHONE_NUMBER | The phone number is not in valid E.164 format |
| 401 | INVALID_API_KEY | Bad or missing API key |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests |
| 503 | DETECTION_UNAVAILABLE | iMessage detection backend is temporarily unreachable |