OneProvider
Reseller API

Reseller API auth and limits

Bearer tokens, scopes, IP allowlist, rate limit, error codes, idempotency keys and pagination of the OneProvider reseller API, with examples.

Bearer tokens, scopes, IP allowlist, rate limit, error codes, idempotency keys and pagination of the reseller API.

All models, capabilities, and prices Documentation index for AI agents: https://oneprovider.dev/docs/llms.txt

Tokens

A token looks like rsk_ followed by 40 characters. Create it in the cabinet (reseller tab, “API & integrations”); the value is shown once, we store only a hash and the last 4 characters. You can have up to 10 active tokens and revoke any of them at any time.

http
Authorization: Bearer rsk_...
Server side only CORS is disabled. Never embed a token in a browser bundle or a mobile app: call the API from your backend. If a reseller loses access, all their tokens answer 403 reseller_disabled.

Scopes

A token carries a set of scopes. Scopes are independent: keys does not imply read. GET /me works with any valid token. Without the required scope the answer is 403 forbidden_scope.

Token scopes
ScopeWhat it unlocks
readRead: balance and transactions, pricing, models, customers, keys, orders, plans, stats, the action log GET /audit (every GET except codes and webhooks).
keysWrite: customers (including blocking), issuing, editing, pausing, topping up, rotating and deleting keys, POST /orders.
codesCode batches and the codes themselves (read, create, revoke, redeem). Codes are secrets, hence a separate scope.
plansCreate, edit and delete plans (reading plans needs read).
billingReseller balance top-ups: POST /balance/topups and the payment status.
webhooksManage webhooks, send a test, read the delivery log.
supportReserved for upcoming support endpoints.
botRead the state of the bots and cashiers: GET /bot and GET /payment-providers (no tokens in the answers). Bots are connected in the cabinet only.

Each method's scope is listed in the reference .

IP allowlist

A token can be limited to a list of IPv4/IPv6 addresses or CIDR ranges. A request from another address gets 403 ip_not_allowed. The list is set when the token is created.

Rate limit

20 requests per second per token. When exceeded: 429 rate_limited and a Retry-After header. Wait that many seconds and retry.

Errors

Every error has the same shape. The same id is sent in the X-Request-Id header: quote it to support.

json
{
"error": {
"code": "insufficient_balance",
"message": "Not enough free reseller balance for this key.",
"request_id": "req_..."
}
}

Branch on error.code, not on the message text.

Error codes
HTTPcodeMeaning
400invalidA field is missing or out of range.
400bad_requestThe request could not be parsed.
400idempotency_key_requiredIdempotency-Key header is missing on a money-spending method.
400invalid_urlThe webhook URL failed validation (https only, no IP literals or private networks).
400limit_below_spentThe new key limit is below what the key has already spent.
401unauthorizedThe token is missing, unknown or revoked.
403forbidden_scopeThe token lacks the required scope.
403ip_not_allowedThe request IP is not in the token's allowlist.
403reseller_disabledThe reseller lost access; every token answers like this.
403bannedThe account is banned.
404not_foundThe object does not exist or belongs to another reseller.
404key_not_foundThe key does not exist.
409insufficient_balanceThe amount does not fit into Free (available_usd), see the money rule.
409idempotency_key_reusedThe same Idempotency-Key was already used with a different request body: use a new key.
409fund_firstTop up the reseller balance first.
409not_activatedThe reseller cabinet is not activated yet.
409name_takenA key with this name already exists.
409key_limitThe key limit is reached.
409plan_limitThe plan limit (20) is reached.
409customer_limitThe customer limit (10,000) is reached.
409code_usedThe code is already redeemed.
409code_revokedThe code is revoked.
409external_order_id_conflictexternal_order_id was already used with different parameters.
409customer_existsA customer with this external_id already exists.
409customer_blockedThe customer is blocked: keys, orders and redemptions for them are rejected.
409token_limitThe active token limit (10) is reached.
409webhook_limitThe webhook limit (5) is reached.
429rate_limitedMore than 20 requests per second; wait Retry-After seconds.
501sandbox_not_implementedThe sandbox (rsk_test_...) is not implemented yet.
503provider_unavailableA payment or model provider is temporarily unavailable: retry later.

Idempotency

Methods that spend money require the Idempotency-Key header (1 to 128 characters); without it the answer is 400 idempotency_key_required. They are marked in the reference. Repeating a request with the same key (per reseller) never spends twice and returns the same object. Use a new key for each new payment or order; for POST /orders the identity is external_order_id.

bash
curl -s -X POST https://app.oneprovider.dev/partner/v1/keys \
-H "Authorization: Bearer $OP_PARTNER_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"name":"client-1","limit_usd":"10.00"}'

Store the idempotency key with your own order record so that after a network error you retry exactly the same request.

Pagination

List endpoints accept ?limit=1..100 (default 50) and &cursor=. The answer is {"items": [...], "next": "<cursor>"}; next is null on the last page. The cursor is opaque: pass it back as is.

bash
curl -s "https://app.oneprovider.dev/partner/v1/keys?limit=100&cursor=<next from the previous page>" \
-H "Authorization: Bearer $OP_PARTNER_TOKEN"

Sandbox

Test tokens rsk_test_... are coming soon. For now such a token gets 501 sandbox_not_implemented.

Last updated: 2026-10-21 Found a bug? @Oneproviderhelpbot