GAMES DROP Logo

GamesDrop.io API - Merchant Guide

[!WARNING] All offer groups in this documentation are PRODUCTION offers!
For testing purposes, please use Test Offer ID 999 only.
API Base URL: https://partner.gamesdrop.io

Welcome to the GamesDrop.io Partner API documentation! This guide provides everything you need to integrate your reseller platform with the GamesDrop network. By integrating, you gain access to our catalog of over 10,000 digital products, ranging from mobile operator top-ups to in-game currency for popular mobile games. Start here to streamline your product offerings and connect your customers to a world of digital goods.

Table of Contents

  1. Authorization
  2. Core Concepts
  3. Step-by-Step Integration Flow
  4. API Endpoints
  5. API Testing
  6. Integration Recommendations
  7. FAQ & Troubleshooting
  8. Support

Authorization

Getting a Token

How to get it

  1. Log in to your merchant account
  2. Create a new store
  3. After creating the store, you will receive a unique token
  4. Token format: abcdef1234567890abcdef1234567890

Authorization Methods

The system supports two authorization methods depending on the request type:

  1. Shop API Token:

    • Used for all product and order operations (creating orders, checking status, checking store balance).
    • Passed in the header: Authorization: <your_token>
    • Example: Authorization: abcdef1234567890abcdef1234567890
  2. JWT Token (for management):

    • Used for the merchant dashboard and top-up operations (Bank Transfer, PayPal, etc.).
    • Passed as a Bearer token: Authorization: Bearer <jwt_token>
    • Note: JWT tokens have a limited lifespan.

Token Security

  • 🔒 The token is confidential information
  • ⚠️ Do not share the token with third parties
  • 📝 The token cannot be recovered after creation
  • 🔄 If necessary, you can generate a new token (the old one will become invalid)

Core Concepts

Order Statuses

StatusDescriptionActions
SUBMITTEDOrder created and awaiting processingWait for transition to PROCESSING
PROCESSINGOrder is being processedWait for completion. For top-ups, this stage can take from 1 to 60 minutes.
COMPLETEDOrder successfully completedReceive key/product
CANCELEDOrder canceled without successful deliveryCheck the order data and create a new order if needed
FAILEDProvider or system errorStop polling; create a new order if needed
REFUNDOrder canceled and funds were returned to partner balanceFunds are returned to the partner balance

The message field is optional and is not guaranteed to be present in every response. For legacy compatibility, some order-status responses can expose an internal FAILED state as CANCELED; create-order can still return FAILED or REFUND directly.

Possible Errors

Error CodeDescriptionSolution
INVALID_TOKENInvalid authorization tokenCheck the token or get a new one
OFFER_NOT_FOUNDProduct not found or no accessCheck Product ID and access rights
TRANSACTION_DUPLICATEDuplicate transactionUse a new transaction_id
WRONG_PRICEIncorrect product priceUpdate price information
ORDER_NOT_FOUNDOrder not foundCheck Order ID
ORDER_NOT_PROCESSINGOrder is not yet processingWait for transition to PROCESSING
ORDER_NOT_COMPLETEDOrder is not yet completedWait for order completion
ORDER_ALREADY_CANCELEDOrder is already canceledCreate a new order
ORDER_ALREADY_REFUNDEDOrder is already refundedCreate a new order
SERVICE_UNAVAILABLEService temporarily unavailableRetry the request later
INVALID_REQUEST_BODYInvalid request formatCheck request structure
INSUFFICIENT_BALANCEInsufficient account balanceTop up balance or reduce purchase amount
BALANCE_UNAVAILABLEBalance temporarily unavailableRetry the request later

Supplier Settlement Compatibility

GamesDrop works with multiple suppliers. Some suppliers settle in fiat payment rails, some settle in USDT, and some support both. To prevent currency-mismatch risk, each partner account is assigned a balance profile and each supplier offer is assigned a settlement method.

Balance profiles:

ProfileMeaning
FIATThe partner is configured for fiat-based settlement.
USDTThe partner is configured for USDT-based settlement.
MIXEDThe partner can use both fiat and USDT supplier offers.

Offer settlement methods:

MethodMeaning
FIATThe supplier offer is settled through fiat rails.
USDTThe supplier offer is settled through USDT rails.
MIXEDThe supplier offer can be used by both fiat and USDT partners.

Compatibility rules:

Partner balance profileVisible / purchasable offer methods
FIATFIAT, MIXED
USDTUSDT, MIXED
MIXEDFIAT, USDT, MIXED

Only compatible offers are returned by catalog and product endpoints. If an offer is not compatible with your account profile, it is hidden from sync and find-one, and order creation is rejected if attempted directly.

This compatibility layer is separate from product price markup and currency conversion. GamesDrop returns the final purchase price available to your account; your system should always use the latest price returned by sync or find-one when creating an order.

Step-by-Step Integration Flow

