SMS activation API
Two ways in: an endpoint compatible with the sms-activate protocol, so existing software switches by changing the URL and key, and a JSON REST API for new integrations. Both use the same API key from your panel.
Get your API key
Create an account, open the panel and generate a key under API access. Keep it secret: anyone with the key can spend your balance.
Sign upTypical flow
- Call getNumber with a service and country.
- Use the number in the target app.
- Poll getStatus every few seconds until you get STATUS_OK.
- Call setStatus with 6 to finish, or 8 to cancel if no code came.
sms-activate compatible endpoint
Send GET or POST requests with api_key and action parameters. Responses are plain text, exactly like sms-activate.
https://smsrota.com/stubs/handler_api.php?api_key=KEY&action=getNumber&service=wa&country=187
Actions
| Action | Parameters | Response |
|---|---|---|
| getBalance | — | ACCESS_BALANCE:12.5000 |
| getPrices | service?, country? | {"187":{"wa":{"cost":0.4,"count":1563}}} |
| getNumber | service, country, maxPrice? | ACCESS_NUMBER:48151623:15550123456 |
| getStatus | id | STATUS_WAIT_CODE · STATUS_WAIT_RETRY:code · STATUS_OK:code · STATUS_CANCEL |
| setStatus | id, status | ACCESS_RETRY_GET · ACCESS_ACTIVATION · ACCESS_CANCEL |
| getRentNumber | service, country, rent_time (4/24/72/168/720) | {"status":"success","phone":{"id":31,"endDate":"…","number":"447700900001"}} |
| getRentStatus | id | {"status":"success","quantity":"1","values":{"0":{"phoneFrom":"WhatsApp","text":"…"}}} |
| setRentStatus | id, status (1 = finish, 2 = cancel) | {"status":"success"} |
| continueRentNumber | id, rent_time | {"status":"success","phone":{…}} |
setStatus values
- 3
- Request another code on the same number
- 6
- Finish the activation
- 8
- Cancel and refund (allowed two minutes after buying)
JSON REST API
Send the key in the Authorization header as "Bearer KEY". Amounts are strings in US dollars with four decimals.
GET https://smsrota.com/v1/balance
GET https://smsrota.com/v1/prices?service=wa
POST https://smsrota.com/v1/activations {"service":"wa","country":"187"}
GET https://smsrota.com/v1/activations/:id
POST https://smsrota.com/v1/activations/:id/retry
POST https://smsrota.com/v1/activations/:id/complete
POST https://smsrota.com/v1/activations/:id/cancel
GET https://smsrota.com/v1/rent/prices?service=wa&hours=24
POST https://smsrota.com/v1/rentals {"service":"full","country":"16","hours":24}
GET https://smsrota.com/v1/rentals/:id
POST https://smsrota.com/v1/rentals/:id/extend {"hours":24}
POST https://smsrota.com/v1/rentals/:id/finish
POST https://smsrota.com/v1/rentals/:id/cancel
POST https://smsrota.com/v1/rentals/:id/dispute {"reason":"no_sms"}
PUT https://smsrota.com/v1/webhook {"url":"https://example.com/sms-webhook"}
POST https://smsrota.com/v1/webhook/test
GET https://smsrota.com/v1/webhook/eventsWebhooks
Set a URL under API access in your panel. We send a POST with a JSON body for each event. Answer with any 2xx status within 10 seconds; otherwise we try again after 1, 5, 30, 120, 360 and 720 minutes.
- activation.sms_received
- A code arrived for a number you bought.
- activation.cancelled
- A number was cancelled or expired and the money went back to your balance.
- rental.sms_received
- An SMS arrived on a rented number.
- rental.ended
- A rental ended or was cancelled.
Example body
{
"id": "evt_1042",
"type": "activation.sms_received",
"createdAt": "2026-11-01T10:00:00.000Z",
"data": {
"activationId": 48151623,
"service": "wa",
"country": "187",
"phone": "15550123456",
"code": "123456"
}
}Checking the signature
Every request has an X-Webhook-Signature header like t=1730000000,v1=…, where v1 is the hex HMAC-SHA256 of "t.body" made with your signing secret. Reject a request if the signature doesn't match or t is more than 5 minutes old.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received, before JSON parsing.
function verify(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(t)) < 300;
return fresh && v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Errors
- BAD_KEY
- The API key is wrong or was replaced.
- NO_NUMBERS
- No stock for this service and country right now.
- NO_BALANCE
- Your balance is too low for this number.
- EARLY_CANCEL_DENIED
- Cancelling is possible two minutes after buying.
- NO_ACTIVATION
- The activation id doesn't exist or isn't yours.