SMS Verification API
Buy numbers and read verification codes over a JSON API. No KYC, crypto only.
How does the API fit together?
- Create an account and store the seed it returns. It is the only credential and cannot be reset.
- Create a top-up, send the crypto, and wait for it to be credited.
- Buy a number for the service and country you need — the balance is debited instantly.
- Poll for the SMS code. No code before the order expires means an automatic refund.
Fund once, buy many: a single top-up covers as many numbers as its balance allows, so only the first purchase waits on a confirmation.
Authentication
Send the account seed as a bearer token. There is no separate API key, and no login call — the seed is the credential.
Authorization: Bearer YOUR-SEED-PHRASE
The catalog endpoints need no authentication at all, so you can browse services, countries and prices before an account exists. Everything that touches money or orders requires the header.
Base URL
All endpoints are relative to:
https://www.otpdrop.com/api/v1
Responses are JSON. POST bodies are accepted as application/json or
application/x-www-form-urlencoded.
Errors
Failures return a non-2xx status and a single error object.
{
"error": {
"code": "invalid_request",
"message": "unknown service: \"whatsap\""
}
}
| Status | Meaning |
|---|---|
200 | Success |
201 | Created — an account, top-up or order now exists |
401 | Missing or invalid seed in the Authorization header |
422 | The request was understood but could not be carried out |
500 | Something failed on our side |
Common 422 messages:
| Message | Cause |
|---|---|
insufficient_funds | Balance is below the price — create a top-up first |
unknown service | No such service code; see List services |
unknown country | No such country code; see List countries |
unknown coin | Coin not accepted; see the top-up endpoint |
amount_usd must be between… | Top-ups are limited to $25–$1000 |
Are there rate limits?
There is no published quota and no API key to throttle, but the endpoints are not free to call in a loop. Two of them are polling endpoints and deserve particular care.
| Endpoint | Sensible pace | Why |
|---|---|---|
| Catalog and quotes | Cache locally | Prices change rarely; there is no need to fetch the catalogue on every request. |
/topups/{id} | Every 10-15 seconds | Network confirmation takes minutes, not milliseconds. Polling faster tells you nothing sooner. |
/orders/{id}/sms | Every 3-5 seconds | Codes usually land within seconds; a tighter loop only adds load. |
| Buying | As needed | Each purchase debits a real balance, so runaway loops cost you money before they cost us anything. |
Traffic that looks like an attack will be blocked at the edge without a courtesy 429.
If you have a legitimate reason to poll harder, ask on the contact page first.
List services
GET/api/v1/services
Every service with its code, category and cheapest price. No authentication required.
Request
curl -s https://www.otpdrop.com/api/v1/services
Response
{
"services": [
{
"code": "binance",
"name": "Binance",
"category": "Finance",
"from_price_cents": 85,
"color": "#F0B90B",
"icon": "binance"
}
],
"count": 133
}
List countries
GET/api/v1/countries
Every country with its dial code and how many services are available there. No authentication required.
Request
curl -s https://www.otpdrop.com/api/v1/countries
Response
{
"countries": [
{
"code": "us",
"name": "United States",
"dial_code": "+1",
"service_count": 133
}
],
"count": 197
}
Pricing matrix
GET/api/v1/catalog
The most useful service and country combinations with their prices, cheapest first. No authentication required.
Parameters
| Name | Type | Description | |
|---|---|---|---|
limit | integer | optional | How many rows to return, 1 to 500. Defaults to 12. |
Request
curl -s 'https://www.otpdrop.com/api/v1/catalog?limit=2'
Response
{
"items": [
{
"service": "badoo",
"country": "us",
"price_cents": 35
}
],
"count": 2
}
Quote a price
GET/api/v1/quote
The exact price for one service and country before you commit to buying. No authentication required.
Parameters
| Name | Type | Description | |
|---|---|---|---|
service | string | required | Service code, e.g. telegram |
country | string | required | Country code, e.g. us |
Request
curl -s 'https://www.otpdrop.com/api/v1/quote?service=telegram&country=us'
Response
{
"service": "telegram",
"country": "us",
"price_cents": 111,
"price_usd": "1.11",
"currency": "USD",
"purchasable": true
}
Create an account
POST/api/v1/accounts
Generates an account and returns its seed. This is the only time the seed is ever shown. No authentication required.
Request
curl -s -X POST https://www.otpdrop.com/api/v1/accounts
Response
{
"public_id": "acc_7f3c1a92",
"seed": "PABh-ZbRt-9xKm-Lq4V",
"seed_prefix": "PABh",
"balance_cents": 0,
"warning": "This seed is shown exactly once, right now..."
}
Create a top-up
POST/api/v1/topups
Claims a deposit address and returns the exact amount to send, as coin_amount, at the rate in rate_usd. Each top-up gets its own address, and it expires at expires_at. Send only the named coin, on the named network, before then.
Parameters
| Name | Type | Description | |
|---|---|---|---|
amount_usd | number | required | How much to add to the balance, in USD. Minimum 25, maximum 1000. |
coin | string | required | BTC, LTC, ETH, XMR, SOL, TRX, BNB, USDT, USDC and more |
Request
curl -s -X POST https://www.otpdrop.com/api/v1/topups \
-H 'Authorization: Bearer YOUR-SEED' \
-H 'content-type: application/json' \
-d '{"amount_usd": 25, "coin": "XMR"}'
Response
{
"topup_id": "top_019195919c80fc8f",
"status": "awaiting_payment",
"coin": "XMR",
"address": "89Rm4XN39m9PCr8Sr3yAFnXvLRRWQVEE...",
"amount_cents": 2500,
"amount_usd": "25.00",
"coin_amount": "0.1337",
"rate_usd": 187.02,
"bonus_cents": 0,
"credited_total_cents": 2500,
"expires_at": 1788532810
}
Top-up status
GET/api/v1/topups/{id}
Whether a deposit has been credited. Confirmation is not instant — poll this rather than assuming the funds arrived.
Parameters
| Name | Type | Description | |
|---|---|---|---|
id | string | required | The top-up id, in the path |
Request
curl -s https://www.otpdrop.com/api/v1/topups/top_019195919c80fc8f \ -H 'Authorization: Bearer YOUR-SEED'
Response
{
"topup_id": "top_019195919c80fc8f",
"status": "credited",
"coin": "XMR",
"amount_usd": "25.00",
"coin_amount": "0.1337",
"credited_total_cents": 2500,
"expires_at": 1788532810
}
Buy a number
POST/api/v1/orders
Debits the balance and issues a number immediately. There is no per-purchase address and no second wait. Fails with insufficient_funds if the balance is short.
Parameters
| Name | Type | Description | |
|---|---|---|---|
service | string | required | Service code, e.g. telegram |
country | string | required | Country code, e.g. us |
Request
curl -s -X POST https://www.otpdrop.com/api/v1/orders \
-H 'Authorization: Bearer YOUR-SEED' \
-H 'content-type: application/json' \
-d '{"service": "telegram", "country": "us"}'
Response
{
"order_id": "ord_1ad450bf7a42519c",
"service": "telegram",
"country": "us",
"phone": "+15558329008",
"status": "paid",
"price_usd": "1.11"
}
List your orders
GET/api/v1/orders
Every order on the account, newest first, with status, number and price. Useful for reconciling state after a restart rather than for polling.
Request
curl -s https://www.otpdrop.com/api/v1/orders \ -H 'Authorization: Bearer YOUR-SEED'
Response
{
"orders": [
{
"order_id": "ord_1ad450bf7a42519c",
"service": "telegram",
"country": "us",
"phone": "+15558329008",
"status": "paid",
"price_usd": "1.11"
}
],
"count": 1
}
Get an order
GET/api/v1/orders/{id}
The current state of one order: its number, status and price.
Parameters
| Name | Type | Description | |
|---|---|---|---|
id | string | required | The order id, in the path |
Request
curl -s https://www.otpdrop.com/api/v1/orders/ord_1ad450bf7a42519c \ -H 'Authorization: Bearer YOUR-SEED'
Response
{
"order_id": "ord_1ad450bf7a42519c",
"service": "telegram",
"country": "us",
"phone": "+15558329008",
"status": "paid",
"price_usd": "1.11"
}
Get the SMS code
GET/api/v1/orders/{id}/sms
Poll this until arrived turns true. If the order expires with nothing delivered, the price returns to your balance automatically.
Parameters
| Name | Type | Description | |
|---|---|---|---|
id | string | required | The order id, in the path |
Request
curl -s https://www.otpdrop.com/api/v1/orders/ord_1ad450bf7a42519c/sms \ -H 'Authorization: Bearer YOUR-SEED'
Response
{
"order_id": "ord_1ad450bf7a42519c",
"status": "paid",
"arrived": false,
"code": null
}
What does a complete integration look like?
Account to code in six calls. Everything below is real: paste it and it runs.
# 1. Create an account and keep the seed
SEED=$(curl -s -X POST https://www.otpdrop.com/api/v1/accounts | jq -r .seed)
# 2. Fund it — send the coin_amount to the address returned
curl -s -X POST https://www.otpdrop.com/api/v1/topups \
-H "Authorization: Bearer $SEED" \
-H 'content-type: application/json' \
-d '{"amount_usd": 25, "coin": "USDT"}'
# 3. Poll until the deposit is credited
curl -s https://www.otpdrop.com/api/v1/topups/TOPUP_ID \
-H "Authorization: Bearer $SEED" | jq .status
# 4. Check the price before committing
curl -s 'https://www.otpdrop.com/api/v1/quote?service=telegram&country=us'
# 5. Buy — the balance is debited and the number issued at once
ORDER=$(curl -s -X POST https://www.otpdrop.com/api/v1/orders \
-H "Authorization: Bearer $SEED" \
-H 'content-type: application/json' \
-d '{"service": "telegram", "country": "us"}' | jq -r .order_id)
# 6. Poll for the code
until curl -s https://www.otpdrop.com/api/v1/orders/$ORDER/sms \
-H "Authorization: Bearer $SEED" | jq -e .code; do sleep 4; done
The same sequence in Python, without the shell:
import time, requests
API = "https://www.otpdrop.com/api/v1"
seed = requests.post(f"{API}/accounts").json()["seed"]
auth = {"Authorization": f"Bearer {seed}"}
topup = requests.post(f"{API}/topups", headers=auth,
json={"amount_usd": 25, "coin": "USDT"}).json()
print("send", topup["coin_amount"], topup["coin"], "to", topup["address"])
while requests.get(f"{API}/topups/{topup['topup_id']}",
headers=auth).json()["status"] != "credited":
time.sleep(15)
order = requests.post(f"{API}/orders", headers=auth,
json={"service": "telegram", "country": "us"}).json()
print("number:", order["phone"])
while True:
sms = requests.get(f"{API}/orders/{order['order_id']}/sms",
headers=auth).json()
if sms["arrived"]:
print("code:", sms["code"])
break
time.sleep(4)
MCP server
The same operations are available over the Model Context Protocol at https://www.otpdrop.com/mcp,
as eleven tools. Add it to Claude Code with:
claude mcp add --transport http otpdrop https://www.otpdrop.com/mcp
Setup and the full tool list are on the Agents page.
Discovery files
Machine-readable descriptions of the service, all served without authentication.
| File | Contents |
|---|---|
/openapi.json | The full OpenAPI 3.1 schema |
/.well-known/agent.json | Capabilities, auth model and business rules |
/llms.txt | A short orientation for language models |
/llms-full.txt | The same with the full catalog inlined |
Frequently asked questions
Does the OTPDrop API need an API key?
No. There is nothing to apply for and no approval step. The account seed is the credential, sent as a bearer token, and the catalogue endpoints need no credential at all.
What does the OTPDrop API cost?
Nothing beyond the numbers you buy. There is no subscription, no per-call charge and no minimum volume — you pay the same prices as anyone using the website.
Which programming languages work with the API?
Any language that can make an HTTPS request. It is plain JSON over HTTP with a bearer header, so there is no SDK to install and nothing to keep in step with our releases.
What happens if the SMS code never arrives?
The order refunds itself to your balance when it expires, and you can cancel earlier through the website. You are charged for delivered codes, not for attempts.
Is the REST API the same as the MCP server?
Yes, deliberately. Each REST endpoint is a translation of one MCP tool call, so the two cannot drift apart: a fix to one is a fix to both. Pick whichever suits your client.
Can you test the API without spending anything?
The catalogue, quotes and account creation are free, so you can build and test most of an integration before funding a balance. Only buying costs money.