Seller API v1 · Online

Промокоды через API

Публичная документация для серверной интеграции: выпуск токенных и безлимитных кодов, проверка активации, баланс продавца и готовые примеры.

https://emeraldai.sbs/seller/v1
JSONBearer tokenДо 100 кодовСтатусы активацииПубличный справочник
БЫСТРЫЙ СТАРТ

Первый запрос

01

Получите роль

Администратор включает роль продавца для обычного аккаунта Emerald.

02

Создайте ключ

В кабинете продавца выпустите отдельный ключ с префиксом sk-em-seller-.

03

Работайте с API

Передавайте ключ как Bearer‑токен и отправляйте JSON с вашего сервера.

Документация открыта без входа. Авторизация нужна только для кабинета продавца и самих API‑запросов.
СПРАВОЧНИК

Все endpoints

GET/accountБаланс и действующие тарифы
POST/promo-codesСоздать от 1 до 100 кодов
GET/promo-codesСписок кодов продавца
GET/promo-codes/{code}Состояние конкретного кода
POST/api-keysВыпустить клиентские API-ключи
GET/api-keysСписок клиентских API-ключей
POST/api-keys/{id}/top-upПополнить баланс ключа

Все ответы имеют тип application/json. Временные метки возвращаются в UTC и формате ISO 8601.

БЕЗОПАСНОСТЬ

Авторизация

Seller API‑ключ используется только сервером продавца и не даёт доступа к AI‑запросам Emerald.

HTTP headers
Authorization: Bearer sk-em-seller-...
Content-Type: application/json
Не передавайте ключ в браузер. Не добавляйте его в клиентский JavaScript, мобильный APK, логи или публичный Git‑репозиторий.
GET

Баланс и актуальные тарифы

GET/account

Получайте стоимость из этого endpoint перед массовым выпуском: тарифы могут быть изменены на стороне Emerald.

Response · 200
{
  "data": {
    "balance_tokens": 5000000,
    "pricing": {
      "minimum_token_promo": 10000,
      "unlimited_minute_tokens": 120000,
      "maximum_unlimited_minutes": 43200
    }
  }
}
РЕЗЕРВИРОВАНИЕ

Стоимость выпуска

TOKENSот 10 000Номинал одного токенного кода
UNLIMITED120 000 / мин.От 1 до 43200 минут
Баланс общий. Средства резервируются сразу: стоимость одного кода × quantity. При активации покупателем повторного списания нет.
JSON BODY

Параметры создания

ПолеТипОписание
typestringtokens или unlimited, обязательно
token_amountinteger10000–1 000 000 000, только для tokens
duration_minutesinteger1–43200, только для unlimited
quantityintegerОт 1 до 100, по умолчанию 1
prefixstringДо 10 букв A–Z и цифр; остальные символы удаляются
expires_atstring | nullБудущее время ISO 8601, например 2026-12-31T23:59:59Z
POST

Токенные промокоды

POST/promo-codes

После ввода такого кода токены сразу начисляются пользователю. Каждый выпущенный продавцом код одноразовый.

cURL
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"
  }'
POST

Безлимитные промокоды

POST/promo-codes

Введённый код попадает в «Мои безлимитные призы». Таймер не начинается при вводе: покупатель отдельно нажимает «Забрать и запустить».

cURL
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"
  }'
RESPONSE · 201

Ответ после создания

data содержит каждый созданный код, а meta — итоговый резерв и новый остаток общего баланса.

JSON
{
  "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}
}
GET

Проверка активации

GET/promo-codes/{code}
statusЗначениеЧто произошло
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"
    }
  }
}
GET

Список и пагинация

GET/promo-codes?limit=50&offset=0

Возвращаются только коды текущего продавца, от новых к старым. limit — от 1 до 100, offset — целое число от 0.

Pagination meta
{
  "data": [/* промокоды */],
  "meta": {"total": 238, "limit": 50, "offset": 0}
}
FUNPAY · EMERALDAI.BEER

Клиентские API-ключи для общей витрины

Для продаж на FunPay можно выпустить отдельные ключи, которые работают только через https://emeraldai.beer/v1. На самой витрине нет регистрации и оплаты: покупатель получает ключ у продавца, вводит его для проверки баланса и использует как обычный OpenAI-совместимый API key.

POST/api-keys
Создать ключ для emeraldai.beer
curl 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-сайтом.

Response · 201
{
  "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
  }
}
GET/api-keys

Возвращает все клиентские ключи продавца с текущим балансом и полем target. Полное значение ключа возвращается только при создании через API и хранится в кабинете в зашифрованном виде.

POST/api-keys/{id}/top-up
Пополнить ключ
curl 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}'
Для FunPay не добавляйте внешнюю оплату на emeraldai.beer. Денежная часть заказа остаётся на площадке; сайт только проверяет выданный ключ, показывает баланс/модели и проксирует AI API.
PYTHON

Готовый клиент на requests

Python 3
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"])
NODE.JS

Готовый клиент на fetch

JavaScript · Node 18+
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]);
ОШИБКИ

Коды ответа

HTTPcodeЗначение
400invalid_json / invalid_*Неверный JSON, параметры, дата или пагинация
401invalid_api_keyКлюч отсутствует, отозван или передан не как Bearer
402insufficient_balanceНедостаточно токенов; есть available_tokens и required_tokens
403seller_disabled / access_deniedРоль отключена или доступ заблокирован
404promo_not_foundКод не существует или принадлежит другому продавцу
Error envelope
{
  "error": {
    "code": "invalid_quantity",
    "message": "quantity должен быть от 1 до 100."
  }
}
ПРАКТИКА

Безопасная интеграция

Храните ключ в secret/env

Передавайте через секреты хостинга и не печатайте в логах.

Ограничьте свой маршрут

Не позволяйте клиенту напрямую задавать произвольный номинал.

Перевыпустите при утечке

Ротация мгновенно отключает старое значение ключа.

Проверяйте весь ответ

Сначала HTTP‑код, затем error.code; таймаут не означает успех.

Повтор POST создаст новые коды. Если соединение оборвалось после отправки, сначала проверьте последние записи через GET /promo-codes.