◆ Reseller developer guide

Rexo Prime Reseller API

Put our live catalogue of AI tools and digital subscriptions inside your own bot, website or app. You make the sale; we handle stock, charging and delivery.

Base URL
https://rexoprime.com/api/telegram-buyer
Auth header
X-API-Key: tgb_…
Prices
USDT, from your wallet
Limits per key
120 reads / 40 orders a minute
01 — Setup map

From zero to first delivery

Six steps. The first three take a minute in Telegram; the rest is your code.

1Step 01

Get your key

In @rexoprimeshop_bot tap Bot API → Get API Key, or sign in on the website and open Account → API. The key starts with tgb_.

2Step 02

Lock the key away

Save it as REXOPRIME_API_KEY in your server's secrets. Never put it in a browser or mobile app, a public repository or a URL.

3Step 03

Fund your wallet

Top up in the bot or on the website (Binance Pay, USDT, bKash or card), from 0.10 USDT. Every API order is paid from this balance.

4Step 04

Load live products

GET /products gives every product you can buy by API: its id, your price, stock, quantity limits and what the buyer has to give.

5Step 05

Create the order

POST /purchase with the product, the quantity and one unique client_order_id per customer order, plus the buyer's details when the product asks.

6Step 06

Deliver the result

Send every line of delivered_items to your buyer. Not delivered yet? Ask GET /orders/{order_id} until final is true, or use the webhook.

02 — Working code

Connect your codebase

The whole flow: products, wallet, a safe purchase, and waiting for a delivery that is not instant. Keep the key server-side.

const API = "https://rexoprime.com/api/telegram-buyer";
const KEY = process.env.REXOPRIME_API_KEY!;   // server-side only

async function rexo(path: string, init: RequestInit = {}) {
  const res = await fetch(API + path, {
    ...init,
    headers: { "X-API-Key": KEY, "Content-Type": "application/json", ...init.headers },
  });
  const data = await res.json();
  if (!res.ok || data.success === false) throw new Error(data.status ?? data.message ?? `HTTP ${res.status}`);
  return data;
}

// 1. live products (your price in USDT) and your wallet
const { products } = await rexo("/products");
const { balance } = await rexo("/balance");

// 2. buy -- send the SAME client_order_id again if you retry this customer order
let order = await rexo("/purchase", {
  method: "POST",
  body: JSON.stringify({
    product_id: products[0].id,
    quantity: 1,
    client_order_id: `tg_${chatId}_${paymentId}`,
    // customer_payload: { custom_details: "buyer@gmail.com" },  // when requiresCustomerDetails
  }),
});

// 3. not delivered yet? ask again until it is
for (let i = 0; i < 24 && order.delivery_status !== "delivered" && !order.final; i++) {
  await new Promise((r) => setTimeout(r, (order.poll_after_seconds || 5) * 1000));
  order = await rexo(`/orders/${order.order_id}`);
}
if (order.delivery_status === "delivered") {
  for (const line of order.delivered_items) await deliverToCustomer(line);
} else {
  // "manual": delivered by hand later -- check again from a background job.
  // "failed": order.refunded tells you the money is back on your wallet.
}

!Most products come back delivered in the purchase answer itself. A few are bought from a supplier first and take a little longer (processing), and some are finished by hand (manual). The purchase call waits up to 12 seconds for you; ?wait=0 answers at once and ?wait=55 waits longest.

03 — API reference

Four calls. One predictable flow.

All paths hang off https://rexoprime.com/api/telegram-buyer. Every answer is JSON with "success": true or false.

CallWhat it does
GET/productsEvery product you can buy by API, with your price in USDT, stock and limits.
GET/balanceYour wallet (balance) and your key's limits (api_profile).
POST/purchaseBuy. Paid from your wallet; the goods come back in delivered_items.
GET/orders/{order_id}One order's state and goods. Also by order code: /orders/REXO7K3M9QP2.
POST/webhookOptional: get a signed callback when an order is delivered.

Safe retries

