Каталог

Скачайте полный каталог продуктов и работайте с ним офлайн

Просмотр в формате Markdown

Полный каталог продуктов — каждый товар, доступный для заказа, с его ценой, запасом, типом продукта и формой ввода — публикуется как единый снимок для скачивания. Вы скачиваете его, читаете локально и используете id каждого товара и его fields, чтобы размещать заказы. Нет пагинированного эндпоинта «list products» для программного использования; снимок и есть каталог.

URL для скачивания:

https://downloads.voodoo.center/catalog.lmdb.zst

Предоставляется через CDN cdn.voodoo.center. Для скачивания аутентификация не требуется.

Персональный каталог

URL выше предоставляет глобальный каталог, который использует стандартные цены. Если ваш аккаунт имеет персональные (согласованные) цены — переопределения цены для отдельных товаров — существует отдельный персональный каталог, опубликованный по URL, содержащему client id вашего аккаунта. Он содержит те же записи, но price и subscriber_price отражают цены вашего аккаунта. Используйте персональный файл, если он существует; иначе используйте глобальный.

URL для скачивания персонального каталога:

https://downloads.voodoo.center/{client_id}.lmdb.zst

Найдите свой Client ID — и готовый к использованию URL персонального каталога — на странице API в дашборде (та же страница, где вы управляете API-ключами и webhook). Не каждый аккаунт имеет персональные цены: если ваш не имеет, этот URL возвращает 404 — в таком случае вернитесь к catalog.lmdb.zst.

Это тот же формат и схема, что и у глобального каталога (сжатая zstd однофайловая база данных LMDB); единственное различие — значения цен. Итак: попробуйте свой персональный URL, вернитесь к глобальному при 404, а затем распакуйте, откройте и прочитайте файл точно так, как показано ниже.

Выберите URL каталога с резервным вариантом (Python)
1import urllib.error
2import urllib.request
3
4GLOBAL_URL = "https://downloads.voodoo.center/catalog.lmdb.zst"
5PERSONAL_URL = "https://downloads.voodoo.center/{client_id}.lmdb.zst"
6
7
8def download_catalog(client_id: str, dest: str = "catalog.lmdb.zst") -> str:
9 # Предпочитаем персональный каталог (ваши согласованные цены); возвращаемся
10 # к глобальному, если у этого аккаунта нет персонального файла (404 на персональном URL).
11 try:
12 urllib.request.urlretrieve(PERSONAL_URL.format(client_id=client_id), dest)
13 except urllib.error.HTTPError as exc:
14 if exc.code != 404:
15 raise
16 urllib.request.urlretrieve(GLOBAL_URL, dest)
17 return dest
18
19
20# Возьмите свой client id со страницы API в дашборде.
21download_catalog("your-client-id") # -> catalog.lmdb.zst
22# Теперь распакуйте, откройте и прочитайте его точно так, как показано ниже.

Что вы получаете

catalog.lmdb.zst — это однофайловая база данных LMDB, сжатая с помощью zstandard:

  • Один файл, одно пространство ключей. Товары хранятся в базе данных LMDB по умолчанию. Каждый товар — это одна запись: ключ = 8-байтный item id в формате big-endian, значение = компактный JSON-объект.
  • Самодостаточные записи. Каждый товар встраивает полную форму ввода (fields, где каждое поле выбора имеет свои options) встроенно, поэтому единственный поиск по ключу даёт вам всё необходимое для заказа этого товара.
  • Маленький и быстрый. Полный каталог сжимается примерно в 45× (база данных ~1,5 МБ → ~34 КБ). Вы распаковываете один раз, а затем отображаете базу данных в память и читаете её без обращений к серверу.

Цены в каталоге указаны в центах (целые числа) и отражают стандартные цены. Ваше финальное списание всегда подтверждается ответом заказа и вашим балансом — см. Размещение заказов.

Скачивание и открытие

Установите два ридера, а затем скачайте → распакуйте → откройте только для чтения.

Установка зависимостей
$pip install zstandard lmdb
Скачивание и распаковка (shell)
$# Скачайте сжатый снимок
$curl -o catalog.lmdb.zst https://downloads.voodoo.center/catalog.lmdb.zst
$
$# Распакуйте zstd-фрейм в однофайловую базу данных LMDB
$zstd -d catalog.lmdb.zst -o catalog.lmdb # или: unzstd catalog.lmdb.zst
Скачивание, распаковка и чтение (Python)
1import json
2import struct
3import urllib.request
4
5import lmdb
6import zstandard
7
8CATALOG_URL = "https://downloads.voodoo.center/catalog.lmdb.zst"
9
10
11def item_key(item_id: int) -> bytes:
12 # Записи индексируются 8-байтным item id в формате big-endian (поэтому сортируются по id).
13 return struct.pack(">Q", item_id)
14
15
16# 1. Скачайте сжатый снимок.
17urllib.request.urlretrieve(CATALOG_URL, "catalog.lmdb.zst")
18
19# 2. Потоково распакуйте zstd-фрейм в однофайловую базу данных LMDB.
20dctx = zstandard.ZstdDecompressor()
21with open("catalog.lmdb.zst", "rb") as fin, open("catalog.lmdb", "wb") as fout:
22 dctx.copy_stream(fin, fout)
23
24# 3. Откройте окружение только для чтения. Это один ФАЙЛ, а не каталог (subdir=False),
25# и читатели в режиме только для чтения должны передавать lock=False.
26env = lmdb.open("catalog.lmdb", subdir=False, readonly=True, lock=False)
27
28# Найдите один товар по id.
29with env.begin() as txn:
30 raw = txn.get(item_key(4211))
31 item = json.loads(raw) if raw else None
32 print(item)
33
34# Итерируйте весь каталог (записи выходят упорядоченными по id).
35with env.begin() as txn:
36 for key, value in txn.cursor():
37 item = json.loads(value)
38 if item["in_stock"]:
39 price = item["price"] / 100 # центы -> основные единицы
40 print(item["id"], item["product_type"], f"{price:.2f}", item["name"])

