For developers

API docs

Click, Payme, Paynet and Xazna through one API. Create a payment, give the customer the pay_url, and get a signed callback once it's paid.

Base URL: https://pay.tolovgo.uz/api120 requests per minute per key

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 the pay_url from the response.
  • Handle the callback. When status=paid arrives, 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

MethodPathPurpose
POST/createCreate 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/ordersCreate 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

FieldTypeDescription
amountintegerRequired. In UZS, 1,000 — 99,999,999.
notestringNote, up to 500 characters. Returned in the callback.
callback_urlurlCalled once the payment is made. Must be a public internet address. If omitted, the store's default URL is used.
return_urlurlPage 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).
body is the JSON body for POST; for GET it's only 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

HTTPCodeReason
401missing_credentialsX-Api-Key header missing
401invalid_credentialsInvalid key
401key_revokedKey revoked
401ip_not_allowedThis IP address isn't allowed
403merchant_inactiveStore 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.refunded event.