01Getting started
4 steps
- Open a store. In the tolovgo.uz dashboard, choose “Create store”. The store becomes active once an admin approves it.
- Get an API key. On the store page, open “API key”. You can restrict the key to specific IPs.
- Create a payment.
POST /create→ give the customer thepay_urlfrom the response. - Handle the callback. When
status=paidarrives, verify the signature and fulfil the order.
Every request must include the X-Api-Key header. If the key is IP-restricted, requests from other IPs are rejected.
02Endpoints
relative to https://pay.tolovgo.uz/api
| Method | Path | Purpose |
|---|---|---|
| POST | /create | Create a payment. Callback is a GET, sent only once paid. |
| GET | /status/{order_id} | Payment status. Pass an order_id or order_hash. |
| POST | /v1/orders | Create a payment, v1. Callback is a JSON POST: order.paid, order.expired, order.cancelled, order.refunded. |
| GET | /v1/orders/{id} | Payment status, v1. |
03POST /create
Fields, request and response
| Field | Type | Description |
|---|---|---|
| amount | integer | Required. In UZS, 1,000 — 99,999,999. |
| note | string | Note, up to 500 characters. Returned in the callback. |
| callback_url | url | Called once the payment is made. Must be a public internet address. If omitted, the store's default URL is used. |
| return_url | url | Page the customer returns to after paying. |
Extra v1 fields: external_id (64), description (500), payer.telegram_id, payer.username, payer.name.
Request
curl -X POST https://pay.tolovgo.uz/api/create \
-H "X-Api-Key: SIZNING_KALIT" \
-d amount=25000 \
-d note="Order #1042" \
-d callback_url=https://sayt.uz/tolovgo-callback
Response · 201
{
"ok": true,
"status": "pending",
"order_id": 1042,
"amount": 25000,
"pay_url": "https://pay.tolovgo.uz/pay/…",
"providers": { /* click, payme, paynet, xazna — direct links */ }
}
04Statuses
Payment lifecycle
pending · paid · expired · cancelled · refunded
An unpaid link becomes expired after 1 hour. Even after a callback, it's best to confirm the status with GET /status/{order_id} before fulfilling the order.
05Callback signature
Verify the notification came from TolovGo
Every callback carries three headers:
X-Rox-Event— the event, e.g.order.paid;X-Rox-Timestamp— Unix time in seconds;X-Rox-Signature—sha256=+ HMAC-SHA256(timestamp.body, the store's webhook secret).
status, order_id, order_hash, amount, note in that order. Other parameters in your URL aren't signed. A callback may arrive more than once — make your handler idempotent.// callback.php — verify the signature
$secret = 'KASSA_WEBHOOK_SECRET';
$ts = $_SERVER['HTTP_X_ROX_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_ROX_SIGNATURE'] ?? '';
// GET callback: only these 5 parameters, in this order
$keys = ['status', 'order_id', 'order_hash', 'amount', 'note'];
$body = http_build_query(array_intersect_key(array_merge(array_flip($keys), $_GET), array_flip($keys)));
// v1 (POST): $body = file_get_contents('php://input');
$ok = hash_equals('sha256=' . hash_hmac('sha256', $ts . '.' . $body, $secret), $sig)
&& abs(time() - (int) $ts) < 300;
The signing secret is on the store page, under “Webhook”.
06Errors
HTTP codes
| HTTP | Code | Reason |
|---|---|---|
| 401 | missing_credentials | X-Api-Key header missing |
| 401 | invalid_credentials | Invalid key |
| 401 | key_revoked | Key revoked |
| 401 | ip_not_allowed | This IP address isn't allowed |
| 403 | merchant_inactive | Store is not active |
| 422 | — | Invalid field: {"ok": false, "error": "…"} |
| 429 | — | Exceeded 120 requests per minute |
07Money
Where it goes
- Payment — credited to the store balance minus the service fee (6%).
- Payout — to a card via the dashboard. Terms: Terms of use, section 5.
- Refunds — v1 stores receive the
order.refundedevent.