Check RCS capability
Before firing a broadcast or a one-off send, ask the gateway which of your recipients are actually RCS-capable. This lets you:
- Save money, never spend
rcs_per_msg_priceon a number that RCS can't deliver to. - Route intelligently, send the unreachable slice down another channel while sending RCS to the rest.
- Segment your list, build "RCS-ready" audiences by pre-checking your CRM export.
Endpoint
POST /api/v1/public/rcs/check-capability
Authorization: Bearer <api_key>
Content-Type: application/json
X-Bot-Id: <bot_uuid> ← multi-bot accounts onlyPicking a bot (multi-bot accounts)
Number checks work only with an active bot that supports them. Not
every bot does; this endpoint refuses the others with
400 unsupported_provider_for_public_api.
If your account has more than one such bot, reachability depends on which bot's carriers you're checking against, bot A may be launched on Airtel but not Vi, bot B may be launched on both. You tell the endpoint which bot to check via one of two inputs (the header wins when both are set):
Without a bot, the endpoint uses your default bot when it supports number checks, and otherwise your first active bot that does.
X-Bot-Id is allowed on cross-origin requests, so a browser app can
send it too.
Errors specific to the bot picker:
Prerequisites
- RCS must be enabled on your account (an admin has provisioned an
RCS agent + key). If not, the endpoint returns
403withcode: "rcs_not_active". - An active bot that supports number checks. See Picking a bot.
- The same Basic-auth API key, IP allowlist and per-key rate limit as
every other
/public/*endpoint.
Request, single number
{
"phone": "+919876543210"
}Request, bulk (up to 10,000)
{
"phones": [
"+919876543210",
"+918765432109",
"+917654321098"
]
}Bulk sizing: any number of phones from 1 up to 10,000 per
request. Above 10,000 the request is rejected with 400. The
platform automatically picks the fastest lookup path based on how
many phones you send:
The API always returns the same response shape (reachable[] +
unreachable[]) whichever path fires.
If both phone and phones are set, they're merged and deduped.
Response
{
"success": true,
"total": 3,
"reachable_count": 2,
"reachable": [
"+919876543210",
"+917654321098"
],
"unreachable": [
"+918765432109"
]
}Order is preserved from the request (after dedup), so you can align input and output positionally if you're carrying per-recipient metadata alongside the phones.
Error responses
Latency
- Single-number lookups return in ~200-500ms.
- Bulk lookups (up to 10,000) return in a single response after every batch resolves; expect ~2-6s wall-clock for a full 10k call.
Idempotency + freshness
Reachability is a snapshot in time, a user who switches phones or disables RCS on their handset today may be unreachable tomorrow.
Recommendation:
- Ad-hoc sends (order shipped, OTP, support reply): skip the
pre-check, the direct
/rcs/messages/sendpath already handles unreachable recipients gracefully (returnssuccess: falseper number with a provider reason) and doesn't debit the wallet. - Bulk broadcasts: pre-check nightly. Cache the result on your side for 24h. If a bulk broadcast is spread over a day, re-check before each batch fire.
- Contact-list segmentation: re-check monthly is enough for most audiences.
Example, curl (bulk)
curl -X POST https://api.splashifypro.com/api/v1/public/rcs/check-capability \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-H "Content-Type: application/json" \
-H "X-Bot-Id: 9c1b7f4e-2a11-4c8e-8e0e-3f5d1b2c9e01" \
-d '{
"phones": [
"+919876543210",
"+918765432109",
"+917654321098"
]
}'Example, Node.js
const res = await fetch(
"https://api.splashifypro.com/api/v1/public/rcs/check-capability",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.SPLASHIFY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ phones: crmExport.map((c) => c.phone) }),
}
);
const { reachable, unreachable } = await res.json();
// Route the reachable slice to RCS...
await sendRCSBroadcast({ audience: reachable });
// ...and send the rest down whichever channel you fall back to.
await sendFallbackBroadcast({ audience: unreachable });Example, Python
import os, requests
resp = requests.post(
"https://api.splashifypro.com/api/v1/public/rcs/check-capability",
headers={"Authorization": f"Bearer {os.environ['SPLASHIFY_API_KEY']}"},
json={"phones": [c["phone"] for c in crm_export]},
timeout=30,
)
resp.raise_for_status()
data = resp.json()
reachable = data["reachable"]
unreachable = data["unreachable"]Fail-open guarantee
If the upstream RCS network is momentarily unavailable (network
blip, throttled), the /rcs/messages/send endpoint
does NOT block on a capability pre-check. It attempts the send
anyway. This endpoint is purely a cost-optimization tool; your
critical send paths keep working even when the capability service
is degraded.
Handling very large lists (10 lakh+)
The public API caps at 10,000 phones per HTTP call. For a 10-lakh (1M) audit, batch client-side into 100 calls of 10k each:
import os, requests
from itertools import islice
def chunk(iterable, size):
it = iter(iterable)
while batch := list(islice(it, size)):
yield batch
all_phones = [c["phone"] for c in crm_export] # 1,000,000 entries
reachable, unreachable = [], []
for batch in chunk(all_phones, 10000):
resp = requests.post(
"https://api.splashifypro.com/api/v1/public/rcs/check-capability",
headers={"Authorization": f"Bearer {os.environ['SPLASHIFY_API_KEY']}"},
json={"phones": batch},
timeout=60,
)
resp.raise_for_status()
data = resp.json()
reachable.extend(data["reachable"])
unreachable.extend(data["unreachable"])
print(f"{len(reachable):,} reachable of {len(all_phones):,}")Each 10k call runs in 2-6 seconds, so a full 100-batch sweep of 1M phones completes in about 5-10 minutes. If you're checking a stored list that already lives on our platform, use the contact-list async check below instead. It runs server-side without your process having to stay online.
Server-side check for stored contact lists
If your recipients already live in one of your platform contact lists, the panel exposes an ASYNC check that runs the full list server-side regardless of size. Kick off with:
POST /api/v1/rcs/contact-lists/{list_id}/check-reachability
X-Bot-Id: <bot_uuid> ← multi-bot accounts onlyThe bot comes from the X-Bot-Id header, then the ?bot_id= query,
then {"bot_id": "…"} in the body. With none of them, your first active
bot that supports number checks is used. Only such a bot can run the check. A bot
that does not support them gets 400 with code: "bot_cannot_check",
and a call with no bot on an account that has none gets 400 with
code: "no_check_bot". See
Contact lists.
The bot the check runs against is stamped on the list row as
last_reachability_check_bot_id so you (and your admins) can see
"reachable count = 850 checked via Store Bot" instead of a
context-free number.
Response is 202 Accepted with the resolved bot info:
{
"success": true,
"status": "started",
"total": 1000000,
"started_at": "2026-08-07T12:04:00Z",
"bot_id": "9c1b7f4e-2a11-4c8e-8e0e-3f5d1b2c9e01",
"bot_name": "Store Bot",
"incremental": false,
"resumed": false,
"keeps_can_get": false
}- The first check of a list checks every number.
totalis the number of members on the list. keeps_can_getistruewhen the list already had answers that count. The check then keeps every reachable answer and checks only the numbers found unreachable and the numbers with no answer that counts. This is the same with any bot, and with or without?force=true. There is no way to check a reachable answer again.incrementalistruewhen only numbers without an answer are checked: the last check used the same bot, finished cleanly, and the call has no?force=true.?force=trueturns that off; it no longer checks every number.resumedistruewhen the last check with this bot stopped part way. The new check keeps the answers it saved and checks the rest.- A check with a different bot no longer checks every number: it follows
the same rule as
keeps_can_get. - While a check runs, another call gets
409withcode: "check_in_progress"and, when known, the currentprogress. - A check never blocks a broadcast. A broadcast sent while one runs uses the answers saved so far, and the answers from the check before it. On a list with no answers before the check, its answers count once it finishes: until then every number reads as not checked.
Poll the list via GET /api/v1/rcs/contact-lists (or read the list
detail) to observe progress:
{
"list_id": "…",
"count": 1000000,
"reachability_check_started_at": "2026-08-07T12:04:00Z",
"reachability_check_progress": 420000,
"reachability_check_phase": "probing",
"reachability_check_total": 1000000,
"last_reachability_check_at": null,
"reachable_count": null,
"last_reachability_check_bot_id": "9c1b7f4e-2a11-4c8e-8e0e-3f5d1b2c9e01",
"last_reachability_check_bot_name": "Store Bot"
}reachability_check_phase says where the check is:
When last_reachability_check_at >= reachability_check_started_at
the job is complete and reachable_count reflects the final tally.
Then use GET /api/v1/rcs/contact-lists/{list_id}/reachable.csv to
download the reachable subset.
The answers count for broadcasts from every bot on your account, not
only the bot that ran the check. A broadcast from any of them with
audience: "rcs" (the default) skips the numbers the check found
unreachable; not_rcs sends only to those, and all to every number.
To see what a send from a given bot would reach, call the audience
endpoint.
A list whose latest check was made with a bot that does not support
number checks reads as never checked: the list row carries none of the
fields above, and its members carry no reachable answer. The saved
answers are not used by any broadcast.