Receive SMS in your own software
Your MirageTEL numbers receive texts — sign-in codes, booking alerts, replies from customers. Read them with one API call, or have each one pushed to your server, signed, the moment it lands.
Ask
GET /messages?after=… with a key. Texts come oldest first; keep nextAfter and you read every text exactly once.
Be told
Add a webhook: each text is POSTed to your https address the moment it arrives, signed with HMAC-SHA256, retried for 24 hours.
Only what it needs
A key reads, nothing else. Narrow it to some numbers and some senders — the right shape for sign-in codes. Revoke in one click.
One call
curl -H "X-Api-Key: $MIRAGETEL_SMS_KEY" \ "https://miragetel.com/api/v1/sms/messages?after=<the last id you have>"
{
"data": [
{
"id": "0b6f1c2e-5a8d-4c1e-9f3a-2d7b8e6a1c40",
"number": "+13075550100",
"from": "22000",
"body": "123456 is your verification code",
"bodyRetained": true,
"receivedAt": "2026-10-02T12:41:51.009Z"
}
],
"hasMore": false,
"nextAfter": "0b6f1c2e-5a8d-4c1e-9f3a-2d7b8e6a1c40"
}body is null with bodyRetained: false once the words have been removed — never an empty string that looks like an empty text.
Reference
Base URL https://miragetel.com/api/v1/sms · header X-Api-Key: mts_…
| Endpoint | Answers |
|---|---|
GET /messages | Texts received, oldest first: {data, hasMore, nextAfter} |
GET /messages/{id} | One text: {data} |
GET /numbers | The numbers this key reads |
| Parameter | Meaning |
|---|---|
after | A message id (preferred) or an ISO 8601 time. Texts strictly after it, oldest first. Without it: the last 24 hours. |
number | One of your numbers, E.164 — %2B13075550100. |
from | One sender. Spaces, dots, dashes, + and capitals do not matter. |
limit | 1–200, default 50. |
| HTTP | Error |
|---|---|
400 | INVALID_AFTER · INVALID_NUMBER · INVALID_SENDER |
401 | API_KEY_REQUIRED · API_KEY_INVALID — the same answer for a revoked key and one that never existed |
404 | CURSOR_NOT_FOUND · MESSAGE_NOT_FOUND — another account answers the same |
429 | RATE_LIMITED — more than 120 requests in a minute on one key |
Waiting for a sign-in code? Note the time before you ask for the code, then ask every 3–5 seconds with after=<that time> and from=<the sender>, and stop after about two minutes.
Webhooks
POST /your/endpoint
Content-Type: application/json
X-MirageTel-Event: sms.received
X-MirageTel-Delivery: 7c1d9e…
X-MirageTel-Timestamp: 1790955722
X-MirageTel-Signature: 3f9a…
{"event":"sms.received","deliveryId":"7c1d9e…",
"data":{ …the same text as GET /messages… },
"sentAt":"2026-10-02T12:41:51.402Z"}Verify every push before you trust it — HMAC-SHA256 of "<timestamp>.<raw body>" with your secret, and refuse a timestamp older than five minutes. deliveryId stays the same on every retry, so a duplicate is easy to ignore.
const crypto = require('crypto');
const ts = req.get('X-MirageTel-Timestamp');
const expected = crypto.createHmac('sha256', SECRET)
.update(ts + '.' + rawBody).digest('hex');
const ok = expected === req.get('X-MirageTel-Signature')
&& Math.abs(Date.now() / 1000 - ts) < 300;import hmac, hashlib, time
ts = request.headers["X-MirageTel-Timestamp"]
expected = hmac.new(SECRET.encode(), f"{ts}.".encode() + raw_body,
hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, request.headers["X-MirageTel-Signature"]) \
and abs(time.time() - int(ts)) < 300Addresses inside private networks are refused, before every delivery, and redirects are not followed. Send test in your account posts one signed sms.test event.
Limits
| Requests | 120 a minute per key — enough to ask every half second |
|---|---|
| Keys | Up to 10 per account, each narrowable to some numbers and some senders |
| Webhooks | Up to 5 per account, https only, public addresses only |
| Retries | 30 s → 6 h, for 24 hours; answer any 2xx within 8 s |
| A dead endpoint | Switched off after 50 failures in a row with nothing delivered for a day — you are told, texts stay readable |
| Text content | Removed after 90 days; the record stays |
Numbers that receive texts
Numbers in 4 of the 93 countries we sell receive texts; the others take calls only. A received text costs 1¢ from your wallet, or one text from a calling pack. The API itself is free.
Questions
Does the SMS API cost anything?
No. The API, the keys and the webhooks are free. A text your number receives costs what it always costs: 1¢ from your wallet, or one text from a calling pack of that country.
Which numbers can receive texts?
Numbers in 4 of the 93 countries we sell receive texts; the others take calls only. Each country page says which.
Will a particular service be able to text my number?
That depends on the service and on the destination network, not on us — some services send only to mobile numbers of certain countries. Send yourself a test before you depend on it.
Can the API send texts?
Not yet. Version 1 reads the texts your numbers receive. Sending stays in your account and the app.
What can somebody do with a leaked key?
Read the texts the key may read — and nothing else. A key cannot send, buy, move money or see another account. Narrow it to the numbers and senders it needs, and revoke it in one click.
What if my server is down?
We retry after 30 s, 2 min, 10 min, 30 min, 1 h, 3 h and 6 h, for 24 hours. The texts stay readable with a key all the while.
How long are texts kept?
The words of a text are removed after 90 days; the record that it arrived stays, with bodyRetained set to false.