Use these calls in this order for product catalog setup and order creation:

  1. Load the catalog

    • POST /api/v1/offers/sync
    • Send the optional ISO 3166-1 alpha-2 countryCode (for example, US or DE) to calculate activation compatibility. It does not filter the global catalog.
    • Use this response to create or update products in your system.
    • Store rows[].offerGroupId as the numeric GamesDrop offerId for all future calls.
    • Store product names, offer names, price, currency, stock flag, platform/region metadata, and required customer fields.
  2. Build your product page or checkout form

    • Show productName, offerGroupName, price, and currency.
    • If isRequiredGameUserId=true, ask the customer for a game/user/player ID.
    • If isRequiredGameServerId=true, fetch server values and ask the customer to select a server.
  3. Refresh the selected offer before payment/order creation

    • POST /api/v1/offers/find-one
    • Send the numeric GamesDrop offer group ID and the same optional countryCode.
    • Use the returned price as the confirmed GamesDrop purchase price for create-order.
  4. Fetch servers if required

    • If isRequiredGameServerId=true, call POST /api/v1/partner/product-offer/servers.
    • Show the response keys to the user as labels and submit the selected response value as gameServerId.
  5. Validate player data if required

    • If isRequiredGameUserId=true, call POST /api/v1/offers/check-game-data.
    • For games that also require a server, include gameServerId.
  6. Create the order

    • POST /api/v1/offers/create-order
    • Send offerId, latest GamesDrop price, unique transactionId, the same optional countryCode, and required customer fields.
    • For prepaid balance orders, send useBalance: true. If you are not integrating balance settlement, follow your agreed settlement mode with GamesDrop.
  7. Poll order status

    • POST /api/v1/offers/order-status
    • Use the order_id returned by create-order as orderId.
    • Poll until a terminal status: COMPLETED, CANCELED, FAILED, or REFUND.

What to Store From sync

FieldHow to use it
offerGroupIdStore as the GamesDrop offerId. Send this value to find-one, servers, check-game-data, and create-order.
productNameProduct title shown in your catalog.
offerGroupNameSellable denomination/variant shown to the customer.
price + currencyGamesDrop purchase price for your account. Refresh with find-one before creating an order.
inStockShow/sell only when true.
isRequiredGameUserIdIf true, your checkout must collect customer.gameUserId.
isRequiredGameServerIdIf true, call servers and collect customer.gameServerId.
platformCode, platformName, regionCode, regionNameOptional display/filter metadata. Use these fields instead of parsing region/platform from the product name.
regionalLimitations, excludedCountryCodes, countryCompatibilityCountry activation metadata for warnings. An excluded country is reported as blocked, but the API does not reject the order. ROW does not guarantee activation in every country.
selectedKeyFormat, availableKeyFormats, selectedKeyStockFulfillment format (text or image), formats available to the shop, and physical stock of the selected seller offer. Image keys require a separate shop opt-in.

create-order Parameter Rules

ParameterRequired whenNotes
offerIdAlwaysNumeric GamesDrop offer group ID from sync.
priceAlwaysLatest GamesDrop purchase price from find-one or sync; do not send your retail/customer-facing price.
transactionIdAlwaysUnique ID from your system. Reusing it returns the existing order or a duplicate error.
countryCodeRecommended for game keysISO 3166-1 alpha-2 activation country. If your shop has a default country, it is used when this field is omitted.
keyFormatImage-key orders onlySend image only when find-one returns selectedKeyFormat: "image". Existing requests without this field remain text-only.
useBalanceBalance/prepaid flowUse true for prepaid balance orders. Omit for test offer 999 and for settlement flows agreed separately.
customer.emailOptionalUsed for tracking/support.
customer.gameUserIdWhen isRequiredGameUserId=truePlayer ID, game account ID, Telegram user ID, or similar delivery identifier.
customer.gameServerIdWhen isRequiredGameServerId=trueUse the value returned by servers, for example os_euro.

For key/gift-card products where isReturnDataForCustomer=true and no player fields are required, you usually only send offerId, price, transactionId, and optional customer.email.

API Endpoints

Balance Management

Check Balance

You can check your account's current balance using your Shop API token.

HTTP
GET /api/v1/partner/balance
Authorization: {{token}}

[!NOTE] The /api/v1/balance endpoint requires JWT authorization and is primarily used for the web interface. For shop-token API integrations, use /api/v1/partner/balance.

Response:

JSON
{
  "balance": 500.25,
  "draft_balance": 0.00,
  "is_postpaid": false,
  "balance_profile": "USDT",
  "currency": {
    "id": 3,
    "code": "USD"
  },
  "partner_id": 123,
  "shop_id": 70,
  "shop_name": "EasyPay",
  "owner_id": 392
}

Response Fields:

KeyTypeDescription
balancenumberCurrent available balance
draft_balancenumberReserved funds (processing)
is_postpaidbooleantrue: postpaid account. false: prepaid account.
balance_profileFIAT | USDT | MIXEDDetermines which supplier offer settlement methods are visible and purchasable.
partner_idnumberUnique ID of your partner account
shop_idnumberShop ID resolved from the token
shop_namestringShop name resolved from the token
owner_idnumberShop owner user ID
currencyobjectBalance currency information

Transaction History

HTTP
GET /api/v1/balance/transactions?page=1&limit=20
Authorization: {{passwordHash}}

[!NOTE] This is a dashboard/JWT endpoint, not part of the basic shop-token order flow. Use it only if you integrate dashboard-level account management.