Send one client_order_id per customer order and the same one on every retry. A repeat answers "duplicate": true with the first order: nothing is bought or charged twice. (idempotency_key and an Idempotency-Key header work the same.)

USDT pricing

price in /products is exactly what you pay, your reseller discount included. Every order uses your prepaid wallet; add your own margin when you sell.

120 reads / 40 orders a minute

The limit applies per key. After a 429, wait before you try again, and keep the same client_order_id.

What you send with an order

FieldWhenWhat it is
product_idalwaysThe id from /products.
quantityalwaysWithin the product's min_purchase_quantity / max_purchase_quantity (0 = no limit).
client_order_idalwaysYour id for this customer order, the same on every retry.
customer_payload.custom_detailsrequiresCustomerDetailsThe buyer's answer to customer_details_prompt (their email, a profile link…), exactly as typed. It is checked before anything is charged.
usernamerequiresTelegramUsernameTelegram Premium and Stars: the recipient's @username. For Stars, quantity is the number of Stars (from 50).

What an order tells you

delivery_statusfinalMeaning
deliveredtrueDone. The goods are in delivered_items, one line per unit.
processingfalsePaid; being bought or checked. Ask again after poll_after_seconds.
manualfalsePaid; our team delivers it by hand. Check again every few minutes.
failedtrueIt will not be delivered. refunded: true and refund_amount say the money is back on your wallet.

Delivery and refunds

Only products we deliver automatically are sold by API. If a paid order cannot be delivered, we deliver it by hand or refund it in full to your wallet, and the order says so. A refused call (no stock, low balance, missing details) is never charged.

Webhook

POST /webhook {"webhook_url": "https://…"} returns a signing secret once. Each callback carries X-Signature: sha256=HMAC_SHA256(secret, raw_body); check it, and expect a delivery to arrive more than once.

Everything else (resale names and prices, all fields, examples) is in the full reference; the machine-readable spec is in Swagger (openapi.json).

04 — AI-assisted setup

Build it with your AI coding tool

Open your project, choose your assistant and paste the prepared prompt. It carries the API and the safety rules that matter: the key stays on the server, retries never buy twice, every result is handled.

Claude

Ask Claude to read your existing bot or app before changing it.

Show the prompt
First read my existing bot / app and tell me where checkout and delivery happen. Then make the change in small steps and show me the diff before you finish.

Connect this project to the Rexo Prime reseller API, so a customer who pays us gets the product delivered automatically.

API
- Base URL: https://rexoprime.com/api/telegram-buyer
- Auth header: X-API-Key: <key>. The key is in the environment variable REXOPRIME_API_KEY. Use it only on the server: never in a browser or mobile app, never in a URL, never in logs.
- GET /products -> {"products": [...]}. Per product: id, name, price (USDT, what we pay), stock, infinite_stock, min_purchase_quantity and max_purchase_quantity (0 = no limit), requiresCustomerDetails, customer_details_prompt, requiresTelegramUsername.
- GET /balance -> {"balance": number}, in USDT.
- POST /purchase with JSON {"product_id": number, "quantity": number, "client_order_id": string, "customer_payload": {"custom_details": string}} -> {"order_id", "orderCode", "delivery_status": "delivered" or "processing", "delivered_items": [one string per unit], "poll_after_seconds"}.
- GET /orders/{order_id} -> {"delivery_status": "processing" | "manual" | "delivered" | "failed", "final", "delivered_items", "refunded", "refund_amount", "message", "poll_after_seconds"}.
- Errors are JSON {"success": false, "message": string, "status": string}: 400 bad input (status custom_details_required, custom_details_invalid_email, custom_details_invalid_link, telegram_username_required), 401 invalid key, 403 not allowed (manual_delivery_not_available), 404 product not found, 409 insufficient_balance / out_of_stock / product_not_available / limit_exceeded / daily_spend_limit_reached, 429 too many requests, 503 API switched off.

