Place orders on this store programmatically, server to server. Every order is charged to your reseller wallet instantly, with a discount and spend limits set by the store admin.
The API is a small signed REST interface. You send form-encoded or JSON parameters over HTTPS; we authenticate the request, price the order with your reseller discount, charge your wallet, and start delivery — all in one step.
https://smgamebazar.comRequest credentials (API key and secret) are issued by the store admin from the admin panel. Keep the secret on your server only — never ship it in client-side code or a public app.
Every request — including read-only ones — must carry three parameters. There are no sessions and no tokens to refresh.
keystringrequiredYour API key id, e.g. RSL-XXXXXXXXXXXX.
timeintegerrequiredCurrent Unix time in seconds. Requests whose clock differs from ours by more than 300 seconds are rejected.
signstringrequiredThe request signature, computed as described below.
How the signature is built
sign.name=value& pairs — note the trailing & after every pair.sign = MD5( MD5( joined + secret ) ) — a double MD5, lowercase hex.Use the exact strings you are sending. If you sign time=1717000000 you must send that same value. The sign parameter itself is never part of the signed string.
params = {
key: "RSL-XXXXXXXXXXXX",
time: 1717000000,
product_id: "mobile-legends",
package_code: "ml-500",
player_id: "123456789",
ref: "ORD-2026-0001"
}
// 1. sort the names -> key, package_code, player_id, product_id, ref, time
// 2. join as name=value& -> key=RSL-...&package_code=ml-500&...&time=1717000000&
// 3. double MD5 with secret -> signPHP
<?php
$secret = 'YOUR_SECRET';
$params = [
'key' => 'RSL-XXXXXXXXXXXX',
'time' => time(),
'product_id' => 'mobile-legends',
'package_code' => 'ml-500',
'player_id' => '123456789',
'ref' => 'ORD-2026-0001',
];
ksort($params);
$query = '';
foreach ($params as $k => $v) {
$query .= $k . '=' . $v . '&';
}
$params['sign'] = md5(md5($query . $secret));
$ch = curl_init('https://smgamebazar.com/api/reseller/order');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($params),
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);Node.js
import crypto from 'node:crypto'
const SECRET = 'YOUR_SECRET'
const md5 = (s) => crypto.createHash('md5').update(s, 'utf8').digest('hex')
function sign(params) {
const query = Object.keys(params)
.sort()
.map((k) => `${k}=${params[k]}&`)
.join('')
return md5(md5(query + SECRET))
}
const params = {
key: 'RSL-XXXXXXXXXXXX',
time: Math.floor(Date.now() / 1000),
product_id: 'mobile-legends',
package_code: 'ml-500',
player_id: '123456789',
ref: 'ORD-2026-0001',
}
params.sign = sign(params)
const res = await fetch('https://smgamebazar.com/api/reseller/order', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams(params),
})
const data = await res.json()Python
import hashlib, time, requests
SECRET = "YOUR_SECRET"
BASE = "https://smgamebazar.com"
def sign(params):
query = "".join(f"{k}={params[k]}&" for k in sorted(params))
return hashlib.md5(hashlib.md5((query + SECRET).encode()).hexdigest().encode()).hexdigest()
params = {
"key": "RSL-XXXXXXXXXXXX",
"time": int(time.time()),
"product_id": "mobile-legends",
"package_code": "ml-500",
"player_id": "123456789",
"ref": "ORD-2026-0001",
}
params["sign"] = sign(params)
r = requests.post(f"{BASE}/api/reseller/order", data=params)Returns every product and package this key may order, already priced with your reseller discount. Restricted keys only see their allowed products; products that cannot be ordered through the API are omitted.
keystringrequiredYour API key id.
timeintegerrequiredUnix time in seconds.
signstringrequiredRequest signature.
https://smgamebazar.com/api/reseller/products?key=…&time=…&sign=…{
"ok": true,
"currency": "\u09F3",
"discount_percent": 5,
"products": [
{
"id": "mobile-legends",
"name": "Mobile Legends",
"image": "/uploads/ml.png",
"description": "Diamonds and passes",
"packages": [
{
"code": "ml-500",
"label": "500 Diamonds",
"price": 475, // what you pay, after your discount
"base_price": 500, // the normal store price
"in_stock": true
}
]
}
]
}Your wallet is the balance every order is charged from. Poll it to know when to top up. It also returns your active limits so you can size orders correctly.
https://smgamebazar.com/api/reseller/balance?key=…&time=…&sign=…{
"ok": true,
"currency": "\u09F3",
"wallet": { "balance": 12500, "total_spent": 8400 },
"account": { "id": 42, "name": "TopupMart", "email": "you@example.com" },
"key": {
"id": "RSL-XXXXXXXXXXXX",
"label": "TopupMart partner",
"discount_percent": 5,
"max_order_amount": 2000,
"daily_max_amount": 10000,
"monthly_max_amount": 100000,
"daily_order_limit": 200,
"allowed_products": null, // null = every product
"expires_at": "2026-12-31 23:59:00"
}
}Creates an order, charges your wallet and starts delivery. The amount charged is package price × (1 − discount) × quantity, rounded to two decimals.
https://smgamebazar.com/api/reseller/orderkeystringrequiredYour API key id.
timeintegerrequiredUnix time in seconds.
signstringrequiredRequest signature.
refstringrequiredYour own unique order reference, 6–64 characters from A–Z a–z 0–9 _ . : -. This is the idempotency key — see Safety & limits.
product_idstringrequiredThe product id from “Get products”.
package_codestringrequiredThe package code from “Get products”.
player_idstringrequiredThe game account id to deliver to (also accepted as uid). 4–64 characters.
nicknamestringoptionalIn-game name, if you have it. Helps support match the delivery.
quantityintegeroptionalNumber of packages, 1–10. Defaults to 1.
{
"ok": true,
"currency": "\u09F3",
"order": {
"id": "ORD-8F3K2A", // the store order code
"ref": "ORD-2026-0001",
"product_id": "mobile-legends",
"package_code": "ml-500",
"quantity": 1,
"amount": 475,
"status": "Processing"
},
"wallet": { "balance": 12025 } // balance after the charge
}A successful response means the wallet was charged and delivery has started. Poll “Order status” until status becomes Completed (or a failure state), which is why the store may also notify you by email.
Look up a single order. Send either the ref you used to place it, or the order_code from the response. Only orders belonging to your key are visible.
https://smgamebazar.com/api/reseller/order?ref=ORD-2026-0001&key=…&time=…&sign=…Or with the store code: ?order_code=ORD-8F3K2A&key=…&time=…&sign=…
{
"ok": true,
"currency": "\u09F3",
"order": {
"id": "ORD-8F3K2A",
"ref": "ORD-2026-0001",
"product_id": "mobile-legends",
"package_code": "ml-500",
"player_id": "123456789",
"nickname": null,
"quantity": 1,
"amount": 475,
"status": "Completed",
"created_at": "2026-05-30T04:26:40.000Z"
}
}Typical status values: Processing, Completed, Partial, Failed, Refunded.
Failures return a non-2xx status and a JSON body of the form { "error": "…" }.
| Status | Meaning | What to do |
|---|---|---|
400 | Missing key, time or sign / bad parameters | Re-check the request fields. |
401 | Invalid signature, unknown key, or stale time | Re-sign and re-send with a current time. |
402 | Insufficient wallet balance | Top up the reseller wallet, then retry. |
403 | Key disabled / expired, product not allowed, or a spend cap reached | Read the message; adjust the order or ask the admin. |
404 | Order not found for this key | Check the ref / order_code. |
429 | Too many requests | Back off and retry after the Retry-After header. |
500 | Server error | Retry later; no charge is made on failure. |
Idempotency — every order is charged once
ref is required and unique per key. If you send the same ref twice — a retry after a timeout, for instance — the second call does not charge again. It returns the original order with replayed: true, so retrying is always safe:
{
"ok": true,
"replayed": true,
"currency": "\u09F3",
"order": { "id": "ORD-8F3K2A", "ref": "ORD-2026-0001", "amount": 475, "status": "Processing" },
"wallet": { "balance": 12025 }
}Use a fresh ref for every new order. Reusing one will return the old order instead of placing a new one.
Limits
Rate limits
Each key may send up to 120 requests per 10-minute window. Limits apply per key and per source IP; on breach you receive HTTP 429 with a Retry-After header (seconds).
Security notes
time window means a captured request cannot be replayed after 5 minutes.