Response:

JSON
{
  "transactions": [
    {
      "id": 12,
      "amount": -75.00,
      "type": "PURCHASE",
      "description": "API Purchase - Virtual credits",
      "balanceAfter": 425.00,
      "createdAt": "2025-07-28T05:21:46.121Z"
    },
    {
      "id": 11,
      "amount": -50.00,
      "type": "PURCHASE", 
      "description": "Test Purchase - Mobile game credits",
      "balanceAfter": 500.00,
      "createdAt": "2025-07-28T05:16:23.718Z"
    }
  ],
  "total": 25
}

Request fields description:

KeyValueNotes
pagenumberPage number (default: 1)
limitnumberRecords per page (default: 20)

Response fields description:

KeyValueNotes
transactionsarrayList of transactions
transactions[].idnumberUnique transaction ID
transactions[].amountnumberOperation amount (negative for debits)
transactions[].typestringOperation type (DEPOSIT, PURCHASE, REFUND)
transactions[].descriptionstringOperation description
transactions[].balanceAfternumberBalance after operation
transactions[].createdAtstringOperation date and time (UTC)
totalnumberTotal number of transactions

Getting Product Information

HTTP
POST /api/v1/offers/find-one
Authorization: {{token}}

{
  "offerId": 1001,
  "offerGroupId": 1001,
  "productOfferId": 77881,
  "providerProductId": "620b94639e44a1f3767893cc",
  "providerOfferId": "66e170989a659600013da9f3",
  "countryCode": "DE"
}

offerId in this request must be the numeric GamesDrop offer group ID returned as rows[].offerGroupId by sync. Do not pass provider external IDs or string product codes.

Response:

JSON
{
  "offerId": 1001,
  "productName": "Total War: WARHAMMER III PC Steam CD Key",
  "offerName": "Total War: WARHAMMER III PC Steam CD Key",
  "platformCode": "steam",
  "platformName": "Steam",
  "regionCode": "ROW",
  "regionName": "RoW",
  "regionalLimitations": "Rest of the world (RoW) - custom",
  "excludedCountryCodes": ["KP", "JP", "CN", "HK", "KR", "TW"],
  "countryCompatibility": "allowed",
  "count": 1,
  "available": 4,
  "sellerOfferCount": 4,
  "selectedTextStock": 39,
  "price": 10.57,
  "currency": "USD",
  "priceBreakdown": {
    "providerPrice": 8.99,
    "providerCurrency": "EUR",
    "addedPercent": 3,
    "fxRate": 1.1418132,
    "price": 10.57,
    "currency": "USD"
  },
  "quoteCheckedAt": "2026-07-16T12:00:00Z",
  "quoteExpiresAt": "2026-07-16T12:00:45Z",
  "isPriceFresh": true,
  "settlementMethod": "MIXED",
  "balanceProfile": "MIXED",
  "isSettlementCompatible": true,
  "isReturnDataForCustomer": true,
  "isRequiredGameUserId": false,
  "isRequiredGameServerId": false
}

Request fields description:

KeyValueNotes
offerIdnumberNumeric GamesDrop offer group ID from sync; must be a number, not a string
countryCodestringOptional ISO 3166-1 alpha-2 activation country.

Response fields description:

KeyValueNotes
offerId, offerGroupIdnumberStable GamesDrop offer group ID. Both fields have the same value.
productOfferIdnumberInternal seller-offer ID for diagnostics. Never send it as offerId.
providerProductId, providerOfferIdstringExact provider identifiers for diagnostics. Never send them as offerId.
productNamestring-
offerNamestring-
platformCodestringNormalized platform code when available.
platformNamestringDisplay platform name when available.
regionCodestringNormalized region code when available, e.g. GLB, EU, ROW, CIS, US, NA, EMEA, OTH.
regionNamestringDisplay region name when available, e.g. Global, Europe, RoW, CIS.
regionalLimitationsstringProvider's broad regional limitation label.
excludedCountryCodesstring[]ISO country codes where activation is blocked. These exclusions take priority over the broad region.
countryCompatibilityallowed | blocked | unverified | not_checkedResult for the requested/default country.
countnumberRequested order quantity (currently 1).
available, sellerOfferCountnumberNumber of eligible seller offers, not number of keys.
selectedTextStocknumberText-key stock of the selected exact seller offer.
selectedKeyFormattext | imageActual fulfillment format of the selected seller offer.
availableKeyFormatsstring[]Formats currently available and enabled for your shop.
selectedKeyStocknumberPhysical stock of the selected exact seller offer. selectedTextStock is 0 for image keys.
pricenumber-
currencyKZT, USD, RUB, etc.Pricing currency code
priceBreakdownobjectProvider price/currency, partner markup, FX rate, and final partner price. MIXED does not add a hidden fee.
quoteCheckedAt, quoteExpiresAt, isPriceFreshstring, string, booleanProvider quote freshness. Call find-one immediately before order creation.
settlementMethodFIAT | USDT | MIXEDSettlement method of the selected supplier offer.
balanceProfileFIAT | USDT | MIXEDYour partner balance profile.
isSettlementCompatiblebooleanAlways true for returned offers. Incompatible offers are hidden.
isReturnDataForCustomerbooleantrue: Key/Gift Card (will return key). false: Direct Top-up (instant credit).
isRequiredGameUserIdbooleantrue if customer.gameUserId is required for order creation.
isRequiredGameServerIdbooleantrue if customer.gameServerId is required for order creation.

