Промокоды через API
Публичная документация для серверной интеграции: выпуск токенных и безлимитных кодов, проверка активации, баланс продавца и готовые примеры.
https://emeraldai.sbs/seller/v1Первый запрос
Получите роль
Администратор включает роль продавца для обычного аккаунта Emerald.
Создайте ключ
В кабинете продавца выпустите отдельный ключ с префиксом sk-em-seller-.
Работайте с API
Передавайте ключ как Bearer‑токен и отправляйте JSON с вашего сервера.
Все endpoints
/accountБаланс и действующие тарифы/promo-codesСоздать от 1 до 100 кодов/promo-codesСписок кодов продавца/promo-codes/{code}Состояние конкретного кода/api-keysВыпустить клиентские API-ключи/api-keysСписок клиентских API-ключей/api-keys/{id}/top-upПополнить баланс ключаВсе ответы имеют тип application/json. Временные метки возвращаются в UTC и формате ISO 8601.
Авторизация
Seller API‑ключ используется только сервером продавца и не даёт доступа к AI‑запросам Emerald.
Authorization: Bearer sk-em-seller-... Content-Type: application/json
Баланс и актуальные тарифы
/accountПолучайте стоимость из этого endpoint перед массовым выпуском: тарифы могут быть изменены на стороне Emerald.
{
"data": {
"balance_tokens": 5000000,
"pricing": {
"minimum_token_promo": 10000,
"unlimited_minute_tokens": 120000,
"maximum_unlimited_minutes": 43200
}
}
}Стоимость выпуска
от 10 000Номинал одного токенного кода120 000 / мин.От 1 до 43200 минутстоимость одного кода × quantity. При активации покупателем повторного списания нет.Параметры создания
typestringtokens или unlimited, обязательноtoken_amountinteger10000–1 000 000 000, только для tokensduration_minutesinteger1–43200, только для unlimitedquantityintegerОт 1 до 100, по умолчанию 1prefixstringДо 10 букв A–Z и цифр; остальные символы удаляютсяexpires_atstring | nullБудущее время ISO 8601, например 2026-12-31T23:59:59ZТокенные промокоды
/promo-codesПосле ввода такого кода токены сразу начисляются пользователю. Каждый выпущенный продавцом код одноразовый.
curl https://emeraldai.sbs/seller/v1/promo-codes \
-H "Authorization: Bearer sk-em-seller-..." \
-H "Content-Type: application/json" \
-d '{
"type": "tokens",
"token_amount": 500000,
"quantity": 2,
"prefix": "SHOP",
"expires_at": "2026-12-31T23:59:59Z"
}'Безлимитные промокоды
/promo-codesВведённый код попадает в «Мои безлимитные призы». Таймер не начинается при вводе: покупатель отдельно нажимает «Забрать и запустить».
curl https://emeraldai.sbs/seller/v1/promo-codes \
-H "Authorization: Bearer sk-em-seller-..." \
-H "Content-Type: application/json" \
-d '{
"type": "unlimited",
"duration_minutes": 60,
"quantity": 1,
"prefix": "TIME"
}'Ответ после создания
data содержит каждый созданный код, а meta — итоговый резерв и новый остаток общего баланса.
{
"data": [{
"id": 184,
"code": "SHOP-4EAC013F2B",
"type": "tokens",
"token_amount": 500000,
"duration_minutes": null,
"reserved_tokens": 500000,
"status": "available",
"is_redeemed": false,
"created_at": "2026-09-04T12:00:00Z",
"expires_at": null,
"activation": null
}],
"meta": {"reserved_tokens": 500000, "balance_tokens": 4500000}
}Проверка активации
/promo-codes/{code}availableДоступенКод можно ввестиredeemedАктивированТокены начисленыredeemed_pending_activationОжидает запускаБезлимит получен, таймер ещё не запущенactiveРаботаетБезлимит сейчас активенendedЗавершёнВремя безлимита истеклоexpiredПросроченСрок ввода закончилсяclosedЗакрытКод больше недоступен{
"data": {
"code": "TIME-XXXXXXXXXX",
"type": "unlimited",
"duration_minutes": 60,
"reserved_tokens": 7200000,
"status": "active",
"is_redeemed": true,
"activation": {
"redeemed_at": "2026-09-04T15:00:00Z",
"activated_at": "2026-09-04T15:05:00Z",
"active_until": "2026-09-04T16:05:00Z"
}
}
}Список и пагинация
/promo-codes?limit=50&offset=0Возвращаются только коды текущего продавца, от новых к старым. limit — от 1 до 100, offset — целое число от 0.
{
"data": [/* промокоды */],
"meta": {"total": 238, "limit": 50, "offset": 0}
}Клиентские API-ключи для общей витрины
Для продаж на FunPay можно выпустить отдельные ключи, которые работают только через https://emeraldai.beer/v1. На самой витрине нет регистрации и оплаты: покупатель получает ключ у продавца, вводит его для проверки баланса и использует как обычный OpenAI-совместимый API key.
/api-keyscurl https://emeraldai.sbs/seller/v1/api-keys \
-H "Authorization: Bearer sk-em-seller-..." \
-H "Content-Type: application/json" \
-d '{
"name": "FunPay order #12345",
"token_amount": 500000,
"quantity": 1,
"target": "funpay_shared"
}'target поддерживает значения auto, public, funpay_shared и seller_site. Для общей FunPay-витрины используйте funpay_shared. Такой ключ специально отключён на обычном публичном /v1 основного Emerald и принимается только gateway-сайтом.
{
"data": [{
"id": 501,
"name": "FunPay order #12345",
"prefix": "sk-em-...",
"balance_tokens": 500000,
"is_active": false,
"target": "funpay_shared",
"api_key": "sk-em-..."
}],
"meta": {
"funded_tokens": 500000,
"balance_tokens": 4500000
}
}/api-keysВозвращает все клиентские ключи продавца с текущим балансом и полем target. Полное значение ключа возвращается только при создании через API и хранится в кабинете в зашифрованном виде.
/api-keys/{id}/top-upcurl https://emeraldai.sbs/seller/v1/api-keys/501/top-up \
-H "Authorization: Bearer sk-em-seller-..." \
-H "Content-Type: application/json" \
-d '{"token_amount": 250000}'Готовый клиент на requests
import os
import requests
BASE_URL = "https://emeraldai.sbs/seller/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['EMERALD_SELLER_API_KEY']}",
"Content-Type": "application/json",
}
response = requests.post(
f"{BASE_URL}/promo-codes",
headers=HEADERS,
json={"type": "unlimited", "duration_minutes": 60, "quantity": 1, "prefix": "TIME"},
timeout=20,
)
response.raise_for_status()
promo = response.json()["data"][0]
print(promo["code"], promo["status"])Готовый клиент на fetch
const baseUrl = "https://emeraldai.sbs/seller/v1";
const response = await fetch(`${baseUrl}/promo-codes`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.EMERALD_SELLER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({type: "tokens", token_amount: 500000, quantity: 1, prefix: "SHOP"}),
});
const payload = await response.json();
if (!response.ok) throw new Error(payload.error?.message);
console.log(payload.data[0]);Коды ответа
invalid_json / invalid_*Неверный JSON, параметры, дата или пагинацияinvalid_api_keyКлюч отсутствует, отозван или передан не как Bearerinsufficient_balanceНедостаточно токенов; есть available_tokens и required_tokensseller_disabled / access_deniedРоль отключена или доступ заблокированpromo_not_foundКод не существует или принадлежит другому продавцу{
"error": {
"code": "invalid_quantity",
"message": "quantity должен быть от 1 до 100."
}
}Безопасная интеграция
Храните ключ в secret/env
Передавайте через секреты хостинга и не печатайте в логах.
Ограничьте свой маршрут
Не позволяйте клиенту напрямую задавать произвольный номинал.
Перевыпустите при утечке
Ротация мгновенно отключает старое значение ключа.
Проверяйте весь ответ
Сначала HTTP‑код, затем error.code; таймаут не означает успех.
GET /promo-codes.