Skip to main content

Purchase flow

A purchase uses one universal route: POST /orders/create. The request fields depend on module.

Telegram Stars and Premium​

For Stars, send stars_amount (50–100000); for Premium, send months (3, 6 or 12). Both require the recipient's public Telegram username, not their numeric Telegram ID. An initial @ is accepted.

Use /recipient/check with the same username and module parameters before buying. The purchase checks the recipient again.

{
"api_key_id": 1,
"module": "stars",
"stars_amount": 50,
"username": "example_user",
"api_user_id": "customer-789",
"partner_order_id": "order-456"
}
{
"api_key_id": 1,
"module": "tg_premium",
"months": 3,
"username": "example_user",
"api_user_id": "customer-789",
"partner_order_id": "order-456"
}

Do not send nominal_id, quantity or recipient_data for these modules. Order history stores quantity=1; the number of Stars or subscription duration appears in stars_amount or months.

Topups and recipient fields​

  1. Select a product from /catalog/list with module=topups.
  2. Get its nominals through /catalog/details.
  3. Call /catalog/nominal with both item_id and nominal_id.
  4. Use the returned input_fields to collect the customer's details.

Example field:

{
"key": "server",
"label": "Server",
"type": "select",
"required": true,
"options": [
{"key": "eu", "label": "Europe"},
{"key": "asia", "label": "Asia"}
]
}

Use label for display and key for the request. Keys are case-sensitive and can differ between products. Do not hardcode playerId or server for every game.

Field typeValue sent in recipient_data
inputEntered text as a string
select, radio, checkOne selected options[].key as a string, not its label or an array

All values in recipient_data must be strings, including numeric-looking UIDs. Retrieve current fields and server choices when preparing a purchase.

{
"api_key_id": 1,
"module": "topups",
"nominal_id": 11,
"quantity": 1,
"recipient_data": {
"playerId": "123456789",
"server": "eu"
},
"api_user_id": "customer-789",
"partner_order_id": "order-456"
}

This example applies only to a nominal whose fields actually include these keys.

compliance_info is an optional topup-only field for nominals that accept additional payment information. It contains paymentMethod, playerIp and sellerName. Omit it unless required for your integration scenario and accepted for the nominal; an unsupported nominal returns HTTP 400. It does not replace recipient_data. If supplied, playerIp must be the customer's actual IP, not your server's address.

How to interpret recipient checks​

HTTP 200 alone does not confirm a recipient.

ResultAction
success=true, valid=trueRecipient verified
success=true, valid=false, supported=false, code=validation_unsupportedTopup verification is unavailable for this product; purchasing is allowed, but the customer's details remain unverified
valid=false with recipient_not_found, recipient_invalid, invalid_username, invalid_recipient_fieldsCorrect the recipient details
recipient_ineligible or premium_already_activeThe recipient cannot receive the selected product
success=falseThe check did not complete successfully; inspect code and retryable

Other returned codes include recipient_fields_unavailable, nominal_unavailable, price_unavailable and recipient_check_unavailable. message is explanatory text; use code for program logic. retryable=true applies to the check, not to replaying a purchase.

Codes​

Choose module=codes and a nominal_id from the catalog. Codes require no username, recipient data or recipient check.

{
"api_key_id": 1,
"module": "codes",
"nominal_id": 12,
"quantity": 1,
"api_user_id": "customer-789",
"partner_order_id": "order-456"
}

For topups and codes, quantity defaults to 1. The JSON schema accepts positive integers, but a nominal can impose a smaller quantity limit, and codes are subject to available stock. In particular, some nominals allow at most 10 units per order; exceeding their limit returns HTTP 400.

Price and balance​

Catalog prices are your API prices with the platform markup already included. /orders/quote calculates a total but does not reserve stock, check your balance or fix the price.

The purchase recalculates the amount and deducts it from the integration balance. You do not send a price or an acceptable maximum. The saved order's amount_usd is the actual charge.

If the balance is insufficient, the API returns HTTP 400 with detail="Insufficient balance"; no order is created and no amount is charged. A confirmed refusal after charging changes the order to refunded and returns the charged amount.

Order identifiers​

  • api_user_id — your customer's ID, a required string.
  • partner_order_id — optional ID of the order in your system.
  • order_id — AdaptGroup order ID returned by the API.

partner_order_id is not an idempotency key. Sending the same value again creates a new purchase. There is no request_id parameter.

Order statuses​

StatusMeaning
processingPurchase accepted; the final result is pending
completedPurchase completed successfully
refundedConfirmed refusal; the charged amount was returned
reviewThe result is not confirmed yet. Funds have not been automatically refunded; do not start another purchase as a retry
pendingA non-final status accepted by the history filter
failedA status accepted by the history filter; do not assume a refund from this value alone

The current creation flow returns processing, completed, refunded or review. A 200 response from /orders/create uses success=true for processing/completed and success=false for refunded/review.

By contrast, success=true from /orders/status only means that the saved order was found. Inspect order.status.

Lost response or timeout​

Do not automatically repeat /orders/create: every call is a separate purchase.

  • If you have order_id, request /orders/status.
  • If an HTTP 503 response contains detail.order_id, use that ID.
  • If the response was lost, search /orders/list by your partner_order_id and, if needed, api_user_id and creation period.
  • An empty list is not proof that an in-flight purchase was never accepted. If the result remains unclear, contact support before buying again.

An example uncertain creation response:

{
"detail": {
"message": "Order creation result unknown; check order status",
"order_id": 125,
"partner_order_id": "order-456"
}
}

Receive the result​

Use Order status or configure Webhooks in the dashboard.

For a completed codes order, /orders/status returns order.codes:

[
{"content": "EXAMPLE-CODE", "number": null, "pin": null},
{"content": null, "number": "EXAMPLE-CARD-NUMBER", "pin": "1234"}
]

A code may have content, a number, a PIN or a combination. Optional absent fields in the status response are serialized as null; webhooks may omit them. Other modules and non-completed orders return an empty array.

History lists omit issued codes and recipient data. Telegram notifications also do not include issued codes; they are available through the API and final webhook.

© 2026 AdaptGroup LLC. All rights reserved.
30 N Gould St Ste R, Sheridan, WY 82801, USA
Back to top