SMS Testing API
Provision real test phone numbers, capture inbound SMS, and extract OTP codes automatically. Perfect for CI pipelines and automated SMS verification testing.
Overview
The SMS Testing API lets you provision real US phone numbers that capture all incoming SMS. Send any text message to the provisioned number — from your app, your SMS provider, or your CI pipeline — and retrieve the full message content with auto-extracted OTP codes via API.
1-48h
Configurable message expiry
3
Active inboxes per user
50
Messages per inbox
1
API call per inbox created
Paid plans only
SMS Testing requires a Business or Enterprise plan, or purchased credits. Each inbox creation costs 1 API call. Listing, reading, and deleting are free.
Quick Start
# 1. Provision a test phone number
curl -X POST "https://api.mailchk.io/v1/test-sms-inboxes" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"label": "OTP flow", "expires_in": "24h"}'
# Response:
# {
# "id": "a1b2c3d4-...",
# "phone_number": "+12025557842",
# "label": "OTP flow",
# "expires_in": "24h",
# "message_count": 0,
# "created_at": "2026-03-14T10:00:00.000Z"
# }
# 2. Send an SMS to the test number from your app
# 3. Poll for messages
curl "https://api.mailchk.io/v1/test-sms-inboxes/a1b2c3d4-.../messages" \
-H "X-API-Key: YOUR_API_KEY"
# 4. Inspect a captured message (with auto-extracted OTP codes)
curl "https://api.mailchk.io/v1/test-sms-inboxes/a1b2c3d4-.../messages/MSG_ID" \
-H "X-API-Key: YOUR_API_KEY"Base URL
https://api.mailchk.ioAuthenticate with your API key in the X-API-Key header. See the authentication guide for details.
Endpoints
/v1/test-sms-inboxesCosts 1 API callProvision a test phone number and create a new SMS inbox. Returns a real US phone number that captures all incoming SMS. Requires a label and optional expiry duration.
Auth: API Key or JWT
Request Body
{
"label": "OTP flow", // required, max 100 chars
"expires_in": "24h" // optional: "1h", "6h", "12h", "24h", "48h"
}Response
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"phone_number": "+12025557842",
"label": "OTP flow",
"expires_in": "24h",
"message_count": 0,
"created_at": "2026-03-14T10:00:00.000Z"
}/v1/test-sms-inboxesList all SMS test inboxes for the authenticated user.
Auth: API Key or JWT
Response
{
"inboxes": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"phone_number": "+12025557842",
"label": "OTP flow",
"expires_in": "24h",
"message_count": 3,
"created_at": "2026-03-14T10:00:00.000Z"
}
]
}/v1/test-sms-inboxes/:idDelete an SMS test inbox, release the phone number back to the carrier, and remove all stored messages.
Auth: API Key or JWT
Response
{
"success": true
}/v1/test-sms-inboxes/:id/messagesList messages received by an SMS test inbox. Returns metadata and body preview (no full content or extracted codes).
Auth: API Key or JWT
Response
{
"messages": [
{
"id": "msg-1234-5678-abcd",
"from_number": "+14155551234",
"to_number": "+12025557842",
"body_preview": "Your verification code is 384729...",
"segments": 1,
"media_urls": [],
"received_at": "2026-03-14T10:05:30.000Z"
}
]
}/v1/test-sms-inboxes/:id/messages/:msgIdGet the full content of a captured SMS — body, auto-extracted OTP codes, and link validation results.
Auth: API Key or JWT
Response
{
"id": "msg-1234-5678-abcd",
"inbox_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"from_number": "+14155551234",
"to_number": "+12025557842",
"body": "Your verification code is 384729. It expires in 10 minutes.",
"segments": 1,
"media_urls": [],
"codes": [
{
"value": "384729",
"type": "otp",
"context": "Your verification code is 384729"
}
],
"links": [
{
"url": "https://example.com/verify?token=abc",
"text": "https://example.com/verify?token=abc",
"status": 200,
"ok": true,
"error": null
}
],
"received_at": "2026-03-14T10:05:30.000Z"
}Message Detail Fields
Fields returned by GET /v1/test-sms-inboxes/:id/messages/:msgId:
| Field | Type | Description |
|---|---|---|
| id | string | Unique message identifier |
| inbox_id | string | The SMS test inbox that received this message |
| from_number | string | Sender phone number in E.164 format |
| to_number | string | Recipient phone number (the test inbox number) |
| body | string | Full SMS message body text |
| segments | number | Number of SMS segments (long messages are split into multiple segments) |
| media_urls | array | MMS media attachment URLs (empty for SMS-only messages) |
| codes | array | Auto-extracted OTP/verification codes with value, type, and context |
| links | array | All URLs in the message with HTTP status check results |
| received_at | string | When the SMS was received (ISO 8601) |
Error Codes
Bad Request
Maximum active inboxes reached (3 per user), missing label, or invalid expires_in value
Authentication Required
Missing or invalid API key / JWT token. Code: AUTH_REQUIRED
Forbidden
SMS Testing requires a Business or Enterprise plan, or purchased credits
Not Found
Inbox or message not found, or inbox belongs to a different user
Usage Limit Exceeded
Subscription limit reached and no credits remaining. Code: USAGE_LIMIT_EXCEEDED
Bad Gateway
Failed to provision a phone number from the carrier. Try again later.
CI/CD Integration
Test your SMS flows in CI. Provision a test number before your test suite runs, trigger SMS through your app, then assert on the captured content and extracted OTP codes.
# GitHub Actions example — test your OTP SMS flow
name: SMS Integration Tests
on: [push]
jobs:
test-sms:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Provision test phone number
id: inbox
run: |
RESPONSE=$(curl -s -X POST "https://api.mailchk.io/v1/test-sms-inboxes" \
-H "X-API-Key: ${{ secrets.MAILCHK_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"label": "CI run #${{ github.run_number }}", "expires_in": "1h"}')
echo "INBOX_ID=$(echo $RESPONSE | jq -r '.id')" >> $GITHUB_OUTPUT
echo "PHONE=$(echo $RESPONSE | jq -r '.phone_number')" >> $GITHUB_OUTPUT
- name: Trigger OTP send
run: |
curl -X POST "http://localhost:3000/api/send-otp" \
-H "Content-Type: application/json" \
-d '{"phone": "${{ steps.inbox.outputs.PHONE }}"}'
- name: Wait for SMS & extract OTP
run: |
sleep 10
MESSAGES=$(curl -s "https://api.mailchk.io/v1/test-sms-inboxes/${{ steps.inbox.outputs.INBOX_ID }}/messages" \
-H "X-API-Key: ${{ secrets.MAILCHK_API_KEY }}")
COUNT=$(echo $MESSAGES | jq '.messages | length')
if [ "$COUNT" -eq "0" ]; then
echo "No SMS received!"
exit 1
fi
MSG_ID=$(echo $MESSAGES | jq -r '.messages[0].id')
DETAIL=$(curl -s "https://api.mailchk.io/v1/test-sms-inboxes/${{ steps.inbox.outputs.INBOX_ID }}/messages/$MSG_ID" \
-H "X-API-Key: ${{ secrets.MAILCHK_API_KEY }}")
OTP=$(echo $DETAIL | jq -r '.codes[0].value')
echo "OTP extracted: $OTP"
- name: Cleanup
if: always()
run: |
curl -s -X DELETE "https://api.mailchk.io/v1/test-sms-inboxes/${{ steps.inbox.outputs.INBOX_ID }}" \
-H "X-API-Key: ${{ secrets.MAILCHK_API_KEY }}"OTP & 2FA Verification
Provision a number, trigger OTP send, extract the code automatically, and verify the login flow end-to-end.
SMS Notifications
Assert that order confirmations, appointment reminders, and shipping alerts arrive with correct content.
Marketing SMS
Test promotional SMS campaigns. Verify links work, content is correct, and opt-out instructions are present.
Ready to Start Testing?
Provision your first test phone number in seconds. Use the dashboard or integrate via API.