Rules
1. Give every customer order one client_order_id, save it with the order, and send the same id on every retry, after a timeout too. A repeat answers {"duplicate": true, "order_id": N} and is never charged twice.
2. When requiresCustomerDetails is true, ask the customer customer_details_prompt and send the answer exactly as typed in customer_payload.custom_details. For Telegram Premium / Stars send the recipient's @username as "username".
3. Deliver every line of delivered_items. While delivery_status is "processing", call GET /orders/{order_id} after poll_after_seconds. "manual" means it is delivered by hand later: check again every few minutes from a background job until final is true. A "failed" order is never delivered later; refunded: true means the money is back on our wallet.
4. On 409 insufficient_balance show the customer "temporarily unavailable" and alert the admin to top up; never retry in a loop. On 429 wait, then retry with the same client_order_id.
5. Read products and prices from /products and refresh them regularly instead of hard-coding ids or prices; add our own margin on top of price.
6. Finish with a low-value test order that runs the whole flow, and show me how to run it.

Gemini

Give Gemini this prompt with your server-side project open.

Show the prompt
My server-side project is open. Find the checkout and delivery code first, then add the integration.

Connect this project to the Rexo Prime reseller API, so a customer who pays us gets the product delivered automatically.

API
- Base URL: https://rexoprime.com/api/telegram-buyer
- Auth header: X-API-Key: <key>. The key is in the environment variable REXOPRIME_API_KEY. Use it only on the server: never in a browser or mobile app, never in a URL, never in logs.
- GET /products -> {"products": [...]}. Per product: id, name, price (USDT, what we pay), stock, infinite_stock, min_purchase_quantity and max_purchase_quantity (0 = no limit), requiresCustomerDetails, customer_details_prompt, requiresTelegramUsername.
- GET /balance -> {"balance": number}, in USDT.
- POST /purchase with JSON {"product_id": number, "quantity": number, "client_order_id": string, "customer_payload": {"custom_details": string}} -> {"order_id", "orderCode", "delivery_status": "delivered" or "processing", "delivered_items": [one string per unit], "poll_after_seconds"}.
- GET /orders/{order_id} -> {"delivery_status": "processing" | "manual" | "delivered" | "failed", "final", "delivered_items", "refunded", "refund_amount", "message", "poll_after_seconds"}.
- Errors are JSON {"success": false, "message": string, "status": string}: 400 bad input (status custom_details_required, custom_details_invalid_email, custom_details_invalid_link, telegram_username_required), 401 invalid key, 403 not allowed (manual_delivery_not_available), 404 product not found, 409 insufficient_balance / out_of_stock / product_not_available / limit_exceeded / daily_spend_limit_reached, 429 too many requests, 503 API switched off.

Rules
1. Give every customer order one client_order_id, save it with the order, and send the same id on every retry, after a timeout too. A repeat answers {"duplicate": true, "order_id": N} and is never charged twice.
2. When requiresCustomerDetails is true, ask the customer customer_details_prompt and send the answer exactly as typed in customer_payload.custom_details. For Telegram Premium / Stars send the recipient's @username as "username".
3. Deliver every line of delivered_items. While delivery_status is "processing", call GET /orders/{order_id} after poll_after_seconds. "manual" means it is delivered by hand later: check again every few minutes from a background job until final is true. A "failed" order is never delivered later; refunded: true means the money is back on our wallet.
4. On 409 insufficient_balance show the customer "temporarily unavailable" and alert the admin to top up; never retry in a loop. On 429 wait, then retry with the same client_order_id.
5. Read products and prices from /products and refresh them regularly instead of hard-coding ids or prices; add our own margin on top of price.
6. Finish with a low-value test order that runs the whole flow, and show me how to run it.

Codex

Use it from the repository root so Codex can test the full flow.

Show the prompt
Work from the repository root. Add the integration, write tests that mock the answers below (delivered at once; processing, then delivered; 409; 429; a repeat) and run them.

Connect this project to the Rexo Prime reseller API, so a customer who pays us gets the product delivered automatically.

