Продавайте наши товары у себяSell our products on your side
FoxyStars API - для тех, кто хочет перепродавать Telegram Stars, Premium и TON на своём сайте, в своём боте или приложении. Заказы оплачиваются с вашего баланса в @FoxyStarsShopBot по тем же ценам, что в боте, а наценку для своих клиентов вы ставите сами.
FoxyStars API is for resellers who want to sell Telegram Stars, Premium and TON on their website, bot or app. Orders are paid from your balance in @FoxyStarsShopBot at the same prices as in the bot, and you set your own markup for your customers.
Получить ключGet a key
- Откройте @FoxyStarsShopBot и пополните баланс - с него оплачиваются заказы через API.Open @FoxyStarsShopBot and top up your balance - API orders are paid from it.
- Перейдите в Профиль → API и нажмите «Получить ключ».Go to Profile → API and tap “Get key”.
- Сохраните ключ вида
fs_live_…- он показывается один раз. Потеряли - нажмите «Перевыпустить ключ»: старый перестанет работать сразу.Save the keyfs_live_…- it is shown only once. Lost it? Tap “Reissue key”: the old one stops working immediately.
АвторизацияAuthentication
Передавайте ключ в заголовке каждого запроса:
Send the key in a header of every request:
Authorization: Bearer fs_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Можно и заголовком X-API-Key: fs_live_…. Без ключа или с неверным ключом - ответ 401 unauthorized.The X-API-Key: fs_live_… header works too. No key or a wrong key returns 401 unauthorized.
Быстрый стартQuick start
Четыре запроса - и первый заказ готов:
Four requests to your first order:
# 1. балансbalance curl https://api.foxystarsshop.com/v1/balance -H "Authorization: Bearer $KEY" # 2. цена 100 звёздprice for 100 stars curl "https://api.foxystarsshop.com/v1/price?product=stars&quantity=100" -H "Authorization: Bearer $KEY" # 3. заказorder curl -X POST https://api.foxystarsshop.com/v1/orders -H "Authorization: Bearer $KEY" \ -H "Content-Type: application/json" \ -d '{"custom_id":"order-1001","product":"stars","quantity":100,"recipient":"@durov"}' # 4. статус заказа (опрашивайте раз в 3-5 секунд)order status (poll every 3-5 seconds) curl https://api.foxystarsshop.com/v1/orders/123 -H "Authorization: Bearer $KEY"
Формат ответаResponse format
Успех - "ok": true и данные в data. Ошибка - "ok": false и объект error с машинным кодом и понятным описанием.
Success is "ok": true with the payload in data. An error is "ok": false with an error object holding a machine code and a readable message.
{ "ok": true, "data": { "balance": "1250.00", "currency": "RUB" } }
{ "ok": false, "error": { "code": "insufficient_balance", "message": "not enough balance, top it up in the bot", "price": "146.00" } }"146.00"): так не теряется точность. Время - UTC в формате ISO 8601.All amounts are strings in rubles with kopecks ("146.00") so no precision is lost. Times are UTC in ISO 8601.Заказы и статусыOrders & statuses
Заказ выполняется в фоне: POST /orders сразу отвечает 202 со статусом pending, дальше вы опрашиваете GET /orders/{id}. Обычно заказ выполняется за 10-60 секунд.
Orders run in the background: POST /orders replies 202 with status pending right away, then you poll GET /orders/{id}. An order usually completes in 10-60 seconds.
| СтатусStatus | Что значитMeaning | ДеньгиMoney |
|---|---|---|
| pending | Принят, ждёт выполненияAccepted, waiting | ещё не списаныnot charged yet |
| processing | Отправляем получателюBeing delivered | списаныcharged |
| completed | Выполнен, товар у получателя. receipt - номер заказа, как в ботеDone, delivered. receipt is the order number, same as in the bot | списаныcharged |
| failed | Не выполнен, причина в errorNot done, reason in error | refunded: true - списывали и вернули на баланс; false - не списывалиrefunded: true - charged and returned to balance; false - never charged |
custom_id и повторыcustom_id & retries
custom_id - ваш уникальный номер заказа (1-64 символа, например номер заказа на вашем сайте). Он защищает от двойной оплаты:
custom_id is your unique order id (1-64 characters, e.g. the order number on your website). It protects from double charges:
• Повтор запроса с тем же custom_id и теми же данными вернёт уже созданный заказ с пометкой "idempotent_replay": true - второй раз ничего не спишется.
• Тот же custom_id с другими данными - ошибка 409 custom_id_conflict.
• Оборвалась связь, пришёл таймаут или 5xx? Повторите запрос с тем же custom_id - это безопасно.
• Заказ со статусом failed окончательный: чтобы попробовать снова, создайте заказ с новым custom_id.
• Repeating a request with the same custom_id and the same data returns the existing order with "idempotent_replay": true - nothing is charged twice.
• The same custom_id with different data is a 409 custom_id_conflict.
• Connection dropped, timeout or 5xx? Retry with the same custom_id - it is safe.
• An order with status failed is final: to try again, create an order with a new custom_id.
Необязательный max_price - потолок цены: если цена успела вырасти выше него, заказ не создаётся (409 price_changed, в ответе текущая цена).
Optional max_price is a price ceiling: if the price has risen above it, no order is created (409 price_changed, the current price is in the reply).
ТоварыProducts
| product | ТоварProduct | quantity | recipient |
|---|---|---|---|
stars | Telegram Stars | звёзд, от 50 до 25 000stars, 50 to 25,000 | @username в TelegramTelegram @username |
premium | Telegram Premium | месяцев: 3, 6 или 12months: 3, 6 or 12 | @username в TelegramTelegram @username |
ton | Пополнение TONTON top-up | TON, от 1 до 10 000TON, 1 to 10,000 | @username в TelegramTelegram @username |
Получателя можно указать как @durov, durov или t.me/durov. Цены совпадают с ценами бота и меняются вместе с курсом - берите актуальную через GET /price. Другие товары бота появятся в API следующими обновлениями.The recipient can be @durov, durov or t.me/durov. Prices match the bot and follow the exchange rate - get the current one via GET /price. More of the bot's products will come to the API in later updates.
ЛимитыLimits
| ЛимитLimit | ЗначениеValue | При превышенииWhen exceeded |
|---|---|---|
| Запросов на ключRequests per key | 60 в минуту60 per minute | 429 rate_limited + Retry-After |
| Незавершённых заказовActive orders | 5 одновременно5 at a time | 429 too_many_active_orders |
| Размер запросаRequest size | 16 KB | 413 too_large |
ОшибкиErrors
| HTTP | code | Что делатьWhat to do |
|---|---|---|
| 400 | bad_request | Тело - не JSON-объектBody is not a JSON object |
| 401 | unauthorized | Нет ключа или он неверный/отключёнMissing, wrong or disabled key |
| 402 | insufficient_balance | Пополните баланс в боте (в ответе - нужная сумма)Top up in the bot (the reply includes the price) |
| 403 | forbidden | Доступ закрыт - напишите в поддержку ботаAccess denied - contact the bot's support |
| 404 | not_found | Нет такого заказа или методаNo such order or endpoint |
| 409 | custom_id_conflict | custom_id уже занят другим заказомcustom_id is already used by another order |
| 409 | price_changed | Цена выше вашего max_pricePrice is above your max_price |
| 422 | validation_error | Неверный параметр - подробности в messageInvalid parameter - see message |
| 422 | invalid_recipient | Такого пользователя Telegram нетNo such Telegram user |
| 422 | recipient_rejected | Получателю нельзя это купить (например, Premium уже есть)This can't be bought for the recipient (e.g. already has Premium) |
| 429 | rate_limited | Подождите Retry-After секундWait Retry-After seconds |
| 429 | too_many_active_orders | Дождитесь завершения текущих заказовWait for active orders to finish |
| 503 | out_of_stock | Товар временно закончился - повторите позжеTemporarily out of stock - retry later |
| 503 | upstream_unavailable | Поставщик не ответил - повторите с тем же custom_idSupplier didn't respond - retry with the same custom_id |
| 500 | internal_error | Повторите позже с тем же custom_idRetry later with the same custom_id |
Если заказ уже создан, но не выполнился, причина будет в поле error самого заказа: price_changed, out_of_stock, insufficient_balance, supplier_error, upstream_unavailable, interrupted.
If an order was created but not completed, the reason is in the order's own error field: price_changed, out_of_stock, insufficient_balance, supplier_error, upstream_unavailable, interrupted.
МетодыEndpoints
GET/v1/balance
Баланс вашего аккаунта в боте.
Your account balance in the bot.
{ "ok": true, "data": { "balance": "1250.00", "currency": "RUB" } }GET/v1/products
Список товаров и допустимое количество.
Products and allowed quantities.
{ "ok": true, "data": [
{ "product": "stars", "title": "Telegram Stars", "recipient": "Telegram username",
"quantity": { "min": 50, "max": 25000, "unit": "stars" } },
{ "product": "premium", "title": "Telegram Premium", "recipient": "Telegram username",
"quantity": { "choices": [3, 6, 12], "unit": "months" } },
{ "product": "ton", "title": "TON top-up", "recipient": "Telegram username",
"quantity": { "min": 1, "max": 10000, "unit": "TON" } }
] }GET/v1/price?product=stars&quantity=100
Текущая цена. Параметры: product, quantity.
Current price. Parameters: product, quantity.
{ "ok": true, "data": { "product": "stars", "quantity": 100, "unit_price": "1.46", "price": "146.00", "currency": "RUB" } }POST/v1/orders
Создать заказ. Получатель и цена проверяются сразу - до списания денег.
Create an order. The recipient and price are checked right away - before any money is charged.
| ПолеField | ТипType | ОписаниеDescription | |
|---|---|---|---|
custom_id | string | обязательноrequired | Ваш уникальный номер заказа, 1-64 символаYour unique order id, 1-64 characters |
product | string | обязательноrequired | stars · premium · ton |
quantity | integer | обязательноrequired | Количество (см. «Товары»)Quantity (see Products) |
recipient | string | обязательноrequired | @username получателяRecipient @username |
max_price | string | нетoptional | Потолок цены в рубляхPrice ceiling in RUB |
{ "custom_id": "order-1001", "product": "stars", "quantity": 100, "recipient": "@durov", "max_price": "150.00" }{ "ok": true, "data": {
"order_id": 123, "custom_id": "order-1001", "product": "stars", "quantity": 100,
"recipient": "durov", "price": "146.00", "currency": "RUB", "status": "pending",
"refunded": false, "error": null, "receipt": null,
"created_at": "2026-09-29T10:00:00Z", "updated_at": "2026-09-29T10:00:00Z" } }Повтор с тем же custom_id отвечает 200 и "idempotent_replay": true.A retry with the same custom_id replies 200 and "idempotent_replay": true.
GET/v1/orders/{order_id}
Заказ по номеру. Ответ - тот же объект заказа, что выше; готовый заказ выглядит так:
An order by its id. Returns the same order object; a finished order looks like this:
{ "ok": true, "data": { "order_id": 123, "status": "completed", "refunded": false, "error": null, "receipt": "37004512", ... } }GET/v1/orders
Ваши заказы, новые первыми. Параметры: limit (1-100, по умолчанию 20), offset. С параметром custom_id вернёт один заказ по вашему номеру.
Your orders, newest first. Parameters: limit (1-100, default 20), offset. With custom_id it returns a single order by your id.
curl "https://api.foxystarsshop.com/v1/orders?custom_id=order-1001" -H "Authorization: Bearer $KEY"
Примеры кодаCode examples
Заказ с ожиданием результата:
Create an order and wait for the result:
import time, uuid, requests API = "https://api.foxystarsshop.com/v1" H = {"Authorization": "Bearer fs_live_..."} order = requests.post(f"{API}/orders", headers=H, timeout=60, json={ "custom_id": str(uuid.uuid4()), # your order number "product": "stars", "quantity": 100, "recipient": "@durov", }).json() if not order["ok"]: raise SystemExit(order["error"]) oid = order["data"]["order_id"] while True: o = requests.get(f"{API}/orders/{oid}", headers=H, timeout=30).json()["data"] if o["status"] in ("completed", "failed"): break time.sleep(4) print(o["status"], o["error"])
const API = "https://api.foxystarsshop.com/v1"; const H = { Authorization: "Bearer fs_live_...", "Content-Type": "application/json" }; const r = await fetch(`${API}/orders`, { method: "POST", headers: H, body: JSON.stringify({ custom_id: crypto.randomUUID(), product: "premium", quantity: 3, recipient: "@durov", }) }).then(r => r.json()); if (!r.ok) throw new Error(r.error.code); let o; do { await new Promise(s => setTimeout(s, 4000)); o = (await fetch(`${API}/orders/${r.data.order_id}`, { headers: H }).then(r => r.json())).data; } while (o.status === "pending" || o.status === "processing"); console.log(o.status, o.error);
<?php $api = "https://api.foxystarsshop.com/v1"; $h = ["Authorization: Bearer fs_live_...", "Content-Type: application/json"]; function call($m, $url, $h, $body = null) { $c = curl_init($url); curl_setopt_array($c, [CURLOPT_CUSTOMREQUEST => $m, CURLOPT_HTTPHEADER => $h, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 60]); if ($body) curl_setopt($c, CURLOPT_POSTFIELDS, json_encode($body)); return json_decode(curl_exec($c), true); } $r = call("POST", "$api/orders", $h, ["custom_id" => "shop-" . time(), "product" => "ton", "quantity" => 5, "recipient" => "@durov"]); if (!$r["ok"]) die($r["error"]["code"]); do { sleep(4); $o = call("GET", "$api/orders/" . $r["data"]["order_id"], $h)["data"]; } while (in_array($o["status"], ["pending", "processing"])); echo $o["status"];
БезопасностьSecurity
Все запросы - только по HTTPS. Вы покупаете у нас по ценам бота и сами назначаете цену своим клиентам.
All requests go over HTTPS only. You buy from us at the bot's prices and set your own prices for your customers.