★ Пояснение ───────────────────────────────────── LMDB отображается в память, поэтому открытие файла практически бесплатно, а поиски читаются прямо из кеша страниц ОС — вы можете держать окружение открытым и обращаться к нему миллионы раз, ничего не перечитывая заново. Именно поэтому каталог поставляется как LMDB, а не как один огромный JSON-массив. ─────────────────────────────────────────────────

Схема записи

Каждое значение — это JSON-объект:

ПолеТипОписание
idцелое числоId товара. Передайте его как item_id при размещении заказа.
nameстрокаЧитабельное название товара.
product_typeстрокаkey, topup или service — определяет правила количества/полей при заказе.
min_quantityчислоМинимальное количество для заказа.
max_quantityчислоМаксимальное количество для заказа (фактический предел).
priceцелое число (центы)Стандартная цена. Разделите на 100, чтобы получить основные единицы.
base_priceцелое число (центы)Первоначальная/каталожная цена. Когда она больше price, показывайте её зачёркнутой.
subscriber_priceцелое число (центы)Цена с активной подпиской.
amount_per_priceчислоЕдиниц, доставляемых на единицу цены (актуально для пополнений).
in_stockлогическое значениеДоступен ли товар для заказа сейчас.
updated_atстрока (ISO 8601)Когда этот товар менялся в последний раз.
fieldsмассивФорма ввода товара — см. ниже.

Каждая запись в fields:

ПолеТипОписание
idцелое числоId поля.
nameстрокаКлюч поля — используйте его как ключ в объекте fields заказа.
typeстрокаstring, integer, email, url или choice.
requiredлогическое значениеНужно ли предоставлять значение.
optionsмассивТолько для полей choice: [{ "id": <int>, "value": "<label>" }, …].
Пример записи (товар типа top-up)
1{
2 "id": 4211,
3 "name": "Sample Game Top-up",
4 "product_type": "topup",
5 "min_quantity": 1,
6 "max_quantity": 1000,
7 "price": 1250,
8 "base_price": 1250,
9 "subscriber_price": 1150,
10 "amount_per_price": 1,
11 "in_stock": true,
12 "updated_at": "2026-07-05T12:00:00+00:00",
13 "fields": [
14 { "id": 88, "name": "player_id", "type": "string", "required": true, "options": [] },
15 {
16 "id": 91, "name": "server", "type": "choice", "required": true,
17 "options": [
18 { "id": 17, "value": "Europe (EU-West)" },
19 { "id": 18, "value": "North America" }
20 ]
21 }
22 ]
23}

Использование каталога с Orders API

Всё, что нужно для построения запроса POST /api/v1/orders, есть в записи:

  • item_id = id записи.
  • quantity — ограничена min_quantity/max_quantity. Обязательна для topup (десятичная) и key (целая, по умолчанию 1); пропустите для service.
  • fields — обязательны только для topup и service. Индексируйте каждую запись по name поля. Для поля choice отправляйте id выбранного варианта (целое число), а не его value. Для текстовых полей отправляйте строку.
Превращение записи каталога в заказ (Python)
1# `item` — это запись, прочитанная из каталога выше; `access_token` — ваш
2# Bearer-токен (см. Аутентификация).
3import urllib.request, json
4
5body = {
6 "item_id": item["id"],
7 "quantity": 10, # в пределах min_quantity..max_quantity
8 "merchant_order_id": "po-10232",
9 "fields": {
10 "player_id": "123456789", # текстовое поле -> его строковое значение
11 "server": 17, # поле выбора -> id варианта
12 },
13}
14req = urllib.request.Request(
15 "https://api.voodoo.center/api/v1/orders",
16 data=json.dumps(body).encode(),
17 headers={"Authorization": f"Bearer {access_token}", "Content-Type": "application/json"},
18 method="POST",
19)
20order = json.loads(urllib.request.urlopen(req).read())
21print(order["id"], order["status"])

Поддержание актуальности

Снимок регулярно перегенерируется. Его свежесть — это HTTP-заголовки ETag / Last-Modified объекта; используйте условный запрос, чтобы повторно скачивать только тогда, когда он действительно изменился:

Повторное скачивание только при изменении
$# -z заставляет curl отправлять If-Modified-Since на основе mtime локального файла;
$# 304 оставляет ваш файл без изменений.
$curl -o catalog.lmdb.zst -z catalog.lmdb.zst https://downloads.voodoo.center/catalog.lmdb.zst

Простой и надёжный подход для работающей интеграции: обновляйте по расписанию (например, каждые несколько минут) условным запросом выше, и когда приходит новый файл, распаковывайте его и заменяйте открытое окружение LMDB.