API
- Base URL: https://rexoprime.com/api/telegram-buyer
- Auth header: X-API-Key: <key>. The key is in the environment variable REXOPRIME_API_KEY. Use it only on the server: never in a browser or mobile app, never in a URL, never in logs.
- GET /products -> {"products": [...]}. Per product: id, name, price (USDT, what we pay), stock, infinite_stock, min_purchase_quantity and max_purchase_quantity (0 = no limit), requiresCustomerDetails, customer_details_prompt, requiresTelegramUsername.
- GET /balance -> {"balance": number}, in USDT.
- POST /purchase with JSON {"product_id": number, "quantity": number, "client_order_id": string, "customer_payload": {"custom_details": string}} -> {"order_id", "orderCode", "delivery_status": "delivered" or "processing", "delivered_items": [one string per unit], "poll_after_seconds"}.
- GET /orders/{order_id} -> {"delivery_status": "processing" | "manual" | "delivered" | "failed", "final", "delivered_items", "refunded", "refund_amount", "message", "poll_after_seconds"}.
- Errors are JSON {"success": false, "message": string, "status": string}: 400 bad input (status custom_details_required, custom_details_invalid_email, custom_details_invalid_link, telegram_username_required), 401 invalid key, 403 not allowed (manual_delivery_not_available), 404 product not found, 409 insufficient_balance / out_of_stock / product_not_available / limit_exceeded / daily_spend_limit_reached, 429 too many requests, 503 API switched off.

Rules
1. Give every customer order one client_order_id, save it with the order, and send the same id on every retry, after a timeout too. A repeat answers {"duplicate": true, "order_id": N} and is never charged twice.
2. When requiresCustomerDetails is true, ask the customer customer_details_prompt and send the answer exactly as typed in customer_payload.custom_details. For Telegram Premium / Stars send the recipient's @username as "username".
3. Deliver every line of delivered_items. While delivery_status is "processing", call GET /orders/{order_id} after poll_after_seconds. "manual" means it is delivered by hand later: check again every few minutes from a background job until final is true. A "failed" order is never delivered later; refunded: true means the money is back on our wallet.
4. On 409 insufficient_balance show the customer "temporarily unavailable" and alert the admin to top up; never retry in a loop. On 429 wait, then retry with the same client_order_id.
5. Read products and prices from /products and refresh them regularly instead of hard-coding ids or prices; add our own margin on top of price.
6. Finish with a low-value test order that runs the whole flow, and show me how to run it.

Lovable

Best for adding the reseller flow to a full-stack web app.

Show the prompt
Add this reseller flow to my full-stack web app. Every API call must run on the server (a backend route or an Edge Function), never in the React client.

Connect this project to the Rexo Prime reseller API, so a customer who pays us gets the product delivered automatically.

API
- Base URL: https://rexoprime.com/api/telegram-buyer
- Auth header: X-API-Key: <key>. The key is in the environment variable REXOPRIME_API_KEY. Use it only on the server: never in a browser or mobile app, never in a URL, never in logs.
- GET /products -> {"products": [...]}. Per product: id, name, price (USDT, what we pay), stock, infinite_stock, min_purchase_quantity and max_purchase_quantity (0 = no limit), requiresCustomerDetails, customer_details_prompt, requiresTelegramUsername.
- GET /balance -> {"balance": number}, in USDT.
- POST /purchase with JSON {"product_id": number, "quantity": number, "client_order_id": string, "customer_payload": {"custom_details": string}} -> {"order_id", "orderCode", "delivery_status": "delivered" or "processing", "delivered_items": [one string per unit], "poll_after_seconds"}.
- GET /orders/{order_id} -> {"delivery_status": "processing" | "manual" | "delivered" | "failed", "final", "delivered_items", "refunded", "refund_amount", "message", "poll_after_seconds"}.
- Errors are JSON {"success": false, "message": string, "status": string}: 400 bad input (status custom_details_required, custom_details_invalid_email, custom_details_invalid_link, telegram_username_required), 401 invalid key, 403 not allowed (manual_delivery_not_available), 404 product not found, 409 insufficient_balance / out_of_stock / product_not_available / limit_exceeded / daily_spend_limit_reached, 429 too many requests, 503 API switched off.

