Provision users
POST /accounts — create a customer attributed to you; read the list and a single record.
A customer created with your key is attributed to you: their payments land in your revenue and in the revshare computation.
Create
POST /api/v1/reseller/accounts
Authorization: Bearer rsk_<key>
Content-Type: application/json
{
"email": "user@example.com",
"external_ref": "tg_123456789",
"language": "en"
}
email— required, must be free.password— optional. Omit it and we generate one and return it exactly once so you can hand it to the user over your own channel. Supply one and it must be at least 8 characters.external_ref— your own identifier for the customer (their id in your bot, say). Stored with the attribution and returned in the list.language— notification locale:ru,en,zh,fa. Defaults toru.
201 Created
{
"account_id": "9a1e...",
"email": "user@example.com",
"external_ref": "tg_123456789",
"generated_password": "...",
"attributed_at": "2026-08-31T10:00:00Z"
}
409 — the email is already registered. That account exists already and this endpoint will not attribute it to you; talk to us.
Requires the accounts:write scope.
List
GET /api/v1/reseller/accounts?limit=100
{
"accounts": [
{
"account_id": "9a1e...",
"email": "user@example.com",
"external_ref": "tg_123456789",
"attributed_at": "2026-08-31T10:00:00Z"
}
],
"count": 1
}
Single record
GET /api/v1/reseller/accounts/<account_id>
{
"account_id": "9a1e...",
"email": "user@example.com",
"external_ref": "tg_123456789",
"attributed_at": "2026-08-31T10:00:00Z",
"email_verified": true,
"status": "active",
"created_at": "2026-08-31T09:59:00Z"
}
Both need accounts:read. The same data is in the dashboard under "Customers".
Suspend and restore
DELETE /api/v1/reseller/accounts/<account_id>
Soft: the account moves to suspended, its tunnel users are disabled, and a live session dies on the next token refresh. Nothing is deleted — the customer stays in your list and the payment history stays intact.
200 OK
{
"account_id": "9a1e...",
"status": "suspended",
"tunnel_users_affected": 1,
"already_in_state": false
}
A repeat call returns already_in_state: true and the same 200 — a retry after a timeout needs no special handling.
Back again:
POST /api/v1/reseller/accounts/<account_id>/restore
Both need accounts:write. An account the user themselves deleted can be neither suspended nor restored and answers 409: deleting an account is the user's own right and it wins.
Grant a subscription
POST /api/v1/reseller/accounts/<account_id>/subscription
Content-Type: application/json
{ "plan_code": "base", "days": 7, "reason": "trial from the bot" }
200 OK
{
"account_id": "9a1e...",
"plan_code": "base",
"status": "active",
"end_at": "2026-09-08T10:00:00Z",
"days_granted": 7,
"budget": {
"per_grant_days_max": 31,
"monthly_days_max": 372,
"monthly_days_used": 7,
"monthly_days_left": 365
}
}
The extension counts from whichever is later: today, or the customer's current expiry. Seven days on top of twenty remaining is twenty-seven, not seven — an extension never shortens a live subscription and never back-dates a lapsed one.
This is not a sales channel. Revshare is computed from confirmed payments, and a subscription granted here creates no payment — so it earns no payout either. The endpoint exists for two things: a trial and a make-good. Selling goes through your checkout.
The trial budget
Grants have two ceilings: per grant and per calendar month. Both are echoed in every answer, refusals included.
400 grant_too_long— more days than one grant allows.409 grant_budget_exhausted— the monthly budget is spent.403 grants_disabled— granting is switched off for your account.
The defaults are 31 days per grant and 372 per month: a dozen monthly trials, or fifty weekly ones. If your funnel needs more, say so and we will raise it.
The ceiling is not bureaucracy. You provision the accounts with the same key, so "everyone gets dedicated for a year" is one loop on your side — and the traffic it entails is billed to us.
What the API does not do yet
Selling a subscription (payment goes through your checkout) and handing out a config or QR code through the partner key. The config reaches the customer in the app after sign-in.