Use the offerGroupId from sync or the same offerId returned by find-one when creating an order. offerId and offerGroupId are always the same stable GamesDrop group ID. Never replace them with productOfferId or provider IDs.

Catalog Synchronization (B2B Sync)

The Sync endpoint is specifically designed for partners who need to regularly update their local product databases. It returns a flattened, highly optimized list of available offers, current prices (with your markup applied), and stock availability in a single request.

The response includes only offers compatible with your balanceProfile. For example, a USDT partner will not receive fiat-only supplier offers in this feed.

For platform and region display, use platformCode/platformName and regionCode/regionName from the response. Do not infer Global from a product name that only says PC Steam CD Key. ROW means a broad Rest of World SKU, but activation can still be unavailable in excludedCountryCodes. Send countryCode to calculate a warning status; the response remains part of the global catalog.

HTTP
POST /api/v1/offers/sync
Authorization: {{token}}

{
  "limit": 1000,
  "page": 1,
  "category": "Top Up",
  "search": "genshin",
  "countryCode": "DE"
}

Request fields description:

KeyValueNotes
limitnumberElements per page (max 5000). Default: 1000.
pagenumberPage number. Default: 1.
searchstringOptional text search by product name.
categorystringOptional filter by category (e.g., Top Up, Gift Cards). Legacy aliases TOP_UP and GIFT_CARD are also accepted.
countryCodestringOptional ISO 3166-1 alpha-2 activation country. It calculates countryCompatibility but never removes rows from the global catalog.

Response:

JSON
{
  "count": 1250,
  "rows": [
    {
      "productId": 5,
      "productName": "PUBG Mobile",
      "offerGroupId": 101,
      "offerGroupName": "60 UC",
      "platformCode": "mobile",
      "platformName": "Mobile",
      "regionCode": "GLB",
      "regionName": "Global",
      "regionalLimitations": "REGION FREE",
      "excludedCountryCodes": [],
      "countryCompatibility": "allowed",
      "productOfferId": 77881,
      "providerProductId": "620b94639e44a1f3767893cc",
      "providerOfferId": "66e170989a659600013da9f3",
      "sellerOfferCount": 4,
      "selectedTextStock": 39,
      "price": 0.99,
      "currency": "USD",
      "isPriceFresh": true,
      "inStock": true,
      "isRequiredGameUserId": true,
      "isRequiredGameServerId": false
    }
  ]
}

Response fields description:

KeyValueNotes
countnumberTotal number of items matching filters.
rows[].offerGroupIdnumberThe ID to pass as offerId when creating an order.
rows[].productOfferId, rows[].providerProductId, rows[].providerOfferIdnumber, string, stringDiagnostic seller/provider IDs. Do not use them as offerId.
rows[].productNamestringProduct name.
rows[].offerGroupNamestringSellable variant name.
rows[].platformCodestringNormalized platform code when available.
rows[].platformNamestringDisplay platform name when available.
rows[].regionCodestringNormalized region code when available, e.g. GLB, EU, ROW, CIS, US, NA. Do not infer Global from a name that only says PC Steam CD Key.
rows[].regionNamestringDisplay region name when available, e.g. Global, Europe, RoW, CIS, North America.
rows[].regionalLimitationsstringProvider's broad regional limitation label.
rows[].excludedCountryCodesstring[]ISO country codes where activation is blocked.
rows[].countryCompatibilityallowed | blocked | unverified | not_checkedWarning status for the requested/default activation country. It does not block ordering.
rows[].pricenumberFinal cost required to purchase the item (in your currency).
rows[].priceBreakdownobjectProvider price, configured partner markup, FX rate and final price.
rows[].sellerOfferCountnumberEligible seller offers. This is not key stock.
rows[].selectedTextStocknumberConfirmed text-key stock for the selected offer.
rows[].quoteCheckedAt, rows[].quoteExpiresAt, rows[].isPriceFreshmixedSnapshot freshness. sync can become stale; find-one is authoritative before checkout.
rows[].inStockbooleantrue if at least one supplier is currently active.
rows[].isRequiredGameUserIdbooleantrue if the product requires a player identifier.
rows[].isRequiredGameServerIdbooleantrue if the product requires a server identifier.

Creating an Order

HTTP
POST /api/v1/offers/create-order
Authorization: {{token}}

{
  "offerId": 1001,
  "price": 560.10,
  "transactionId": "test112321124214",
  "countryCode": "DE",
  "keyFormat": "text",
  "useBalance": true,
  "customer": {
    "email": "user@gmail.com",
    "gameUserId": "52357322414"
  }
}

Request fields description:

