Sell Warya products through your own system
Connect your website, Telegram bot or reseller panel to Warya. Show your customers the products and prices, place their orders, and receive the final result automatically — over one REST API authenticated with a single X-API-Key header.
https://api.waryashop.org/api/v1
What the Warya API does
It is a reseller (wholesale) API. Your customers stay on your website or bot; your server talks to Warya in the background and manages the catalogue, the prices, the orders and the delivery through one key. You fund a USD wallet on your Warya account; each accepted order is charged to it, and the result comes back by polling a status endpoint or — if you give a callback URL — by a signed webhook.
Catalogue
Games, products, packages and current USD sale prices.
Player validation
Confirm a game account before you charge your customer.
Orders and wallet
Place orders, read their status, and read your balance and transactions.
Signed webhooks
Get each order event pushed to your own URL, verified with an HMAC signature.
Authentication
Every request carries your key in the X-API-Key request header. The key is a secret: send it in the header only, never in a URL, a query string or a log line — a key in a URL ends up in browser history, proxy logs and screenshots. The API trusts no forwarded header, so a key's optional IP allow-list cannot be spoofed.
The header
A request with no key, an unknown key, or a disabled or revoked key answers 401 — and nothing about the account is disclosed.
curl "https://api.waryashop.org/api/v1/games" \
-H "X-API-Key: YOUR_API_KEY"1 key per account
Create it on the API keys page once you are signed in. A key carries scopes, and it may restrict the addresses it answers from (up to 32 rules). You can regenerate, disable or revoke it at any time; every answer also carries X-Request-Id.
Endpoints
Every path is relative to the base URL above. Each operation needs the scope named beside it.
Catalog
https://api.waryashop.org/api/v1/games
catalog:read
List games and products
The code, English name, optional Persian name and Warya-hosted image URL. Paged; the default page is the whole list.
https://api.waryashop.org/api/v1/games/{code}/catalogue
catalog:read
Packages and sale prices
Use the exact catalogue_name returned here when creating an order. These are Warya sale prices in USD, as decimal strings. Only packages that can be priced right now are listed: an item that is no longer on sale, or one whose amount cannot be confirmed, is absent here rather than published at 0.000000, and naming it in an order is a 422.
https://api.waryashop.org/api/v1/games/{code}/fields
catalog:read
Required player fields
The identifiers this game's order form must collect, with meta.source and meta.freshness saying where the answer came from. Vouchers return an empty list.
https://api.waryashop.org/api/v1/games/{code}/servers
catalog:read
Servers and regions
An empty list is a verified answer: this game needs no server selection. A game whose list cannot be confirmed is a 503, never an empty list.
Checkout
https://api.waryashop.org/api/v1/player/validate
players:validate
Validate player
Confirm an account before charging your customer. A temporary failure is a 503 with Retry-After, never "invalid account".
https://api.waryashop.org/api/v1/orders
orders:write
Create order
Confirms the current Warya price, charges your wallet and starts fulfillment. If the price cannot be confirmed, the answer is a 503 and nothing is charged.
https://api.waryashop.org/api/v1/orders/{orderId}
orders:read
Get order status
For completed vouchers, delivery contains the redeem code.
https://api.waryashop.org/api/v1/orders
orders:read
List orders
Paginated order history; newest first.
Account
https://api.waryashop.org/api/v1/balance
balance:read
Wallet balance
Available and locked USD balances are returned as decimal strings.
https://api.waryashop.org/api/v1/transactions
transactions:read
Wallet transactions
Paginated wallet ledger for reconciliation.
Scopes
A key reaches only the endpoints its scopes cover. A request whose key lacks the scope an endpoint needs answers 403 and names the missing scope. The read-only set is granted by default; creating an order is a scope you must ask for.
| Scope | What it unlocks |
|---|---|
catalog:read |
Read games, packages, order fields and servers |
players:validate |
Validate a player account before placing an order |
balance:read |
Read the wallet balance |
transactions:read |
Read this account's own transactions |
orders:read |
Read this account's own orders |
orders:write |
Create orders (an Idempotency-Key header is required) |
Rate limits
These are the limits the API actually enforces, in requests per minute.
| Where | Per caller | Whole deployment |
|---|---|---|
| Any /api/v1 request, before the key is checked | 600/min | 6,000/min |
| Your key (per key, configurable) | 60/min (default, up to 6,000) | — |
POST https://api.waryashop.org/api/v1/player/validate |
60/min | 600/min |
Every answer carries X-RateLimit-Limit and X-RateLimit-Remaining. A refusal is a 429 and also carries Retry-After and X-RateLimit-Reset — read those before retrying; the same wait is repeated in the body as meta.retry_after.
Pagination
Listing endpoints are paged with page and per_page (alias limit). per_page is clamped to 1..100 on the order and transaction listings; the catalogue listings default to, and are capped at, 500 families per page, and meta.has_more tells you when there are more.
Every listing answer carries meta with current_page, last_page, per_page, total, count and request_id, so a client can walk pages and still quote one correlation id.
curl "https://api.waryashop.org/api/v1/orders?page=2&per_page=50" \
-H "X-API-Key: YOUR_API_KEY"Errors
Every answer — success or failure — is one JSON envelope with success, error_code, message and meta.request_id. Failures repeat the code and message under error. Quote meta.request_id in any support request.
{
"success": false,
"error": {
"code": "MISSING_API_KEY",
"message": "X-API-Key header is required."
},
"error_code": "MISSING_API_KEY",
"message": "X-API-Key header is required.",
"meta": {
"request_id": "01J8ZQ4M6W9K2N7P3R5T8V0XYZ"
}
}{
"success": false,
"error": {
"code": "SCOPE_FORBIDDEN",
"message": "This API key does not grant the \"catalog:read\" scope."
},
"error_code": "SCOPE_FORBIDDEN",
"message": "This API key does not grant the \"catalog:read\" scope.",
"meta": {
"request_id": "01J8ZQ4M6W9K2N7P3R5T8V0XYZ"
}
}Every status
| Status | Codes | Meaning |
|---|---|---|
| 200 / 201 | — |
Success. success: true, the endpoint's own keys, the same keys under data, and meta.request_id. |
| 400 | BAD_REQUEST / IDEMPOTENCY_KEY_REQUIRED |
The request could not be understood, or a key that requires an Idempotency-Key did not send one. |
| 401 | MISSING_API_KEY / INVALID_API_KEY / UNAUTHENTICATED |
No key, an unknown key, or a disabled or revoked key. Nothing else about the account is disclosed. |
| 402 | INSUFFICIENT_BALANCE |
The wallet cannot cover the order. Nothing was charged and no order was created. |
| 403 | SCOPE_FORBIDDEN / ACCOUNT_BLOCKED / IP_NOT_ALLOWED |
The key does not hold this endpoint's scope, the account is blocked, or the request came from outside the key's IP allow-list. |
| 404 | NOT_FOUND / GAME_NOT_FOUND / ORDER_NOT_FOUND |
Nothing is served at that address, that product is not on sale, or that order is not yours (another account's id is a 404, never a 403). |
| 405 | METHOD_NOT_ALLOWED |
The HTTP method is not the one this endpoint accepts. |
| 409 | IDEMPOTENCY_CONFLICT / CONFLICT |
The Idempotency-Key was already used by this account for a different order. Reuse it only with the identical body; a key another account happens to use is that account's own and never collides with yours. |
| 422 | VALIDATION_FAILED / INVALID_REQUEST |
A field is missing, malformed or not something we sell. errors names each field. |
| 429 Retry-After: 60s | RATE_LIMITED |
Too many requests. Wait for the Retry-After header (seconds) before retrying. |
| 500 | INTERNAL_ERROR / SERVICE_TEMPORARILY_UNAVAILABLE |
An unexpected failure on our side. meta.request_id identifies it in our logs; retry with backoff. |
| 503 Retry-After: 60s | CATALOG_TEMPORARILY_UNAVAILABLE / SERVICE_TEMPORARILY_UNAVAILABLE |
The catalogue or a price could not be confirmed, or the service is temporarily unavailable. Nothing was charged; RETRY_AFTER seconds are enough before asking again. |
Do not retry 401, 402, 403 or 422 without correcting the request. Back off exponentially for a 429 and for temporary 5xx answers.
Idempotency on order creation
Creating an order spends money, so POST /orders is idempotent through the Idempotency-Key request header — the only published mechanism. Send the same key with the same body to retry safely: a replay returns the first order, with idempotent_replay set to true, and charges nothing again. The same key with a different body is a 409 for your account; a key another account happens to use is that account's own and never collides with yours.
curl -X POST "https://api.waryashop.org/api/v1/orders" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Idempotency-Key: 8f3kd-order-1042" \
-H "Content-Type: application/json" \
-d '{"game":"pubgm","catalogue_name":"60 UC","player_id":"12345678"}'Customer webhooks
Send a callback_url when you create an order and Warya pushes each order event to it. Every delivery is signed, so you can trust it came from us and was not altered in transit. Retries follow the schedule below; a rotated secret keeps signing alongside its successor for a grace window so you can roll the verification over without dropping events.
Events
order.createdorder.processingorder.completedorder.failedorder.refunded
The payload names its event and carries api_version 2026-10-28.
Retries
Up to 5 attempts, with waits of 1, 5, 15, 60 minutes between them (the last wait repeats). A delivery that keeps failing is recorded for you to inspect.
Grace window after rotating the secret: 60 minutes.
The endpoint must be HTTPS; an http:// callback is refused. Redirects are not followed.
The signature
X-Warya-Signature: t=<unix>,v1=<hex>
v1 is HMAC-SHA256 over the string "{t}.{event_id}.{raw_body}" keyed with your webhook secret; the same t is repeated in X-Warya-Timestamp, and the event id in X-Warya-Event-Id. Verify by recomputing over the exact bytes you received. Answer 2xx to accept, and treat a repeat of the same X-Warya-Event-Id as already processed.
:raw_body = the exact bytes you received
t, v1 = the two values in X-Warya-Signature
expected = hmac_sha256(key = WEBHOOK_SECRET, message = t + "." + event_id + "." + raw_body)
ok = hash_equals(expected, v1) # compare in constant timeGet started
-
1. Create an account
Register on Warya and sign in. Every reseller account includes API keys, IP allow-lists and signed webhooks.
Create an account → -
2. Request reseller (API) access
The self-service reseller-access request flow is not live yet. Until it is, ask for API access through our support channel on Telegram and we will enable it for your account.
Contact support on Telegram → -
3. Create a key
Once you are signed in, open the API keys page and create your key. Pick the scopes you need; the read-only set is a good start.
-
4. Call /api/v1/games
Read the catalogue with your key. A request with no key answers the 401 body below — the real response captured from the live API:
curl "https://api.waryashop.org/api/v1/games" \ -H "X-API-Key: YOUR_API_KEY"With no key, the live API answers:
{ "success": false, "error": { "code": "MISSING_API_KEY", "message": "X-API-Key header is required." }, "error_code": "MISSING_API_KEY", "message": "X-API-Key header is required.", "meta": { "request_id": "01J8ZQ4M6W9K2N7P3R5T8V0XYZ" } } -
5. Place an order
Confirm a player, then post the order with an Idempotency-Key (the request shown in section 08). Here is the 201 it answers with:
{ "success": true, "order_id": "WR-20261010-8F3KD", "status": "processing", "charged": "0.950000", "currency": "USD", "idempotent_replay": false, "data": { "order_id": "WR-20261010-8F3KD", "status": "processing", "charged": "0.950000", "currency": "USD", "idempotent_replay": false }, "meta": { "request_id": "01J8ZQ4M6W9K2N7P3R5T8V0XYZ" } } -
6. Receive the webhook
Send a callback_url when you create the order; we push each order event to it, signed with the scheme above. If you would rather poll, read GET /orders/{orderId} and stop when the status is completed, failed or refunded.
Machine-readable contract
The same contract is published as an OpenAPI 3.1 document, reachable without a key. Generate a client from it, or import it into Postman or Insomnia.
https://api.waryashop.org/openapi.json
Questions? The official support channel is Telegram — @warya_game.