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. API Endpoints
  4. API Testing
  5. Integration Recommendations
  6. FAQ & Troubleshooting
  7. 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 due to an errorCheck message field for details, create a new order
FAILEDInternal system errorAutomatic refund, check message, stop polling
REFUNDOrder refundedWait for funds return

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.

API Endpoints

Balance Management

Check Balance

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

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

[!NOTE] The /api/v1/balance endpoint (without /offers/) requires JWT authorization and is primarily used for the web interface. For API integration, use /api/v1/offers/balance with your Shop Token.

Response:

JSON
{
  "balance": 500.25,
  "draftBalance": 0.00,
  "isPostpaid": false,
  "balanceProfile": "USDT",
  "currency": {
    "id": 3,
    "code": "USD"
  },
  "partnerId": 123
}

Response Fields:

KeyTypeDescription
balancenumberCurrent available balance in USD
draftBalancenumberReserved funds (processing)
isPostpaidbooleantrue: postpaid account (balance not required for orders). false: prepaid account (must top up balance).
balanceProfileFIAT | USDT | MIXEDDetermines which supplier offer settlement methods are available to your account.
partnerIdnumberUnique ID of your partner account
currencyobjectBalance currency information (always USD)

Transaction History

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

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
}

Response:

JSON
{
  "offerId": 1001,
  "productName": "PUBG MOBILE GIFT",
  "offerName": "60 UC",
  "count": 1,
  "price": 560.10,
  "currency": "RUB",
  "settlementMethod": "USDT",
  "balanceProfile": "USDT",
  "isSettlementCompatible": true,
  "isReturnDataForCustomer": true
}

Request fields description:

KeyValueNotes
offerIdnumberImportant: must be a number, not a string

Response fields description:

KeyValueNotes
offerIdnumber-
productNamestring-
offerNamestring-
countnumberNumber of product units
pricenumber-
currencyKZT, USD, RUB, etc.Pricing currency code
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).

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.

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

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

Request fields description: | limit | number | Elements per page (max 5000). Default: 1000. | | page | number | Page number. Default: 1. | | search | string | Optional text search by product name. | | category | string | Optional filter by category (e.g., Top Up, Gift Cards). Legacy aliases TOP_UP and GIFT_CARD are also accepted. |

Response:

JSON
{
  "count": 1250,
  "rows": [
    {
      "productId": 5,
      "productName": "PUBG Mobile",
      "offerGroupId": 101,
      "offerGroupName": "60 UC",
      "price": 0.99,
      "currency": "USD",
      "inStock": true
    }
  ]
}

Response fields description:

KeyValueNotes
countnumberTotal number of items matching filters.
rows[].offerGroupIdnumberThe ID to pass as offerId when creating an order.
rows[].pricenumberFinal cost required to purchase the item (in your currency).
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",
  "customer": {
    "email": "user@gmail.com",
    "gameUserId": "52357322414"
  }
}

Request fields description:

KeyValueNotes
offerIdnumberImportant: 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
customerundefinedobject
emailundefinedstring
gameUserIdundefinedstring

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
{
  "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-
currencyKZTUSD
offerIdnumber-
productNamestring-
offerNamestring-
statusstringSUBMITTED, PROCESSING, COMPLETED, CANCELED
isReturnDataForCustomerbooleantrue: Key product. false: Direct top-up.
isRequiredGameUserIdbooleantrue if the product requires a player identifier.
isRequiredGameServerIdbooleantrue if the product requires a server identifier.
keystring (optional)Activation Code/PIN. Present ONLY if isReturnDataForCustomer: true AND status: "COMPLETED".
createdAtstringUTC +0

Check Order Status

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

{
  "orderId": 10222502
  // OR
  "transactionId": "test112321124214"
}

Request fields description:

KeyValueNotes
orderIdnumberOptional if transactionId is provided
transactionIdstringOptional if orderId is provided

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-
offerIdnumber-
productNamestring-
offerNamestring-
statusstringCurrent status: SUBMITTED, PROCESSING, COMPLETED, CANCELED, FAILED
messagestring (optional)Detailed error message if status is CANCELED or FAILED.
isReturnDataForCustomerbooleantrue: Key product. false: Direct top-up.
isRequiredGameUserIdbooleantrue if the product requires a player identifier.
isRequiredGameServerIdbooleantrue if the product requires a server identifier.
keystring (optional)Activation Code/PIN. Present ONLY if isReturnDataForCustomer: true AND status: "COMPLETED".
createdAtstringUTC +0

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
}

You can also use the equivalent short path:

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

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
gameServerIdundefinedstring

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: 23.09 KZT (important to use exact value)
  • 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": 23.09,
  "transactionId": "test_123456",
  "customer": {
    "email": "test@example.com",
    "gameUserId": "123456789"
  }
}

Test product features:

  • Always returns successful response with correct parameters
  • Generates test activation key
  • Creates order with COMPLETED status
  • Player validation always returns VALID for test product
  • Works in test mode without real fund deduction

Balance Management Examples

Check balance before purchase:

JAVASCRIPT
// 1. Check current balance
const balanceResponse = await fetch('/api/v1/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': 'your-token-here' }
});
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 status: "COMPLETED". The player receives the item in-game automatically.
  • 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"
  }
}

Response on successful delivery:

JSON
{
  "orderId": 10228901,
  "count": 1,
  "price": 0.78,
  "currency": "USD",
  "offerId": 1001,
  "productName": "Telegram Stars",
  "offerName": "100 Stars",
  "status": "COMPLETED",
  "isReturnDataForCustomer": true,
  "fulfillmentData": {
    "telegram_user_id": 143594291,
    "stars_amount": 100,
    "transaction_id": "tg_tx_abc123",
    "delivery_status": "completed"
  },
  "createdAt": "2025-08-26T12:30:15.234Z"
}

Response on delivery failure:

JSON
{
  "orderId": 10228902,
  "status": "CANCELED",
  "message": "Failed to deliver Stars: user not found",
  "fulfillmentData": {
    "telegram_user_id": 123456789,
    "stars_amount": 100,
    "delivery_status": "failed",
    "error_message": "user not found"
  },
  "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