KeyValueNotes
offerIdnumberNumeric GamesDrop offer group ID from sync; must be a number, not a string
pricenumberThe latest GamesDrop purchase price returned by find-one or sync. Do not send your retail/customer-facing price.
transactionIdstringUnique transaction identifier in your system
countryCodestringOptional ISO 3166-1 alpha-2 activation country. Use the same value as in sync and find-one.
keyFormattext | imageOptional. Omitting it keeps text-only behavior. image requires shop opt-in.
useBalancebooleanUse true for prepaid balance orders. Test orders with offer 999 can omit it.
customerobjectCustomer and delivery data
customer.emailstringOptional field for tracking
customer.gameUserIdstringRequired when isRequiredGameUserId=true
customer.gameServerIdstringRequired when isRequiredGameServerId=true

Price Confirmation and Supplier Selection

The price field in create-order is a price confirmation. It must match the GamesDrop price that your system received from find-one or sync before creating the order.

Do not send the price shown to your end customer. Your storefront markup is managed on your side and is not part of the GamesDrop order request.

For products backed by multiple suppliers, GamesDrop may select the best available supplier at order time. The order will only be accepted if the confirmed price still covers the required GamesDrop purchase price. If supplier prices changed or the cheapest supplier became unavailable and the confirmed price is no longer valid, the API returns WRONG_PRICE, OFFER_NOT_FOUND, OUT_OF_STOCK, or SERVICE_UNAVAILABLE depending on the situation. In this case, refresh the offer price and ask the customer to retry the purchase.

Response:

JSON
{
  "order_id": 10222502,
  "count": 1,
  "price": 560.10,
  "currency": "RUB",
  "offer_id": 1001,
  "product_name": "PUBG MOBILE GIFT",
  "offer_name": "60 UC",
  "status": "COMPLETED",
  "is_return_data_for_customer": true,
  "selected_key_format": "text",
  "key": "001434249936"
}

Response fields description:

KeyValueNotes
order_idnumber-
countnumberNumber of product units
pricenumber-
currencyKZT | USD | EUR | RUB-
offer_idnumberGamesDrop offer group ID used for the order
product_namestring-
offer_namestring-
statusstringSUBMITTED, PROCESSING, COMPLETED, CANCELED, FAILED, REFUND
is_return_data_for_customerbooleantrue: Key product. false: Direct top-up.
keystring (optional)Activation Code/PIN. Present ONLY if is_return_data_for_customer: true AND status: "COMPLETED".
selected_key_formattext | imageActual fulfillment format.
fulfillment_itemsobject[] (optional)For image keys contains format, mimeType, fileName, contentBase64, and provider IDs. Returned to the authorized shop only after COMPLETED; base64 is never copied into key.

For selected_key_format: "image", decode fulfillment_items[].contentBase64 using its mimeType and deliver the unchanged original image to the customer. Do not treat OCR as the source of truth and never log base64 or serial values.

[!NOTE] create-order currently returns snake_case field names. order-status returns camelCase field names for legacy compatibility.

Check Order Status

HTTP
POST /api/v1/offers/order-status
Authorization: {{token}}

{
  "orderId": 10222502
}

Request fields description:

KeyValueNotes
orderIdnumberGamesDrop order ID returned as order_id by create-order

[!NOTE] The short /api/v1/offers/order-status endpoint currently checks by orderId. If you need lookup by transactionId, use the legacy endpoint POST /api/v1/partner/product-offer/status.

Response:

JSON
{
  "orderId": 10222502,
  "count": 1,
  "price": 560.10,
  "currency": "RUB",
  "offerId": 1001,
  "productName": "PUBG MOBILE GIFT",
  "offerName": "60 UC",
  "status": "COMPLETED",
  "isReturnDataForCustomer": true,
  "key": "001434249936",
  "createdAt": "2024-05-28 10:08:04.296+00"
}

Response fields description:

KeyValueNotes
orderIdnumber-
countnumberNumber of product units
pricenumber-
currencyKZT | USD | EUR | RUB-
offerIdnumberGamesDrop offer group ID
productNamestring-
offerNamestring-
statusstringCurrent status: SUBMITTED, PROCESSING, COMPLETED, CANCELED, FAILED, REFUND
messagestring (optional)Additional status details if available; not guaranteed.
isReturnDataForCustomerbooleantrue: Key product. false: Direct top-up.
keystring (optional)Activation Code/PIN. Present ONLY if isReturnDataForCustomer: true AND status: "COMPLETED".
createdAtstringUTC +0

[!NOTE] For legacy compatibility, some internal FAILED states can be returned as CANCELED by order-status. Treat both as terminal unsuccessful statuses.

Server List Discovery

For products that require a server identifier (isRequiredGameServerId: true), you can fetch the list of available servers to display in your UI.

HTTP
POST /api/v1/partner/product-offer/servers
Authorization: {{token}}

{
  "offerId": 1001
}

Response:

JSON
{
  "Europe": "os_euro",
  "America": "os_usa",
  "Asia": "os_asia"
}

Note: Use the key (e.g., "Europe") as the display label and the value (e.g., "os_euro") as the gameServerId when creating an order.

Player Validation

HTTP
POST /api/v1/offers/check-game-data
Authorization: {{token}}

{
  "offerId": 1001,
  "gameUserId": "52357322414",
  "gameServerId": "1234"
}

Request fields description:

