API Reference
MrOTP API
A simple REST API for renting phone numbers and receiving OTP / SMS codes in real time. Everything is JSON, everything is predictable, and every request you make is billed per code — and refunded automatically when a code doesn't arrive.
Quick start
You'll need an API token. Create an account, sign in, and copy your token from the Profile page — then make your first call.
Get your API token
Create an account, then open Profile to view or regenerate your personal API token.
Check your balance
Balance is pre-paid. Each get_phone deducts the code cost; failures are refunded.
Request a number & poll for the code
Call get_phone, keep the returned request_id, then poll get_otp until a code arrives.
# 1. request a number
curl -X POST https://<host>/api/v1/get_phone \
-H "X-Api-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"service": "telegram"}'
# 2. poll for the code
curl -X POST https://<host>/api/v1/get_otp \
-H "X-Api-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"request_id": "0195a2f0-1234-7abc-8def-123456789abc"}'
Python — full flow
import requests, time
BASE = "https://<host>/api/v1"
TOKEN = "your-api-token"
H = {"X-Api-Token": TOKEN, "Content-Type": "application/json"}
# 1. get a phone number
r = requests.post(f"{BASE}/get_phone", headers=H, json={"service": "telegram"}).json()
request_id = r["data"]["request_id"]
phone = r["data"]["phone"]
print("Phone:", phone, "(request_id:", request_id, ")")
# 2. poll until the code arrives
while True:
r = requests.post(f"{BASE}/get_otp", headers=H, json={"request_id": request_id}).json()
d = r["data"]
if d["status"] == "otp":
print("OTP:", d["otp"]) # e.g. 123456
print("SMS:", d["sms"])
break
if d["status"] == "fail":
print("Failed:", d["message"])
break
time.sleep(3)
Authentication
Every endpoint except /ping requires your API token. You can pass the token in any one of three places:
Header (recommended)
X-Api-Token: $TOKEN
Query string
?token=$TOKEN
JSON body
{"token": "$TOKEN"}
Missing or invalid tokens return 401.
Response envelope
Every non-/ping response uses the same fixed shape. The HTTP status code always mirrors the code field.
{
"code": 200, // same as the HTTP status
"message": "Success", // human-readable
"data": { ... } // endpoint-specific payload (or null)
}
Tip: branch on data for success values and on message for errors — but never on the code alone, since the same code can come with different messages.
How it works
The full lifecycle of a single OTP request, from your app to the SIM and back.
1 · Provision
Your request locks an available SIM for that service and charges your balance.
2 · Receive
The SIM gets the code, which is delivered back to the server automatically.
3 · Retrieve
You poll get_otp until it returns the code — or a failure (which refunds you).
/api/v1/ping
Liveness probe. The only endpoint that needs no token and returns plain text instead of JSON.
Request
curl https://<host>/api/v1/ping
Response 200
pong
/api/v1/balance
API tokenReturns your current pre-paid balance as a string.
Request
curl https://<host>/api/v1/balance \
-H "X-Api-Token: $TOKEN"
Response 200
{
"code": 200,
"message": "Success",
"data": {
"balance": "100.0000"
}
}
/api/v1/services
API tokenLists the active services (platforms) you can request, with the per-code cost and OTP timeout for each. Note data is a bare array, not wrapped in an object.
Response 200
{
"code": 200,
"message": "Success",
"data": [
{ "name": "telegram", "cost": "5.0000", "timeout_seconds": 120 },
{ "name": "whatsapp", "cost": "7.5000", "timeout_seconds": 180 }
]
}
/api/v1/get_phone
API tokenAssigns an available SIM for a service and charges your balance. Use the request_id returned here to call get_otp.
| Field | Type | Req | Description |
|---|---|---|---|
| service | string | one of | Service name (e.g. telegram) — or use service_id. |
| service_id | integer | one of | Service id as an alternative to the name. |
Request
curl -X POST https://<host>/api/v1/get_phone \
-H "X-Api-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"service": "telegram"}'
Response 200
{
"code": 200,
"message": "Success",
"data": {
"request_id": "0195a2f0-1234-7abc-8def-123456789abc",
"phone": "8499880001",
"service": "telegram",
"cost": "5.0000"
}
}
Possible errors: 404 no available SIM / unknown service, 400 missing service or insufficient balance, 503 maintenance mode.
/api/v1/get_otp
API tokenPolls the status of a previous get_phone request. The data.status field tells you where you are in the lifecycle.
| Field | Type | Req | Description |
|---|---|---|---|
| request_id | string | yes | The request_id returned by get_phone. |
Request
curl -X POST https://<host>/api/v1/get_otp \
-H "X-Api-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{"request_id": "0195a2f0-1234-7abc-8def-123456789abc"}'
Three possible status values 200
{ "status": "waiting", "phone": "8499880001" }
{ "status": "otp", "otp": "123456",
"sms": "Your Telegram code is 123456",
"voice_call": null, "phone": "8499880001" }
{ "status": "fail", "message": "timeout",
"phone": "8499880001" }
Poll every few seconds until the status is otp or fail. A fail (timeout or error) refunds your balance automatically. Errors: 400 missing or invalid request_id, 404 request not found / not yours.
Error codes
All errors use the same envelope; the HTTP status equals code and the detail is in message.
| Code | Meaning | Typical cause |
|---|---|---|
| 200 | Success | Request processed. Read data. |
| 400 | Bad request | Missing field, invalid type, insufficient balance, wrong-service OTP. |
| 401 | Unauthorized | Missing or invalid token. |
| 404 | Not found | Unknown service, no available SIM, request not found. |
| 503 | Service unavailable | Maintenance mode — phone provisioning paused. |
Ready to integrate?
Create a free account, grab your token, and ship your first OTP in minutes.