Home › SMS API
Developer API

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.

195services currently listed
209countries currently listed
GET · POSTrequest methods
HMAC-SHA256signed webhooks

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.

bash
curl "https://turonay.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getBalance"
ACCESS_BALANCE:125.4000

2. 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.

bash
curl "https://turonay.com/stubs/handler_api.php?api_key=YOUR_KEY&action=getNumber&service=wa&country=62&maxPrice=20"
ACCESS_NUMBER:184213:905301234567

3. 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.

bash
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:123456

Prefer 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).

json
{
  "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.

ActionWhat it doesResponse
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_CODE
STATUS_OK:123456
STATUS_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_READY
ACCESS_RETRY_GET
ACCESS_ACTIVATION
ACCESS_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:

MomentWhat happensYour 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 the X-Turonay-Signature header.
  • Headers: X-Turonay-Event, X-Turonay-Timestamp, X-Turonay-Signature, X-Turonay-Delivery.
  • Only https URLs 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.
http
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.