Rules
1. Give every customer order one client_order_id, save it with the order, and send the same id on every retry, after a timeout too. A repeat answers {"duplicate": true, "order_id": N} and is never charged twice.
2. When requiresCustomerDetails is true, ask the customer customer_details_prompt and send the answer exactly as typed in customer_payload.custom_details. For Telegram Premium / Stars send the recipient's @username as "username".
3. Deliver every line of delivered_items. While delivery_status is "processing", call GET /orders/{order_id} after poll_after_seconds. "manual" means it is delivered by hand later: check again every few minutes from a background job until final is true. A "failed" order is never delivered later; refunded: true means the money is back on our wallet.
4. On 409 insufficient_balance show the customer "temporarily unavailable" and alert the admin to top up; never retry in a loop. On 429 wait, then retry with the same client_order_id.
5. Read products and prices from /products and refresh them regularly instead of hard-coding ids or prices; add our own margin on top of price.
6. Finish with a low-value test order that runs the whole flow, and show me how to run it.

Replit

Save the key in Secrets before asking the Agent to connect it.

Show the prompt
The key is saved in Replit Secrets as REXOPRIME_API_KEY. Connect it in the server code of this Repl.

Connect this project to the Rexo Prime reseller API, so a customer who pays us gets the product delivered automatically.

API
- Base URL: https://rexoprime.com/api/telegram-buyer
- Auth header: X-API-Key: <key>. The key is in the environment variable REXOPRIME_API_KEY. Use it only on the server: never in a browser or mobile app, never in a URL, never in logs.
- GET /products -> {"products": [...]}. Per product: id, name, price (USDT, what we pay), stock, infinite_stock, min_purchase_quantity and max_purchase_quantity (0 = no limit), requiresCustomerDetails, customer_details_prompt, requiresTelegramUsername.
- GET /balance -> {"balance": number}, in USDT.
- POST /purchase with JSON {"product_id": number, "quantity": number, "client_order_id": string, "customer_payload": {"custom_details": string}} -> {"order_id", "orderCode", "delivery_status": "delivered" or "processing", "delivered_items": [one string per unit], "poll_after_seconds"}.
- GET /orders/{order_id} -> {"delivery_status": "processing" | "manual" | "delivered" | "failed", "final", "delivered_items", "refunded", "refund_amount", "message", "poll_after_seconds"}.
- Errors are JSON {"success": false, "message": string, "status": string}: 400 bad input (status custom_details_required, custom_details_invalid_email, custom_details_invalid_link, telegram_username_required), 401 invalid key, 403 not allowed (manual_delivery_not_available), 404 product not found, 409 insufficient_balance / out_of_stock / product_not_available / limit_exceeded / daily_spend_limit_reached, 429 too many requests, 503 API switched off.

Rules
1. Give every customer order one client_order_id, save it with the order, and send the same id on every retry, after a timeout too. A repeat answers {"duplicate": true, "order_id": N} and is never charged twice.
2. When requiresCustomerDetails is true, ask the customer customer_details_prompt and send the answer exactly as typed in customer_payload.custom_details. For Telegram Premium / Stars send the recipient's @username as "username".
3. Deliver every line of delivered_items. While delivery_status is "processing", call GET /orders/{order_id} after poll_after_seconds. "manual" means it is delivered by hand later: check again every few minutes from a background job until final is true. A "failed" order is never delivered later; refunded: true means the money is back on our wallet.
4. On 409 insufficient_balance show the customer "temporarily unavailable" and alert the admin to top up; never retry in a loop. On 429 wait, then retry with the same client_order_id.
5. Read products and prices from /products and refresh them regularly instead of hard-coding ids or prices; add our own margin on top of price.
6. Finish with a low-value test order that runs the whole flow, and show me how to run it.

Other AI tools

Works with any coding assistant that can edit your server.

Show the prompt
Connect this project to the Rexo Prime reseller API, so a customer who pays us gets the product delivered automatically.

