SMS Verification API

Buy numbers and read verification codes over a JSON API. No KYC, crypto only.

REST · JSONOpenAPI 3.1 OpenAPI spec →

Every operation here is also an MCP tool. The REST endpoints are a translation of the same tools the MCP server exposes, so an autonomous agent and a conventional integration get identical behaviour. If you are pointing an AI agent at OTPDrop, start at Agents instead.

How does the API fit together?

  1. Create an account and store the seed it returns. It is the only credential and cannot be reset.
  2. Create a top-up, send the crypto, and wait for it to be credited.
  3. Buy a number for the service and country you need — the balance is debited instantly.
  4. 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.

The seed cannot be recovered. We store only a hash of it. Lose it and the account and its balance are gone, with no reset and no support route back in.

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\""
  }
}
StatusMeaning
200Success
201Created — an account, top-up or order now exists
401Missing or invalid seed in the Authorization header
422The request was understood but could not be carried out
500Something failed on our side

Common 422 messages:

MessageCause
insufficient_fundsBalance is below the price — create a top-up first
unknown serviceNo such service code; see List services
unknown countryNo such country code; see List countries
unknown coinCoin 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.

EndpointSensible paceWhy
Catalog and quotesCache locallyPrices change rarely; there is no need to fetch the catalogue on every request.
/topups/{id}Every 10-15 secondsNetwork confirmation takes minutes, not milliseconds. Polling faster tells you nothing sooner.
/orders/{id}/smsEvery 3-5 secondsCodes usually land within seconds; a tighter loop only adds load.
BuyingAs neededEach 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

NameTypeDescription
limitintegeroptionalHow 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

NameTypeDescription
servicestringrequiredService code, e.g. telegram
countrystringrequiredCountry 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

NameTypeDescription
amount_usdnumberrequiredHow much to add to the balance, in USD. Minimum 25, maximum 1000.
coinstringrequiredBTC, 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

NameTypeDescription
idstringrequiredThe 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

NameTypeDescription
servicestringrequiredService code, e.g. telegram
countrystringrequiredCountry 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

NameTypeDescription
idstringrequiredThe 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

NameTypeDescription
idstringrequiredThe 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.

FileContents
/openapi.jsonThe full OpenAPI 3.1 schema
/.well-known/agent.jsonCapabilities, auth model and business rules
/llms.txtA short orientation for language models
/llms-full.txtThe 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.