KeyValueNotes
offerIdnumberImportant: must be a number, not a string
gameUserIdstringPlayer identifier
gameServerIdstringServer identifier (if required)

Successful response:

JSON
{
  "status": "VALID",
  "gameUserLogin": "JJJ"
}

Successful response fields description:

KeyValueNotes
status"VALID"Player is valid
gameUserLoginstringPlayer login

Error response:

JSON
{
  "status": "INVALID"
}

Error response fields description:

KeyValueNotes
status"INVALID"Player is invalid

API Testing

Test Product

For testing API integration, a special test product is available:

  • Product ID: 999
  • Name: Steam US
  • Offer Name: TEST OFFER GROUP
  • Price: use the value returned by find-one
  • Returns Key: Yes

Example request for test product information:

HTTP
POST /api/v1/offers/find-one
Authorization: {{token}}

{
  "offerId": 999
}

Example creating test order:

HTTP
POST /api/v1/offers/create-order
Authorization: {{token}}

{
  "offerId": 999,
  "price": 21.79,
  "transactionId": "test_123456",
  "customer": {
    "email": "test@example.com",
    "gameUserId": "123456789"
  }
}

Before creating a test order, call find-one for offerId: 999 and copy the returned price into create-order. Do not hardcode the example price, because the value can differ by shop currency and pricing settings.

Test product features:

  • Returns a completed test order when the test offer is enabled for your shop
  • Generates test activation key
  • Creates order with COMPLETED status
  • Player validation always returns VALID for test product
  • Works in test mode without a provider order

Balance Management Examples

Check balance before purchase:

JAVASCRIPT
// 1. Check current balance
const balanceResponse = await fetch('/api/v1/partner/balance', {
  headers: { 'Authorization': 'your-token-here' }
});
const { balance } = await balanceResponse.json();

// 2. Get product information
const offerResponse = await fetch('/api/v1/offers/find-one', {
  method: 'POST',
  headers: { 
    'Authorization': 'your-token-here',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ offerId: 1001 })
});
const { price } = await offerResponse.json();

// 3. Check sufficient funds
if (balance >= price) {
  // Create order
  console.log('Sufficient balance, creating order...');
} else {
  console.log('Insufficient balance, need to top up');
}

Get transaction history:

JAVASCRIPT
const transactionsResponse = await fetch('/api/v1/balance/transactions', {
  headers: { 'Authorization': 'Bearer your-dashboard-jwt-token' }
});
const { transactions, total } = await transactionsResponse.json();

console.log(`Total transactions: ${total}`);
transactions.forEach(tx => {
  console.log(`${tx.createdAt}: ${tx.type} ${tx.amount} (Balance: ${tx.balanceAfter})`);
});

Integration Recommendations

💰 Balance Management

  • Regularly check balance before large purchases
  • Keep track of transactions for reconciliation with your system
  • Notify users about need to top up when funds are insufficient
  • Use pagination when requesting transaction history

🔍 Before Creating an Order

  • Get up-to-date product information
  • Check balance to ensure sufficient funds
  • Check player validity (for direct top-up)

📝 When Creating an Order

  • Use a unique transactionId
  • Specify the latest GamesDrop price returned by find-one or sync
  • Do not send your customer-facing retail price in the price field
  • Specify offerId as number, not string
  • Fill in all required fields for the product type

✅ After Creating an Order

  • Save the orderId
  • Check the order status
  • Upon COMPLETED status, receive the key/product

⚠️ When Errors Occur

  • Check the token
  • Ensure data correctness and request format
  • Create a new order if necessary

FAQ & Troubleshooting

Product Types (Top-up vs Keys)

Our system supports two main types of delivery. You can distinguish them using the isReturnDataForCustomer field in the Product Info response.

1. Gift Cards / Keys (isReturnDataForCustomer: true)

  • What it is: The customer receives a digital code, PIN, or link to activate manually.
  • Flow:
    1. create-order returns status: "COMPLETED" and a key field.
    2. You display this key to your customer.
  • Example: Steam Wallet Code, PUBG UC usage code.

2. Direct Top-up (isReturnDataForCustomer: false)

  • What it is: Funds are credited directly to the player's game account. No code is returned.
  • Flow:
    1. You MUST provide gameUserId (and sometimes gameServerId) in the create-order request.
    2. We recommend validating the ID first using /check-game-data.
    3. create-order returns the current status. Poll order-status until the order becomes COMPLETED or CANCELED.
  • Example: Mobile Legends Diamonds top-up by User ID.

Currency Conversion

  • Your Partner Balance: Always maintained in USD.
  • Product Prices: Can be in various currencies (RUB, KZT, EUR, etc.) depending on the region.
  • How it works:
    • You do not need to convert funds manually.
    • When you purchase a product priced in RUB (e.g., 500 RUB), the system calculates the equivalent in USD (e.g., $5.50) and deducts it from your USD balance.
    • Ensure you have enough USD balance to cover the converted amount.
  • Supplier settlement compatibility: Your catalog is filtered by your balanceProfile before pricing is returned. This prevents fiat-only supplier offers from being sold to USDT-only partners, and vice versa.
  • No manual FX surcharge: GamesDrop does not require you to add an extra conversion-loss percentage in the API request. Use the latest price returned by find-one or sync. Any configured B2B markup is already included in the returned GamesDrop purchase price.

