Reseller API
Complete REST reference for the reseller program: signup, login, quota top-up, minting, and customer management.
The reseller API is a REST surface under /api/reseller. Every endpoint except signup and login requires a reseller JWT sent as Authorization: Bearer <token>. The token is issued at login and is valid for 24 hours (HS256).
Authentication endpoints#
/api/reseller/auth/signupRegister a new reseller account. On success the account is created in pending status and awaits admin review.
Parameters
Login email. Must not be blacklisted.
Account password. Minimum 8 characters.
Display name of the reseller.
WhatsApp number for contact, digits only with country code (for example `6281234567890`).
Request Example
curl -X POST "https://api.zrouter.dev/api/reseller/auth/signup" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "<password>",
"name": "Your Name",
"wa_number": "6281234567890"
}'Responses
{
"reseller": {
"id": "<reseller-id>",
"email": "[email protected]",
"name": "Your Name",
"status": "pending"
}
}/api/reseller/auth/loginAuthenticate and obtain a reseller JWT. The token is HS256 and valid for 24 hours.
Parameters
Registered reseller email.
Account password.
Request Example
curl -X POST "https://api.zrouter.dev/api/reseller/auth/login" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "<password>"
}'Responses
{
"token": "<token>",
"reseller": {
"id": "<reseller-id>",
"email": "[email protected]",
"name": "Your Name",
"status": "active"
}
}Account endpoints#
/api/reseller/meReturn the authenticated reseller's profile, including current status.
Responses
{
"id": "<reseller-id>",
"email": "[email protected]",
"name": "Your Name",
"status": "active"
}/api/reseller/balanceReturn the current quota balance as an integer micro-USD value.
Responses
{
"balance_usd_micro": "99500000"
}Top-up endpoints#
/api/reseller/topupCreate a top-up order that adds USD quota. Available methods: qris (IDR, fixed rate), crypto (USDC/USDT on Solana, 1:1), sumopod (QRIS, zero fee), or crypto_bep20 (USDT/USDC on BNB Smart Chain, 1:1). The order starts in pending and is credited only after confirmation.
Parameters
Payment method for this order.
qriscryptosumopodcrypto_bep20Principal amount in IDR. Required when `method` is `qris` or `sumopod`.
Amount in micro-USD. Required when `method` is `crypto` or `crypto_bep20`.
Deposit token for `crypto_bep20` (BEP20 on BSC chain 56). Ignored by every other method.
usdtusdcRequest Example
curl -X POST "https://api.zrouter.dev/api/reseller/topup" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"method": "qris", "amount_idr": 50000}'Responses
{
"id": "0d9c6f5e-4c1b-4f6e-9d2a-7b3f8c1e5a20",
"order_number": "RTO-0d9c6f5e-4c1b-4f6e-9d2a-7b3f8c1e5a20",
"payment_method": "qris",
"provider": "tako",
"amount_idr": 50000,
"fee_idr": 2500,
"total_idr": 52500,
"quota_usd_micro": 5000000,
"status": "pending",
"payment_status": "pending",
"provider_payment_id": "...",
"expires_at": "2026-09-16T00:15:00Z",
"created_at": "2026-09-16T00:00:00Z",
"qr_content": "0002...",
"qr_image_url": "https://...",
"payment_url": "https://..."
}curl -X POST "https://api.zrouter.dev/api/reseller/topup" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"method": "crypto", "amount_usd_micro": 20000000}'curl -X POST "https://api.zrouter.dev/api/reseller/topup" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"method": "crypto_bep20", "amount_usd_micro": 20000000, "token_kind": "usdt"}'/api/reseller/topup/{orderID}Get the status of a top-up order and reconcile it. If the payment has finalized, the order is marked paid and your quota is credited in the same call. The status field is the order lifecycle (pending → crediting → credited, or expired / failed); payment_status is the derived payment view (paid, pending, expired, failed) — a paid payment on a not-yet-credited order still credits. Prefer this GET endpoint for polling.
Parameters
The order `id` returned by `POST /api/reseller/topup`.
Request Example
curl "https://api.zrouter.dev/api/reseller/topup/<order-id>" \
-H "Authorization: Bearer <token>"Responses
{
"id": "0d9c6f5e-4c1b-4f6e-9d2a-7b3f8c1e5a20",
"order_number": "RTO-0d9c6f5e-4c1b-4f6e-9d2a-7b3f8c1e5a20",
"payment_method": "qris",
"provider": "tako",
"amount_idr": 50000,
"fee_idr": 2500,
"total_idr": 52500,
"quota_usd_micro": 5000000,
"status": "credited",
"payment_status": "paid",
"provider_payment_id": "...",
"expires_at": "2026-09-16T00:15:00Z",
"created_at": "2026-09-16T00:00:00Z",
"paid_at": "2026-09-16T00:07:41Z",
"credited_at": "2026-09-16T00:07:41Z"
}/api/reseller/topupsList your top-up orders, newest first. Each entry has the same shape as the single-order response. total is the total number of your orders (not the page size), for pagination.
Parameters
Page size, default 20, max 100.
Page offset, default 0.
Request Example
curl "https://api.zrouter.dev/api/reseller/topups?limit=20&offset=0" \
-H "Authorization: Bearer <token>"Responses
{
"topups": [
{
"id": "0d9c6f5e-...",
"order_number": "RTO-0d9c6f5e-...",
"payment_method": "qris",
"provider": "tako",
"amount_idr": 50000,
"fee_idr": 2500,
"total_idr": 52500,
"quota_usd_micro": 5000000,
"status": "credited",
"payment_status": "paid",
"expires_at": "2026-09-16T00:15:00Z",
"created_at": "2026-09-16T00:00:00Z",
"paid_at": "2026-09-16T00:07:41Z",
"credited_at": "2026-09-16T00:07:41Z"
}
],
"total": 1
}/api/reseller/topup/{orderID}/checkLegacy alias of GET /api/reseller/topup/{orderID} — same poll-and-reconcile behavior and the same response body. Kept for backward compatibility.
Parameters
The order id returned by `POST /api/reseller/topup`.
Request Example
curl -X POST "https://api.zrouter.dev/api/reseller/topup/<order-id>/check" \
-H "Authorization: Bearer <token>"Responses
Minting endpoints#
/api/reseller/mintMint a Token Plan tier to a customer, debiting your quota atomically. Idempotent on operation_id. See Quota & Minting.
Parameters
Client-generated idempotency key. Non-empty, at most 128 characters.
Email of the target customer (a zrouter user).
The Token Plan tier to grant. See the live [pricing page](/en/pricing).
Request Example
curl -X POST "https://api.zrouter.dev/api/reseller/mint" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"operation_id": "op_1234567890abcdef",
"customer_email": "[email protected]",
"plan_tier_id": "<tier-id>"
}'Responses
{
"customer_user_id": "<user-id>",
"model_id": "<model-id>",
"granted_tokens": 1000,
"price_usd_micro": "1000000",
"balance_after": "98500000",
"already_applied": false
}Tier catalog#
GET /api/reseller/tiers lists the Token Plan tiers you can mint, one entry per tier, ordered by tier price ascending then model name ascending. The topup_idr_required field is the IDR top-up quota needed to cover the tier at the fixed rate of Rp10.000 per USD (tier_usd_cents × 100); the 5% QRIS processing fee is separate and never included. Only safe, public fields are returned.
/api/reseller/tiersReturn the list of Token Plan tiers available to mint, sorted by tier price ascending then model name ascending. Internal-only pricing fields are never exposed.
Responses
{
"tiers": [
{
"plan_tier_id": "<tier-id>",
"model_id": "<model-id>",
"model_name": "<public-name>",
"tier_usd_cents": 100,
"price_usd_micro": 1000000,
"granted_tokens": 1000,
"topup_idr_required": 10000
}
]
}Customer endpoints#
/api/reseller/customersList the customers associated with this reseller.
Responses
{
"customers": [
{ "user_id": "<user-id>", "email": "[email protected]" }
]
}/api/reseller/customersResolve-or-create a customer by email. If the zrouter user does not exist, one is created and linked to this reseller.
Parameters
The customer's email.
Request Example
curl -X POST "https://api.zrouter.dev/api/reseller/customers" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"email": "[email protected]"}'Responses
{
"user_id": "<user-id>",
"email": "[email protected]",
"created": false
}/api/reseller/customers/{userID}/keysCreate an API key for a customer. The secret is revealed once and never stored. The response is served with Cache-Control: no-store.
Parameters
The customer's user id.
A label for this key.
Request Example
curl -X POST "https://api.zrouter.dev/api/reseller/customers/<user-id>/keys" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"name": "production"}'Responses
{
"key_id": "<key-id>",
"name": "production",
"secret": "zr_<public-id>_<secret>"
}/api/reseller/keys/{keyID}Revoke an API key. Scoped: the key must belong to a customer of this reseller, otherwise the request fails with 404.
Parameters
The key id to revoke.
Request Example
curl -X DELETE "https://api.zrouter.dev/api/reseller/keys/<key-id>" \
-H "Authorization: Bearer <token>"Responses
Balance endpoints#
The balance endpoints share one response shape: a payg object with a USD balance as a decimal string, and a token_plans array of integer token counts. Money is always a decimal string of micro-USD (for example "0.000001" is $0.000001) — never a float — and token counts are always integers. A revoked key still resolves to its owner's balances, so you can reconcile historical usage.
/api/reseller/keys/{keyID}/balancesReturn the PAYG balance and Token Plan balances of the customer who owns the given API key. Works even if the key is revoked, for historical reconciliation. Scoped: the key must belong to a customer of this reseller, otherwise the request fails with 404.
Parameters
The API key id (UUID) to look up.
Request Example
curl "https://api.zrouter.dev/api/reseller/keys/<key-id>/balances" \
-H "Authorization: Bearer <token>"Responses
{
"key_id": "<key-id>",
"customer_user_id": "<user-id>",
"payg": {
"currency": "USD",
"balance": "0.000001"
},
"token_plans": [
{
"model": "<public-name>",
"purchased_tokens": 1000,
"used_tokens": 123,
"remaining_tokens": 877,
"status": "active"
}
],
"as_of": "2026-09-16T00:00:00Z"
}/api/reseller/customers/{userID}/balancesReturn the PAYG balance and Token Plan balances for one of your customers. Same shape as the key balance endpoint, minus the key_id field. The customer must be owned by this reseller, otherwise the request fails with 404.
Parameters
The customer's user id (UUID).
Request Example
curl "https://api.zrouter.dev/api/reseller/customers/<user-id>/balances" \
-H "Authorization: Bearer <token>"Responses
{
"customer_user_id": "<user-id>",
"payg": {
"currency": "USD",
"balance": "0.000001"
},
"token_plans": [
{
"model": "<public-name>",
"purchased_tokens": 1000,
"used_tokens": 123,
"remaining_tokens": 877,
"status": "active"
}
],
"as_of": "2026-09-16T00:00:00Z"
}Usage endpoints#
/api/reseller/usageReturn settled usage for this reseller's customers, newest first, with cursor pagination. Each item includes the exact cost as display_cost_usd_micro.
Parameters
50Page size. Minimum 1, maximum 100.
Opaque cursor from a previous response's `next_cursor`.
Responses
{
"data": [
{
"user_id": "<user-id>",
"model": "<public-name>",
"total_tokens": 49,
"display_cost_usd_micro": "0.000120",
"timestamp": "2026-09-16T00:00:00Z"
}
],
"next_cursor": "<opaque-string>"
}