Skip to main content
REST · JSON API v1 X-API-Key

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.

Base URL https://api.waryashop.org/api/v1
01

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.

02

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.

03

Endpoints

Every path is relative to the base URL above. Each operation needs the scope named beside it.

Catalog

GET 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.

GET 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.

GET 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.

GET 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

POST 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".

POST 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.

GET https://api.waryashop.org/api/v1/orders/{orderId} orders:read

Get order status

For completed vouchers, delivery contains the redeem code.

GET https://api.waryashop.org/api/v1/orders orders:read

List orders

Paginated order history; newest first.

Account

GET https://api.waryashop.org/api/v1/balance balance:read

Wallet balance

Available and locked USD balances are returned as decimal strings.

GET https://api.waryashop.org/api/v1/transactions transactions:read

Wallet transactions

Paginated wallet ledger for reconciliation.

04

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)
05

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.

06

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"
07

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.

401 No key was sent
{
    "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"
    }
}
403 The key lacks the scope
{
    "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.

08

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"}'
09

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.created
  • order.processing
  • order.completed
  • order.failed
  • order.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 time
10

Get started

  1. 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. 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. 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. 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. 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. 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.