Toolverio Reseller API
Sell our digital products from your own Telegram bot or website. You pay from a prepaid USDT API balance and get the items back in the same request.
https://api.toolverio.comAll requests and responses are JSON (UTF-8). All money values are numbers in USDT.
Quickstart
- Open @ToolverioBot and tap 🔑 Reseller API, then Request Access.
- When approved, tap 🔑 Create API Key and save the key (it is shown once).
- Add USDT to your bot wallet, then tap 💵 Top Up API Balance.
- List products and place your first order:
curl https://api.toolverio.com/v1/products -H "Authorization: Bearer tvr_YOUR_KEY"
curl -X POST https://api.toolverio.com/v1/orders \
-H "Authorization: Bearer tvr_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-order-1001" \
-d '{"product_id": "p12", "quantity": 1}'
Getting access
Everything is managed in the Telegram bot, screen 🔑 Reseller API: Account, Status, API Balance, Discount, API Orders, API Key and Low-Balance Alert, with the buttons Top Up API Balance, Transfer to Wallet, My Prices, API Orders, API Docs, Regenerate Key, Revoke Key and Low Balance Alert. New requests are approved by our team.
Balance & top-ups
Your API balance is separate from your bot wallet. Add money to the wallet (Binance Pay or USDT BEP20), then move any amount to the API balance with Top Up API Balance. You can move any amount back with Transfer to Wallet at any time. There is no minimum or maximum.
Authentication
Send your key in the Authorization header on every request:
Authorization: Bearer tvr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Keys start with tvr_. Regenerate or revoke them in the bot. X-API-Key: tvr_... also works.
Idempotency (never pay twice)
Every POST /v1/orders needs an Idempotency-Key header: any unique string up to 64 characters, for example your own order id. If your request times out, send it again with the same key: you get the same order back and you are never charged twice. Using the same key with a different body returns 409 idempotency_conflict.
Order statuses
| Status | Meaning |
|---|---|
processing | Paid, being prepared (usually a few seconds). Poll GET /v1/orders/{code}. |
delivered | Done. Your items are in items. |
pending | Manual delivery by our team. Items appear when ready. |
refunded | Could not be delivered. The total went back to your API balance. |
Delivery types
Each product has delivery: instant (items come back in the order) or manual (our team delivers, status pending until then).
Required fields
Some products are activated on the buyer's own account. They list what we need in required_fields (for example ["Email"]). Send them in fields:
{"product_id": "p31", "quantity": 1, "fields": {"Email": "buyer@mail.com"}}
Errors
{"ok": false, "error": {"code": "insufficient_balance", "message": "API balance is too low."}}
| HTTP | code | Meaning |
|---|---|---|
| 401 | invalid_key | Key missing or wrong |
| 403 | account_pending | Access not approved yet |
| 403 | account_disabled | Access disabled, contact support |
| 404 | product_not_found | No product with that id |
| 404 | order_not_found | No order found |
| 400 | invalid_request | Bad JSON, missing parameter or missing Idempotency-Key |
| 400 | qty_out_of_range | Quantity below min_qty or above max_qty |
| 400 | missing_fields | required_fields not sent |
| 402 | insufficient_balance | Top up your API balance |
| 409 | out_of_stock | Not enough stock right now |
| 409 | idempotency_conflict | Key reused with a different body |
| 429 | rate_limited | Too many requests, see Retry-After |
| 500 | internal_error | Retry with the same Idempotency-Key |
Rate limits
60 requests per minute per key. Every response has X-RateLimit-Limit and X-RateLimit-Remaining; a 429 has Retry-After (seconds). 5 wrong keys in a minute from one IP block that IP for 15 minutes.
GET /v1/balance
curl https://api.toolverio.com/v1/balance -H "Authorization: Bearer tvr_YOUR_KEY"
{"ok": true, "balance": 12.5, "currency": "USDT"}
GET /v1/products
All products with your price (your discount is already applied).
{"ok": true, "products": [
{"id": "p12", "name": "Gemini AI Pro 18 Month", "description": "...", "category": "AI Tools",
"emoji": "🤖", "unit_price": 0.42, "currency": "USDT", "stock": 120,
"min_qty": 1, "max_qty": 100, "delivery": "instant", "required_fields": [],
"bulk_prices": [{"min_qty": 10, "unit_price": 0.40}], "in_stock": true}
]}
| Field | Type | Description |
|---|---|---|
id | string | Use it as product_id |
unit_price | number | Your price per unit in USDT |
stock | number or null | null = unlimited |
min_qty / max_qty | number | Allowed quantity per order |
delivery | string | instant or manual |
required_fields | array | Send these in fields |
bulk_prices | array | Cheaper unit price from min_qty units |
GET /v1/products/{id}
{"ok": true, "product": { ...same fields... }}
POST /v1/orders
| Body | Type | Required | Description |
|---|---|---|---|
product_id | string | yes | From /v1/products |
quantity | integer | yes | Between min_qty and max_qty |
fields | object | if listed | Values for required_fields |
Header Idempotency-Key is required.
curl -X POST https://api.toolverio.com/v1/orders \
-H "Authorization: Bearer tvr_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-order-1001" \
-d '{"product_id": "p12", "quantity": 2}'import requests
r = requests.post("https://api.toolverio.com/v1/orders",
headers={"Authorization": "Bearer tvr_YOUR_KEY", "Idempotency-Key": "my-order-1001"},
json={"product_id": "p12", "quantity": 2}, timeout=30)
data = r.json()
if data["ok"]:
print(data["order"]["status"], data["order"]["items"])
else:
print(data["error"]["code"], data["error"]["message"])const r = await fetch("https://api.toolverio.com/v1/orders", {
method: "POST",
headers: {"Authorization": "Bearer tvr_YOUR_KEY", "Content-Type": "application/json",
"Idempotency-Key": "my-order-1001"},
body: JSON.stringify({product_id: "p12", quantity: 2})
});
const data = await r.json();
console.log(data.ok ? data.order.items : data.error);$ch = curl_init("https://api.toolverio.com/v1/orders");
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer tvr_YOUR_KEY", "Content-Type: application/json",
"Idempotency-Key: my-order-1001"],
CURLOPT_POSTFIELDS => json_encode(["product_id" => "p12", "quantity" => 2])]);
$data = json_decode(curl_exec($ch), true);Response 201:
{"ok": true, "order": {
"code": "TVR-8F3K2M7Q", "status": "delivered", "product_id": "p12",
"product_name": "Gemini AI Pro 18 Month", "quantity": 2, "unit_price": 0.42, "total": 0.84,
"currency": "USDT", "items": ["https://one.google.com/...", "https://one.google.com/..."],
"note": "How to use: open the link and confirm.",
"created_at": "2026-10-15T10:21:04Z", "delivered_at": "2026-10-15T10:21:05Z"},
"balance_after": 11.66}
GET /v1/orders
{"ok": true, "orders": [ ...newest first... ], "next_cursor": "TVR-..." }
GET /v1/orders/{code}
{"ok": true, "order": { ...order... }}
GET /v1/orders/by-idempotency/{key}
Find an order by your own Idempotency-Key (404 if none). Useful after a timeout.
Guide: retry safely
Network errors happen. Always reuse the same Idempotency-Key for the same customer order:
for attempt in range(3):
try:
r = requests.post(URL + "/v1/orders", headers={**H, "Idempotency-Key": order_id},
json=body, timeout=30)
break
except requests.RequestException:
time.sleep(2) # same key = never charged twice
Guide: processing orders
Most orders come back delivered. If you get processing, check every 3 seconds for up to 2 minutes:
while order["status"] == "processing":
time.sleep(3)
order = requests.get(f"{URL}/v1/orders/{order['code']}", headers=H).json()["order"]
Guide: Telegram resale bot
import requests, uuid
from telegram.ext import Application, CommandHandler
URL, KEY = "https://api.toolverio.com", "tvr_YOUR_KEY"
H = {"Authorization": f"Bearer {KEY}"}
async def products(update, context):
items = requests.get(URL + "/v1/products", headers=H, timeout=20).json()["products"]
await update.message.reply_text("\n".join(f"{p['id']} - {p['name']} - ${p['unit_price']}"
for p in items if p["in_stock"]))
async def buy(update, context): # /buy p12 1 (charge your own customer first!)
pid, qty = context.args[0], int(context.args[1])
r = requests.post(URL + "/v1/orders", timeout=30,
headers={**H, "Idempotency-Key": str(uuid.uuid4())},
json={"product_id": pid, "quantity": qty}).json()
if not r["ok"]:
return await update.message.reply_text("Error: " + r["error"]["message"])
await update.message.reply_text("\n".join(r["order"]["items"]) or "Your order is being prepared.")
app = Application.builder().token("YOUR_BOT_TOKEN").build()
app.add_handler(CommandHandler("products", products))
app.add_handler(CommandHandler("buy", buy))
app.run_polling()