Common Questions

"I see a parameter 'it' mentioned, what is it?"

There is no parameter named it in our API. This is likely a typo for id or a misunderstanding.

  • Product identifier is offerId.
  • Transaction identifier is transactionId.
  • User identifier is gameUserId.

"How do I validate a Player ID?"

Use the POST /api/v1/offers/check-game-data endpoint. It will return VALID and the player's nickname if the ID is correct. This is highly recommended for Direct Top-up products to avoid errors.

Support

If you have any questions, please contact technical support:

Error Handling Recommendations

🔍 Pre-Request Checks

  • Token validation
  • Product ID verification
  • Price accuracy
  • Uniqueness of transaction_id
  • Correct data format (especially offerId as number)

🛠 Response Handling

  • Handle all error codes
  • Log errors
  • Implement retry mechanism

📊 Order Management

  • Save order IDs
  • Monitor statuses
  • Update data

Telegram Stars

🌟 GamesDrop has integrated Telegram Stars support! Now you can send Telegram Stars to users through the same standard API endpoints.

Available Telegram Stars Products

For the Partner API, offerId must be the numeric GamesDrop offer group ID returned by sync or find-one. The string IDs below are internal provider product identifiers and are shown only for reference.

Internal Provider Product IDNumber of StarsDynamic Price
telegram_stars_5050Based on TON exchange rate
telegram_stars_100100Based on TON exchange rate
telegram_stars_500500Based on TON exchange rate
telegram_stars_10001000Based on TON exchange rate

How pricing works:

  • A6-Gateway gets the current TON/USD rate from kernel currency API
  • Price is calculated based on Fragment.com coefficients (100 Stars ≈ 0.3 TON)
  • Prices are updated in real-time with each request

Using the Same Endpoints

1. Getting Telegram Stars information:

HTTP
POST /api/v1/offers/find-one
Authorization: {{token}}

{
  "offerId": 1001
}

Response:

JSON
{
  "offerId": 1001,
  "productName": "Telegram Stars",
  "offerName": "100 Stars",
  "count": 1,
  "price": 0.77,
  "currency": "USD",
  "isReturnDataForCustomer": true
}

2. Creating an order for Telegram Stars:

HTTP
POST /api/v1/offers/create-order
Authorization: {{token}}

{
  "offerId": 1001,
  "price": 0.77,
  "transactionId": "tg_stars_12345",
  "customer": {
    "email": "user@example.com",
    "gameUserId": "143594291"
  }
}

Create-order response:

JSON
{
  "order_id": 10228901,
  "count": 1,
  "price": 0.78,
  "currency": "USD",
  "offer_id": 1001,
  "product_name": "Telegram Stars",
  "offer_name": "100 Stars",
  "status": "SUBMITTED",
  "is_return_data_for_customer": false
}

Use order-status to track final delivery:

JSON
{
  "orderId": 10228902,
  "transactionId": "tg_stars_12345",
  "count": 1,
  "price": 0.78,
  "currency": "USD",
  "offerId": 1001,
  "productName": "Telegram Stars",
  "offerName": "100 Stars",
  "status": "CANCELED",
  "isReturnDataForCustomer": false,
  "createdAt": "2025-08-26T12:30:15.234Z"
}

🔑 Important Telegram Stars Features

gameUserId requirements:

  • gameUserId must be a numeric Telegram User ID for order creation
  • Get User ID in two ways:
    1. 📞 Via @userinfobot in Telegram
    2. 🆕 Via our API validation (see section below)
  • Example: "gameUserId": "143594291"
  • ❌ NOT username (@username) for order creation

Delivery statuses:

  • COMPLETED - Stars successfully delivered to user
  • CANCELED - Failed to deliver (invalid user ID, blocked bot, etc.)

Typical delivery errors:

  • "user not found" - invalid Telegram User ID
  • "STARGIFT_INVALID" - user cannot receive Stars (restrictions)
  • "bot was blocked by user" - user blocked the bot

🆔 Telegram User Validation

🎯 New endpoint for validating username and getting User ID!

If your users only know their @username, use this endpoint to get User ID before creating an order.

Validation endpoint:

HTTP
POST https://gamesdrop.io/api/aggregator/a6/telegram/user-info
Authorization: {{token}}
Content-Type: application/json

{
  "username": "@igoryan34"
}

Response on successful validation:

JSON
{
  "valid": true,
  "username": "igoryan34",
  "userInfo": {
    "id": 143594291,
    "first_name": "Igor",
    "username": "igoryan34",
    "photo_url": "AQADAgADRKgxGzMTjwgABCAI..."
  },
  "message": "User account verified successfully"
}

Response when User ID cannot be obtained:

JSON
{
  "valid": true,
  "username": "igoryan34",
  "userInfo": {
    "username": "igoryan34",
    "first_name": "igoryan34"
  },
  "message": "Username format is valid, but user details are not publicly available. Full verification requires user interaction with the bot."
}

Request fields description:

