Errors and limits
Error format
{"error": "insufficient_balance", "message": "Недостаточно средств на балансе. Пополните его в кабинете."}
Rely on the machine-readable error code. The message field is text in Russian and may change.
| HTTP | error |
When | What to do |
|---|---|---|---|
| 400 | invalid_json |
The body is not JSON or is larger than 4 KB | Fix the request |
| 401 | missing_api_key |
There is no Authorization header |
Pass the key |
| 401 | unauthorized |
The key was not found or has been revoked | Create a new key |
| 402 | insufficient_balance |
The balance is less than the SMS price | Top up the balance |
| 402 | daily_limit |
The daily spending limit has been reached | Raise the limit or wait until midnight Almaty time |
| 403 | phone_blocked |
The number is on your blocklist | Do not retry |
| 403 | fraud_blocked |
Antifraud rejection, the reason is in the reason field |
Do not retry right away |
| 403 | session_required |
The route is available only from the dashboard | Perform the action in the dashboard |
| 404 | not_found |
The object does not exist in your account | Check the id |
| 422 | invalid_phone |
Not a Kazakhstan mobile number | Fix the number |
| 422 | invalid_purpose, invalid_ip, invalid_signals, invalid_options, invalid_metadata |
Invalid field in the code request | Fix the field |
| 422 | invalid_before |
before in the statement is not in RFC 3339 format |
Fix the parameter |
| 429 | rate_limited |
The per-number session limit has been exceeded | Ask the user to wait |
| 500 | internal |
Internal error | Retry the request later |
Automatic retries make sense only for 500 and network errors. Keep in mind that POST /v1/verify is not idempotent: if the first request actually went through, a retry creates a second session.
Limits and antifraud
The default per-number session limit is 4 per 72 hours. It does not apply to test numbers, allowlisted numbers or requests with signals.is_trusted_user: true.
Antifraud rules are configured in the Antifraud section. The value 0 turns a rule off.
reason |
Rule | Default |
|---|---|---|
ip_rate |
Sessions from one IP per hour | 10 |
device_rate |
Sessions from one device per hour | 5 |
ip_numbers |
Different numbers from one IP per day | 5 |
ip_country |
IP from a country outside the allowed list | All allowed |
ip_blocked |
IP on the shared VERYO blocklist | — |
{"error": "fraud_blocked", "reason": "ip_rate", "message": "Слишком много запросов кода с этого IP за час."}
IP and device rules work only if you pass signals.ip and signals.device_id.