API
- Base URL: https://rexoprime.com/api/telegram-buyer
- Auth header: X-API-Key: <key>. The key is in the environment variable REXOPRIME_API_KEY. Use it only on the server: never in a browser or mobile app, never in a URL, never in logs.
- GET /products -> {"products": [...]}. Per product: id, name, price (USDT, what we pay), stock, infinite_stock, min_purchase_quantity and max_purchase_quantity (0 = no limit), requiresCustomerDetails, customer_details_prompt, requiresTelegramUsername.
- GET /balance -> {"balance": number}, in USDT.
- POST /purchase with JSON {"product_id": number, "quantity": number, "client_order_id": string, "customer_payload": {"custom_details": string}} -> {"order_id", "orderCode", "delivery_status": "delivered" or "processing", "delivered_items": [one string per unit], "poll_after_seconds"}.
- GET /orders/{order_id} -> {"delivery_status": "processing" | "manual" | "delivered" | "failed", "final", "delivered_items", "refunded", "refund_amount", "message", "poll_after_seconds"}.
- Errors are JSON {"success": false, "message": string, "status": string}: 400 bad input (status custom_details_required, custom_details_invalid_email, custom_details_invalid_link, telegram_username_required), 401 invalid key, 403 not allowed (manual_delivery_not_available), 404 product not found, 409 insufficient_balance / out_of_stock / product_not_available / limit_exceeded / daily_spend_limit_reached, 429 too many requests, 503 API switched off.

Rules
1. Give every customer order one client_order_id, save it with the order, and send the same id on every retry, after a timeout too. A repeat answers {"duplicate": true, "order_id": N} and is never charged twice.
2. When requiresCustomerDetails is true, ask the customer customer_details_prompt and send the answer exactly as typed in customer_payload.custom_details. For Telegram Premium / Stars send the recipient's @username as "username".
3. Deliver every line of delivered_items. While delivery_status is "processing", call GET /orders/{order_id} after poll_after_seconds. "manual" means it is delivered by hand later: check again every few minutes from a background job until final is true. A "failed" order is never delivered later; refunded: true means the money is back on our wallet.
4. On 409 insufficient_balance show the customer "temporarily unavailable" and alert the admin to top up; never retry in a loop. On 429 wait, then retry with the same client_order_id.
5. Read products and prices from /products and refresh them regularly instead of hard-coding ids or prices; add our own margin on top of price.
6. Finish with a low-value test order that runs the whole flow, and show me how to run it.
05 — Go live

Launch checklist

  • The API key is stored in your server's secrets
  • Products and balance load successfully
  • Every checkout has its own stable client_order_id
  • Delivered, processing, manual and failed results are handled
  • 400, 409, 429 and 503 answers have clear fallbacks
  • A low-value test order reads back through your customer screens (some products cost a few cents)
Troubleshooting

When a request stops

The HTTP code says what kind of problem it is; status in the answer names it. Every refusal below charges nothing.

400 · Missing details

custom_details_required, custom_details_invalid_email, custom_details_invalid_link, telegram_username_required, or a quantity outside the product's limits. Ask the buyer again and resend.

401 · Invalid key

The key is wrong or was replaced by a new one, or the base URL is not https://rexoprime.com: our keys work only here.

403 · Not allowed

manual_delivery_not_available (that product is delivered by hand and not sold by API), a product your key may not buy, or a paused key.

404 · Product not found

The product is off sale or the id is wrong. Reload /products.

409 · Cannot buy now

insufficient_balance: top up your wallet. out_of_stock / product_not_available: try later or another product. limit_exceeded / daily_spend_limit_reached: your key's limits.

429 · Too many requests

More than 120 reads or 40 orders a minute on one key. Wait, then retry with the same client_order_id.

manual · Delivered by hand

Paid and on its way through our team. Keep checking GET /orders/{order_id} every few minutes, or wait for the webhook.

503 · API switched off

Our API is paused for a moment. Try again later; nothing was charged.

Ready for your first API order?

Get your key in Telegram, fund the wallet, and use the examples above to connect your store.