SMS Verification API for Virtual Numbers
The Turonay SMS verification API lets your app, bot or panel get a virtual number and read the incoming SMS code. It speaks the handler_api-compatible protocol: if you already have an integration written for it, you usually only change the base URL and the API key. You pay when the code reaches you, not when you request a number.
API pages
Quickstart in 3 steps
First sign up for free, top up your balance and get your API key from your profile (API section). In the examples, replace YOUR_KEY with your own key. Requests can be GET or POST: with POST you can send all parameters, including api_key, as form fields (application/x-www-form-urlencoded) in the request body, so the key does not have to appear in URLs or server logs. The two base URLs are equivalent: https://turonay.com/stubs/handler_api.php and https://turonay.com/api/.
1. Check your balance
getBalance returns your balance as ACCESS_BALANCE:amount, which is also the quickest way to confirm that your key works. The amount is in TRY and is the available balance after the amount reserved for open activations.
curl "https://turonay.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getBalance"
ACCESS_BALANCE:125.40002. Get a number
service is the service code (wa for WhatsApp) and country is the country id. A successful call returns ACCESS_NUMBER:activation_id:phone. The price is reserved on your balance at this point, not charged yet. If you pass the highest price you accept as maxPrice, no number is taken when the price is higher and WRONG_MAX_PRICE:price is returned.
curl "https://turonay.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getNumber&service=wa&country=62&maxPrice=20"
ACCESS_NUMBER:184213:9053012345673. Receive the code
Until the code arrives getStatus returns STATUS_WAIT_CODE; once it does you get STATUS_OK:code. The fee is finalised at exactly that moment. Instead of polling you can also use signed webhooks.
curl "https://turonay.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getStatus&id=184213"
STATUS_WAIT_CODE
curl "https://turonay.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getStatus&id=184213"
STATUS_OK:123456Prefer JSON? getNumberV2
getNumberV2 takes the same parameters as getNumber and returns JSON on success: activation id, phone number, price, currency (949 = TRY), country, end time and operator. activationTime and activationEndTime are in server time (Europe/Istanbul, UTC+3), formatted Y-m-d H:i:s without a time zone. On failure you get the classic plain-text codes (NO_NUMBERS, NO_BALANCE, WRONG_MAX_PRICE:price).
{
"activationId": "184213",
"phoneNumber": "905301234567",
"activationCost": "12.50",
"currency": 949,
"countryCode": "62",
"canGetAnotherSms": true,
"activationTime": "2026-10-10 12:00:00",
"activationEndTime": "2026-10-10 12:20:00",
"activationOperator": "any"
}Why the Turonay virtual number API?
The goal is a short integration and a cost you can predict.
Compatible protocol
It speaks the widely used handler_api format: the same action names, the same plain-text responses, plus JSON endpoints on top. Existing clients and bots usually work after changing the base URL; verify service codes and country ids with getPrices.
Pay when the code arrives
When you get a number the price is only reserved. If no code arrives, the provider cancels, or the activation expires, the reserved amount goes back to your balance.
Signed webhooks
When a code arrives or an activation is cancelled, an HMAC-SHA256-signed HTTPS POST is sent to your server. Failed deliveries are retried with progressive backoff.
Current prices and stock
getPrices returns the current price and stock count for every service and country pair. You do not guess: fetch the list, see the price, then buy.
Multi-currency display
API prices are in TRY (currency code 949 in getNumberV2). On the website you can view your balance and prices in TRY, USD or RUB.
Site and docs in three languages
The site and the API documentation are available in Turkish, English and Russian. If you get stuck during integration, write to us through the support ticket system.
API methods
Every request carries api_key and action. The table below summarises all actions with typical responses; details are on the API reference page.
| Action | What it does | Response |
|---|---|---|
getBalance |
Returns your available balance (reserved amounts already deducted). | ACCESS_BALANCE:125.4000 |
getPrices |
Returns the current price and stock count per service and country as JSON. Filter with service and country; prices include your account's tier discount. |
{"62":{"wa":{"cost":12.50,"count":744716}}} |
getCountries |
Lists the countries you can get numbers for (id and name). | {"62":{"id":62,"eng":"Turkey"}} |
getNumbersStatus |
Returns the stock count of each service in the selected country. | {"wa_0":"744716"} |
getOperators |
Lists selectable operators; currently only any is available. |
{"status":"success","countryOperators":{"62":["any"]}} |
getNumber |
Gets a number: service, country, optional operator and maxPrice. The price is reserved. |
ACCESS_NUMBER:184213:905301234567 |
getNumberV2 |
JSON counterpart of getNumber; also returns price, currency, end time and operator. |
{"activationId":"184213","phoneNumber":"905301234567",…} |
getStatus |
Asks whether the code has arrived. The fee is finalised when it does. | STATUS_WAIT_CODESTATUS_OK:123456STATUS_CANCEL |
getStatusV2 |
JSON counterpart of getStatus: an sms object once the code has arrived, a plain-text status before that. |
{"sms":{"code":"123456",…}} |
getActiveActivations |
Lists the open activations on your account, to resume after a restart or to power a dashboard. | {"status":"success","activeActivations":[…]} |
setStatus |
1 ready (no charge change), 3 request another SMS (free), 6 complete (only after a code), 8 cancel (refunded if no code; EARLY_CANCEL_DENIED after a code). |
ACCESS_READYACCESS_RETRY_GETACCESS_ACTIVATIONACCESS_CANCEL |
Billing: reserve, charge, release
With Turonay you pay for a virtual number when the code arrives, not when the number is allocated, so you do not lose money on activations that are never delivered. The flow has four states:
| Moment | What happens | Your balance |
|---|---|---|
Number allocated (getNumber / getNumberV2) |
The price is set aside on your balance, which is why getBalance shows a lower available amount. |
Reserved |
| SMS code arrives | The fee is finalised. Requesting another SMS on the same number (status=3) is free. |
Charged |
| Cancelled before a code, provider cancellation, or expiry | The reserved amount is released and nothing is charged. | Restored |
Cancel attempt after the code (status=8) |
EARLY_CANCEL_DENIED is returned; because the service was delivered there is no refund. Close the activation with status=6. |
Unchanged |
Price cap: maxPrice
Your balance must cover the number's price, otherwise NO_BALANCE is returned. To protect yourself against price surprises, send maxPrice: if the current price is higher, nothing is purchased and the real price is reported as WRONG_MAX_PRICE:price.
Webhooks: get the code notification on your server
Instead of calling getStatus every second, register an HTTPS URL. When a code arrives or an activation is cancelled, Turonay sends a signed POST to it. The notification is queued as soon as the code is recorded and is typically delivered within 1–2 minutes; polling getStatus remains an alternative and a fallback. You manage the URL and the secret from your profile and can send a test event.
- Signature: HMAC-SHA256 over
timestamp.body, sent in theX-Turonay-Signatureheader. - Headers:
X-Turonay-Event,X-Turonay-Timestamp,X-Turonay-Signature,X-Turonay-Delivery. - Only
httpsURLs are accepted. - A failed delivery is attempted up to 8 times with progressive backoff; the same event can arrive again, so write your handler to be idempotent.
POST /your-webhook HTTP/1.1
X-Turonay-Event: code_received
X-Turonay-Timestamp: 1791631200
X-Turonay-Signature: sha256=<hex>
X-Turonay-Delivery: dlv_<id>
signature = HMAC_SHA256(secret, timestamp + "." + body)For signature verification examples, the payload schema and the retry policy, see the SMS API webhook guide.
Examples in your language
The same flow (get a number, wait for the code, complete) is shown with ready-made examples in three languages.
Coming from another SMS activation API?
Turonay is compatible with the widely used handler_api protocol. If you are coming from another provider that uses it and have written a bot, panel or script against that protocol, switching usually comes down to three changes: the base URL, the API key, and checking service codes and country ids. Test the full flow before going live.
Turonay is an independent service. It is not affiliated with any other provider and does not claim to replace them. Balances cannot be transferred; you top up your Turonay account separately.
Pricing and payment
Prices vary by service and country and are updated continuously, so instead of a fixed list you read the live value with getPrices. For current examples and cost calculation see SMS API pricing. All API amounts are in TRY; on the site you can view TRY, USD or RUB.
You can top up on the payment page by card (Shopier, Stripe), crypto (Cryptomus, Heleket) or bank transfer; which methods are available depends on the currency and region. There is no separate subscription fee for API access.
Resell with your own margin
If you sell SMS verification to your customers through a Telegram bot, a panel or a website, see the SMS reseller page for tiered discounts and margin math.
Developer resources
Ready-made files to speed up your integration:
For the full method and error code reference, open the API reference.
Frequently asked questions
Is the SMS verification API paid?
There is no separate subscription or fee for API access. You only pay for delivered codes: when a number is allocated the amount is reserved on your balance, and it is charged when the code arrives.
Do I pay if the code never arrives?
No. If you cancel before a code arrives, the provider cancels, or the number expires, the reserved amount is released back to your balance.
Will my handler_api-compatible integration work?
Turonay works with the handler_api protocol; for most integrations it is enough to change the base URL (https://turonay.com/stubs/handler_api.php) and the API key. Verify service codes, country ids and prices with getPrices. Turonay is an independent service with no affiliation to any other provider.
Can I cancel an activation after the code has arrived?
No. After the code arrives, setStatus 8 returns EARLY_CANCEL_DENIED and the fee is not refunded because the service was delivered. Complete the activation with setStatus 6.
Should I poll for the code or use webhooks?
They work well together. The webhook notification is queued as soon as the code is recorded and is typically delivered within 1–2 minutes; getStatus and getActiveActivations are an alternative path and the safety net for missed events and restarts. The webhook body is signed with HMAC-SHA256, so always verify the signature.
Which currency are prices in, and how do I pay?
API prices are in TRY; on the site you can view TRY, USD or RUB. You can top up by card (Shopier, Stripe), crypto (Cryptomus, Heleket) or bank transfer; the available methods depend on the currency and region.
What if the price suddenly goes up?
Send the highest price you accept as maxPrice. If the current price is higher, nothing is purchased and the real price is reported in the WRONG_MAX_PRICE:price response.
What is the API meant for?
It is built for developers, test automation and QA teams, and resellers. Use must comply with the rules of the platforms involved and with the Turonay terms of use.
Start integrating
Sign up for free, top up your balance and get your first number in a few minutes.