A read-only REST API over the same public catalog the website uses: list countries, list temporary numbers, and poll inboxes for verification codes. Useful for automated testing of SMS sign-up flows. There is no self-serve sign-up - email us and we issue you a token.
This API is read-only and access is granted manually. There is no public sign-up page and no published SDK package to install - use any HTTP client with the Bearer token we issue you.
Four steps from zero to your first automated verification code.
Send a note from the contact page describing your use case and roughly how many requests per minute you expect. There is no public registration form.
We issue a token and send it to you once. Store it as a secret in your CI or environment file - it is not retrievable later, and a lost token has to be replaced.
Send Authorization: Bearer {token} with every request. cURL, Guzzle, Axios, Dio, and requests all work - there is nothing to install.
List numbers for a country, choose an active one, trigger the SMS in your app, then poll the messages endpoint until the verification code arrives. Numbers are shared and cannot be reserved.
Need an API token?
Tokens are issued by hand. Email us your use case and expected request rate and we will send one back.
Send the token we issue you in the Authorization header on every request; without it the API returns 401. Keep it server-side - never commit it or ship it in browser or mobile code, because anything shipped to a client can be extracted.
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
All endpoints are versioned under /api/v1. Responses are JSON with standard HTTP status codes.
https://instant-sms.com/api/v1
One envelope for every endpoint, and a fixed pagination allow-list.
Successful responses return
{ "message", "data" }.
Errors on 401, 403, 404, 405, and 429 return
{ "message", "errors" },
so you can branch on one shape. Lists are paginated with a
per_page
allow-list of 15, 25, or 50 - other values are rejected rather than silently clamped.
Message timestamps are ISO-8601. Numbers are identified by their E.164 digits, and the catalog only exposes public numbers - there is no reservation or ownership model, so treat every inbox as shared.
Read-only endpoints for listing numbers and reading public inbox messages.
/api/v1/countries
List all enabled countries with number counts and activity stats. Paginated (per_page 15, 25, or 50).
/api/v1/countries/featured
List enabled countries flagged as featured, in the same shape as the countries list.
/api/v1/countries/{iso}/numbers
List public temporary numbers for a two-letter country code (e.g. us, ca, gb).
/api/v1/numbers/featured
List the curated featured numbers across all countries.
/api/v1/numbers/{number}/messages
List SMS for a number in E.164 digits. Add ?sync=1 to pull from the upstream provider first; omit it for a faster database-only read.
{
"message": "Messages retrieved.",
"data": [
{
"id": 1042,
"service": "Google",
"body": "Your Google verification code is 847291",
"code": "847291",
"received_at": "2026-09-06T14:32:25+00:00"
}
]
}
Copy a snippet and replace YOUR_API_TOKEN with the token we issued you. No SDK required.
# List US numbers
curl -s "https://instant-sms.com/api/v1/countries/us/numbers" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
# Read an inbox, pulling from the upstream provider first
curl -s "https://instant-sms.com/api/v1/numbers/14165550198/messages?sync=1" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
# Same read without the upstream pull (faster, database only)
curl -s "https://instant-sms.com/api/v1/numbers/14165550198/messages" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
const BASE = 'https://instant-sms.com/api/v1';
const headers = {
Authorization: `Bearer ${process.env.INSTANTSMS_API_TOKEN}`,
Accept: 'application/json',
};
const get = async (path) => {
const response = await fetch(`${BASE}${path}`, { headers });
if (! response.ok) throw new Error(`${response.status} ${await response.text()}`);
return response.json();
};
// Pick a Canadian number for your test
const { data: numbers } = await get('/countries/ca/numbers');
const number = numbers.find((n) => n.active);
console.log('Using number:', number.number);
// Trigger the SMS in your app here, then poll for the code
const digits = number.number.replace(/\D/g, '');
let code;
for (let attempt = 0; attempt < 24; attempt++) {
const { data: messages } = await get(`/numbers/${digits}/messages?sync=1`);
code = messages.find((m) => m.code)?.code;
if (code) break;
await new Promise((resolve) => setTimeout(resolve, 5000));
}
console.log('Verification code:', code);
use Illuminate\Support\Facades\Http;
$api = Http::baseUrl('https://instant-sms.com/api/v1')
->withToken(config('services.instantsms.token'))
->acceptJson()
->throw();
// List numbers and pick an active one
$numbers = $api->get('/countries/ca/numbers')->json('data');
$number = collect($numbers)->firstWhere('active', true);
$digits = preg_replace('/\D/', '', $number['number']);
// Trigger the SMS in your app here, then poll for the code
$code = null;
for ($attempt = 0; $attempt < 24; $attempt++) {
$messages = $api->get("/numbers/{$digits}/messages", ['sync' => 1])->json('data');
$code = collect($messages)->firstWhere('code', '!=', null)['code'] ?? null;
if ($code !== null) {
break;
}
sleep(5);
}
// Use $code in your Pest / PHPUnit assertion
A repeatable pattern for E2E and integration tests that depend on SMS verification.
Call GET /countries/{iso}/numbers and pick an active number that matches the region your app expects.
Enter the E.164 number in your sign-up or login flow so the service sends an SMS to the public inbox.
Poll GET /numbers/{slug}/messages?after={cursor} every few seconds. Stop when detected_code is present in the response.
Pass the extracted code back into your app or test assertion to finish the onboarding step automatically.
Public inboxes are visible to anyone. Use the API for QA, staging, and development - not for production user authentication or sensitive account recovery flows.
Yes. Reasonable test volumes are free. Human-paced rate limits apply so one client cannot starve the upstream providers everyone shares.
Email us from the contact page with your use case and expected request rate. There is no public registration page or developer dashboard - tokens are issued by hand and sent to you once.
No. There is no published npm or Composer package. The API is plain JSON over HTTPS with a Bearer token, so any HTTP client works - cURL, Guzzle, Laravel Http, Axios, fetch, Dio, or requests.
Poll the messages endpoint with ?sync=1 so it pulls from the upstream provider before responding. Most codes arrive within 10-30 seconds; retry for up to two minutes in CI before failing the test.
No. It is built for development, QA, and staging workflows. Public temporary numbers are shared inboxes and are not suitable for verifying real users.
401 means the Bearer token is missing, malformed, or expired. 429 means you hit the rate limit - back off and retry with exponential delay rather than tightening the polling loop.