Two interfaces over the same account and the same wallet: a clean JSON API, and an SMS-Activate compatible endpoint so existing bots work with a URL swap.
Every request carries your API key — find it on the Account page. Send it as a header (preferred) or a query parameter.
X-API-Key: ws_xxxxxxxxxxxxxxxxxxxxxxxx
# or
Authorization: Bearer ws_xxxxxxxxxxxxxxxxxxxxxxxx
# or ?api_key=ws_xxxx on the SMS-Activate endpoint
Rate limit: 120 requests per minute per key. Exceeding it returns HTTP 429.
Base URL: https://watersms.com/api/v1
{ "balance": 42.50, "currency": "USD" }
Prices, live stock per service, and the rental plans.
{
"country": "US",
"services": [ { "code": "ig", "name": "Instagram", "price": 1.10, "stock": 14 } ],
"rentals": [ { "hours": 24, "label": "24 hours", "price": 6.00 } ],
"rental_stock": 22
}
Buys one verification. Body: { "service": "ig" }. Charges your balance and holds a number.
{
"ok": true,
"activation": {
"id": 8123, "type": "activation", "number": "+14045551234",
"service": "ig", "price": 1.10, "status": "waiting",
"code": null, "expires_at": "2026-09-03 23:41:12"
}
}
Poll this until code is set. Every message received on the number during the hold is in messages.
{
"order": {
"id": 8123, "status": "received", "code": "418302",
"messages": [ { "sender": "Instagram", "body": "418302 is your Instagram code", "code": "418302", "received_at": "..." } ]
}
}
You got what you needed — releases the number back to the pool.
Refunds the full price and releases the number. Only before a code arrives, and not within the first 60 seconds.
Asks for another SMS on the same number (up to twice) and extends the hold by 10 minutes.
Body: { "hours": 24 }. Holds a number for the window; read its inbox with GET /orders/:id.
Point existing software at https://watersms.com/stubs/handler_api.php. Responses are the same plain-text strings, so most clients need only the base URL changed.
GET /stubs/handler_api.php?api_key=KEY&action=getBalance
→ ACCESS_BALANCE:42.50
GET /stubs/handler_api.php?api_key=KEY&action=getNumber&service=ig&country=12
→ ACCESS_NUMBER:8123:14045551234
GET /stubs/handler_api.php?api_key=KEY&action=getStatus&id=8123
→ STATUS_WAIT_CODE (nothing yet)
→ STATUS_OK:418302 (code arrived)
→ STATUS_CANCEL (expired or cancelled)
GET /stubs/handler_api.php?api_key=KEY&action=setStatus&id=8123&status=6 → ACCESS_ACTIVATION (done)
GET /stubs/handler_api.php?api_key=KEY&action=setStatus&id=8123&status=8 → ACCESS_CANCEL (cancel + refund)
GET /stubs/handler_api.php?api_key=KEY&action=setStatus&id=8123&status=3 → ACCESS_RETRY_GET (another code)
GET /stubs/handler_api.php?api_key=KEY&action=getNumbersStatus → {"ig_0":14,"go_0":9,...}
GET /stubs/handler_api.php?api_key=KEY&action=getPrices → {"12":{"ig":{"cost":1.10,"count":14}}}
Country is always 12 (USA) — the parameter is accepted and ignored. Service codes come from getPrices or the JSON /services endpoint.
curl -s https://watersms.com/api/v1/activations \
-H "X-API-Key: $KEY" -H "Content-Type: application/json" \
-d '{"service":"ig"}'
# poll every 2-3 seconds until "code" is filled in
curl -s https://watersms.com/api/v1/orders/8123 -H "X-API-Key: $KEY"
# release the number when you're finished
curl -s -X POST https://watersms.com/api/v1/orders/8123/complete -H "X-API-Key: $KEY"
If no SMS arrives before the hold expires, the order is cancelled and the charge is reversed automatically — you are never billed for a code you did not receive.
| JSON | SMS-Activate | Meaning |
|---|---|---|
| bad_key | BAD_KEY | Key missing, wrong, or the account is suspended |
| no_balance | NO_BALANCE | Wallet balance is below the price |
| no_numbers | NO_NUMBERS | No unburned number free for that service |
| bad_service | BAD_SERVICE | Unknown or disabled service code |
| too_soon | EARLY_CANCEL_DENIED | Cancel attempted within 60 seconds of purchase |
| code_received | ACCESS_ACTIVATION | Cannot cancel — a code already arrived |
| rate_limited | HTTP 429 | Over 120 requests in a minute |