Partner API
Покупайте Telegram Stars и Premium для клиентов своего магазина, бота или сайта по HTTP. Деньги сразу списываются с вашего кошелька YuDrop, доставка — автоматическая, как обычно.
Как подключиться
- Партнёрство согласуется с магазином: напишите в чат поддержки — задаются скидка и дневной лимит.
- Ключ (yd_live_…) и секрет webhook приходят вам от бота. Команда /partner в боте показывает статус.
- Кошелёк пополняется как обычно в приложении; цена каждого заказа — базовая минус ваша скидка.
Авторизация
Добавляйте к каждому запросу заголовок Authorization: Bearer <ключ>. Никому не передавайте ключ — он покупает с вашего кошелька. Нужен новый ключ — напишите магазину: старый сразу отключится.
https://tgstars.uz/partner/v1
Запросы
/partner/v1/meПартнёр: баланс, скидка, покупки и лимит за сегодня, webhook.
/partner/v1/pricesВаши цены: цена 1 Stars, примеры, периоды Premium.
/partner/v1/recipientПроверка получателя: {"product", "username"}.
/partner/v1/ordersЗаказ: {"product", "recipient", "quantity" | "months", "ref", "expected_amount"?}.
/partner/v1/ordersСписок заказов: ?limit=1..100&before=<id>.
/partner/v1/orders/{id}Статус заказа.
/partner/v1/orders/ref/{ref}Заказ по вашему ref.
/partner/v1/orders/{id}/refundВернуть деньги за задержанный заказ на кошелёк.
/partner/v1/webhookАдрес webhook: {"url": "https://…" | null, "rotate_secret"?: true}.
Создание заказа
Для Stars quantity — 50…100000; для Premium months — 3, 6, 12. ref — ваш номер заказа (1–64 символа): повторный запрос с тем же ref возвращает тот же заказ и не покупает дважды (ответ 200, created: false). Тот же ref с другим товаром/получателем/количеством — 409 ref_conflict. expected_amount — максимальная сумма, которую вы ожидаете: если цена выше, заказ не создаётся (409 quote_changed). Получатель проверяется через Fragment до списания денег.
curl -X POST https://tgstars.uz/partner/v1/orders \
-H "Authorization: Bearer yd_live_…" \
-H "Content-Type: application/json" \
-d '{"product": "stars", "recipient": "@username", "quantity": 100, "ref": "shop-order-1001"}'
HTTP/1.1 201 Created
{"order": {"id": 1234, "ref": "shop-order-1001", "product": "stars", "recipient": "username", "quantity": 100,
"amount": 22000, "currency": "UZS", "status": "processing", "created_at": "2026-10-28T12:00:00Z",
"paid_at": "2026-10-28T12:00:00Z", "delivered_at": null}, "created": true}
Статусы
processingОплачен, доставляется (обычно несколько минут).
deliveredДоставлен.
cancelledОтменён; при refunded: true деньги вернулись на кошелёк. reason: recipient_not_found / already_premium / recipient_restricted (исправьте получателя и отправьте заново с новым ref), refunded (возврат из-за задержки) или cancelled.
expired / pendingЗаказ без завершённой оплаты (редко: например, если запрос оборвался). Отправьте тот же ref ещё раз — оплата завершится.
Ошибки
Ответ: {"error": "код", "message": "…"}. 400 неверный запрос · 401 нет ключа или он неверный · 402 не хватает денег на кошельке (wallet_low) · 403 приостановлен или дневной лимит · 404 не найдено (и recipient_not_found) · 409 ref_conflict / quote_changed / refund_too_early · 422 already_premium · 429 слишком много запросов (Retry-After) · 503 сервис временно недоступен.
Webhook
События: order.delivered, order.cancelled, order.expired, order.delayed (оплачен, но задерживается — можно /refund). Тело — JSON: {"id", "event", "created_at", "order": {…}}. Подпись: X-YuDrop-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<body>")>. Пока нет ответа 2xx, повтор через 1 мин, 5 мин, 30 мин, 2 ч, 6 ч, 12 ч и 24 ч; событие может прийти несколько раз — отбрасывайте повторы по X-YuDrop-Delivery (id). Только https и публичные серверы; редиректы не выполняются.
Проверка подписи (Python)
import hashlib, hmac, time
def verified(secret: str, header: str, body: bytes, tolerance: int = 300) -> bool:
parts = dict(item.split("=", 1) for item in header.split(","))
stamp, signature = parts.get("t", ""), parts.get("v1", "")
expected = hmac.new(secret.encode(), stamp.encode() + b"." + body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature) and abs(time.time() - int(stamp or 0)) <= tolerance
Ограничения
На один ключ — 120 запросов чтения и 60 записи в минуту (всплеск до 120 / 30). С одного адреса — 20 попыток с неверным ключом в минуту.