KeyValueNotes
usernamestringTelegram username with @ or without

Response fields description:

KeyValueNotes
validbooleanAlways true for correct usernames
usernamestringCleaned username without @
userInfo.idnumber🎯 User ID for orders (if available)
userInfo.first_namestringUser's first name
userInfo.usernamestringUser's username
userInfo.photo_urlstringAvatar URL (if available)
messagestringValidation result description

⚠️ Important features:

  • Endpoint returns User ID only if user has interacted with the bot
  • If userInfo.id is missing, ask user to message @gamesdrop_api_bot
  • Can pass as "@username" or "username"
  • Can also pass User ID to get additional information

📱 Developer Integration Examples

Complete flow example with username validation in JavaScript:

JAVASCRIPT
// 1. Validate username and get User ID
const validateTelegramUser = async (username) => {
  const response = await fetch('https://gamesdrop.io/api/aggregator/a6/telegram/user-info', {
    method: 'POST',
    headers: {
      'Authorization': 'your-token-here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ username })
  });

  const result = await response.json();

  if (result.valid && result.userInfo && result.userInfo.id) {
    return {
      userId: result.userInfo.id,
      firstName: result.userInfo.first_name,
      username: result.userInfo.username
    };
  } else {
    throw new Error('Unable to get User ID. Please ask user to message @gamesdrop_api_bot first.');
  }
};

// 2. Resolve numeric offer group ID from your synced catalog
const getTelegramStarsOfferGroupId = async (starsAmount) => {
  const response = await fetch('/api/v1/offers/sync', {
    method: 'POST',
    headers: {
      'Authorization': 'your-token-here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ limit: 5000, page: 1, search: 'Telegram Stars' })
  });
  const catalog = await response.json();
  const row = catalog.rows.find((item) =>
    item.productName?.includes('Telegram Stars') &&
    item.offerGroupName?.includes(String(starsAmount))
  );
  if (!row) {
    throw new Error(`Telegram Stars offer group not found for ${starsAmount} Stars`);
  }
  return row.offerGroupId;
};

// 3. Get current price
const getStarsPrice = async (starsAmount) => {
  const offerGroupId = await getTelegramStarsOfferGroupId(starsAmount); // Resolve from your synced catalog
  const response = await fetch('/api/v1/offers/find-one', {
    method: 'POST',
    headers: {
      'Authorization': 'your-token-here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      offerId: offerGroupId
    })
  });
  return response.json();
};

// 4. Send Stars to user
const sendStarsByUsername = async (usernameOrId, starsAmount) => {
  // First get User ID if username was passed
  let userId;
  if (isNaN(usernameOrId)) {
    // This is username, need to get User ID
    const userInfo = await validateTelegramUser(usernameOrId);
    userId = userInfo.userId;
    console.log(`✅ Validated user: ${userInfo.firstName} (@${userInfo.username}) - ID: ${userId}`);
  } else {
    // This is already User ID
    userId = parseInt(usernameOrId);
  }

  // Get price
  const { offerId, price } = await getStarsPrice(starsAmount);

  // Create order
  const response = await fetch('/api/v1/offers/create-order', {
    method: 'POST',
    headers: {
      'Authorization': 'your-token-here',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      offerId: offerId,
      price: price,
      transactionId: `stars_${Date.now()}`,
      customer: {
        email: "optional@example.com",
        gameUserId: userId.toString()
      }
    })
  });

  const result = await response.json();

  if (result.status === 'COMPLETED') {
    console.log(`✅ Successfully sent ${starsAmount} Stars to User ID ${userId}`);
    return result;
  } else {
    console.error(`❌ Failed to send Stars: ${result.message}`);
    throw new Error(result.message);
  }
};

// Usage:
// With username:
sendStarsByUsername('@igoryan34', 100)
  .then(order => console.log('Order created:', order.orderId))
  .catch(error => console.error('Delivery failed:', error));

// With User ID:
sendStarsByUsername('143594291', 100)
  .then(order => console.log('Order created:', order.orderId))
  .catch(error => console.error('Delivery failed:', error));

💼 B2B Use Cases

1. Game rewards:

JAVASCRIPT
// Reward player for achievement
await sendStars(userTelegramId, 50);

2. Promo campaigns:

JAVASCRIPT
// Send Stars to all contest winners
const winners = [143594291, 987654321, 456789123];
for (const userId of winners) {
  await sendStars(userId, 100);
}

3. Cashback programs:

JAVASCRIPT
// Return part of purchase as Stars
const cashbackAmount = Math.floor(purchaseAmount * 0.05); // 5% cashback
const starsAmount = Math.min(cashbackAmount * 100, 1000); // convert to Stars
await sendStars(userTelegramId, starsAmount);

⚡ Performance and Limits

  • Rate limiting: 30 requests per second on Telegram API
  • Minimum amount: 1 Star
  • Maximum amount: 2500 Stars per transaction
  • Retry logic: Automatic retries on temporary errors
  • Delivery time: Instant delivery (< 3 seconds)

🛡️ Security

  • Telegram User ID validation before sending
  • GamesDrop balance check before order creation
  • Logging of all operations for audit
  • Duplicate transaction protection via transactionId