Хостинг

API автора сборки: коды активации и обновления

Как автору платной сборки выдавать коды активации и публиковать обновления через API Millida Hosting: версии сборки, заливка архива, публикация, откат, статус кода и вебхук.

Обновлено 7 августа 2026 г.

Эта статья — для авторов платных сборок, которые продают их сами, а установку на сервер отдают нам. Покупателю при этом ничего скачивать не нужно: он вводит код и получает поднятую сборку. Как это выглядит с его стороны — Платная сборка по коду активации.

Что нужно, чтобы подключиться

  1. Прислать нам серверный архив сборки.zip с mods/ в корне (без обёртки вида Server Files/) или .mrpack. Архив лежит у нас в приватном хранилище, ссылка наружу не отдаётся никогда.
  2. Сказать ядро, версию игры и минимальную память — по ним мастер отсеет тарифы, на которых сборка не запустится.
  3. Получить от нас ключ сборки (key, например arcania) и токен выдачи — им ваш сайт печатает коды.

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

Как устроена схема

  • Оплату принимаете вы, у себя.
  • После оплаты ваш сайт дёргает наш API и получает код активации.
  • Код вы отдаёте покупателю — письмом, ботом, на странице «спасибо».
  • Покупатель вводит код у нас и получает сервер со сборкой на платном тарифе.
  • Файлы сборки на сервере закрыты: скачать mods нельзя ни из панели, ни по SFTP.

Физически покупатель серверную сборку в руки не получает — только работающий сервер.

Адрес и авторизация

Базовый адрес — https://millida.net/v2/hosting.

Токен передаётся заголовком X-Pack-Token. Он не JWT и не Bearer — это отдельный секрет вашей сборки.

X-Pack-Token: mpk_pack_XXXXXXXXXXXXXXXX
Content-Type: application/json

Токен живёт на вашем сервере — держите его в переменных окружения, не в коде фронта.

Выпустить коды

POST /v2/hosting/packs/{key}/keys

ПолеТипПо умолчаниюЧто делает
countчисло 1–2001Сколько кодов напечатать за вызов
noteстрока до 120Ваша пометка: номер заказа, ник покупателя
maxServersчисло 1–201На сколько серверов можно активировать один код
expiresAtдата ISOСрок годности кода
curl -X POST https://millida.net/v2/hosting/packs/arcania/keys \
  -H "X-Pack-Token: $PACK_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"count": 1, "note": "заказ 4821"}'
{
  "code": "A7K2-9MHD-4RTP-QW38",
  "codes": ["A7K2-9MHD-4RTP-QW38"]
}

Поле code — первый код партии, оставлено для совместимости; при count > 1 берите codes.

Коды возвращаются только здесь и больше нигде. У нас хранится их хеш — как пароль. Если код потерялся у вас, восстановить его мы не можем: выпускайте новый и отзывайте старый.

Лимит — 30 запросов в минуту на сборку. Партия до 200 кодов за вызов сделана как раз для распродаж: печатайте пачкой, а не по одному коду в запросе.

Что стало с кодами

GET /v2/hosting/packs/{key}/keys?limit=100

[
  {
    "codeHint": "A7K29MHD",
    "note": "заказ 4821",
    "maxServers": 1,
    "usedCount": 1,
    "state": "spent",
    "expiresAt": null,
    "revokedAt": null,
    "createdAt": "2026-08-03T12:20:11.000Z"
  }
]

Самих кодов в ответе нет и быть не может. codeHint — начало кода, по нему вы свяжете строку со своим заказом.

Состояния: free — не использован, spent — израсходован, expired — истёк срок, revoked — отозван вами.

Проверить один код

POST /v2/hosting/packs/{key}/keys/status, тело {"code": "A7K2-9MHD-4RTP-QW38"}.

Ответ — та же строка, что и в списке. Код идёт телом, а не в адресе: адреса оседают в логах прокси и в истории браузера, а до активации код — рабочий ключ.

Дефисы и регистр не важны: a7k29mhd4rtpqw38 найдётся так же, как A7K2-9MHD-4RTP-QW38.

Отозвать код

POST /v2/hosting/packs/{key}/keys/revoke, тело {"code": "..."}.

Нужен при возврате денег, ошибочной выдаче или споре. Отзыв закрывает будущие активации, но не снимает уже поставленную сборку — покупатель, который её активировал, останется с рабочим сервером.

Вебхук об активации

Если вы дадите нам адрес вебхука, мы позовём его в момент, когда код сработал:

POST <ваш адрес>
X-Millida-Pack: arcania
Content-Type: application/json

{
  "event": "pack.activated",
  "packKey": "arcania",
  "codeHint": "A7K29MHD",
  "serverId": "cm4x...",
  "activatedAt": "2026-08-04T09:14:02.000Z"
}

Подписи у вызова нет: проверить факт можно тем же токеном через keys/status — по codeHint вы найдёте свою строку и увидите state: "spent". Так вам не приходится хранить второй секрет.

Вебхук отправляется без ожидания ответа и не повторяется: если ваш сервер лежал, активация всё равно прошла, а увидеть её вы сможете в списке кодов. Адрес должен быть публичным — на внутренние и локальные адреса мы не ходим. Редиректы не выполняются.

Карточка сборки

GET /v2/hosting/packs/{key} — публичная, без токена. Отдаёт то, что видит покупатель: название, ядро, версию, минимум памяти, список тарифов и флаги защит. Ссылки на архив в ответе нет.

Удобно для страницы «Купить» на вашем сайте: требования к тарифу берутся из одного источника и не расходятся с тем, что скажет наш мастер.

Витринные поля своей карточки вы правите сами: PATCH /v2/hosting/packs/{key} с токеном принимает name, authorName, authorUrl, iconUrl, webhookUrl. Условия продажи (paidOnly, requireKey, lockFiles, planCodes), включение сборки на витрине и флаги запуска JVM токеном не меняются — это наш договор с вами и наши ноды, по ним пишите нам.

Обновления сборки

Раньше обновление означало письмо нам и ожидание. Теперь вы публикуете версию сами, а владельцы серверов выбирают её у себя в панели.

Ключевое: мы никого не обновляем молча. Переход между версиями сборки бывает несовместимым с миром, и решение принимает владелец сервера. Опубликованная версия — то, что получают новые серверы и что мы предлагаем поставленным; прежние версии остаются в списке, и с них можно не уходить или откатиться назад.

Как выглядит цикл

# 1. Завести версию
curl -X POST https://millida.net/v2/hosting/packs/arcania/versions \
  -H "X-Pack-Token: $PACK_TOKEN" -H "Content-Type: application/json" \
  -d '{"label":"1.5.0","changelog":"Обновлён Create до 0.5.1, чинит краш на порталах","minRamMb":10240}'

# 2. Залить архив кусками (по 32 МБ), адресуя смещением
curl -X POST "https://millida.net/v2/hosting/packs/arcania/versions/1.5.0/archive?offset=0" \
  -H "X-Pack-Token: $PACK_TOKEN" -H "Content-Type: application/octet-stream" \
  --data-binary @part0.bin

# 3. Сказать, что архив кончился, и опубликовать после разбора
curl -X POST https://millida.net/v2/hosting/packs/arcania/versions/1.5.0/finish \
  -H "X-Pack-Token: $PACK_TOKEN" -H "Content-Type: application/json" \
  -d '{"archiveSha256":"<sha256 архива>","publish":true}'

# 4. Дождаться разбора
curl https://millida.net/v2/hosting/packs/arcania/versions/1.5.0 -H "X-Pack-Token: $PACK_TOKEN"

Версия

ПолеТипЧто делает
labelстрока до 40Номер версии: латиница, цифры, точка, дефис, подчёркивание. Неизменяем: та же метка с другими файлами превращает разбор жалобы в гадание
changelogстрока до 4000Что изменилось — это читает владелец сервера перед обновлением
core, gameVersionстрокиЕсли сборка переехала на другое ядро или версию игры
loaderBuild, javaVersionстрокиПин билда загрузчика и Java, если версии он нужен
minRamMbчислоПланка памяти именно этой версии. Кому её не хватает — увидит причину и не потеряет мир
archiveSha256hex 64Сверяем перед разбором: недоехавший архив лучше отклонить, чем разложить наполовину

Заливка

POST /v2/hosting/packs/{key}/versions/{label}/archive?offset=N, тело — кусок .zip, Content-Type: application/octet-stream. Кусок до 32 МБ, весь архив — до 4 ГБ.

Кусок адресуется смещением, а не «дописать в конец»: оборвавшийся на середине кусок уже частично лёг в файл, и повтор дописал бы те же байты второй раз — архив приехал бы битым молча. Ответ отдаёт uploadedBytes, по нему заливка возобновляется после обрыва.

Разбор

POST .../finish отвечает сразу (status: "processing"), а разбор идёт в фоне: распаковка сборки на гигабайт живёт минутами. Состояние читайте из GET .../versions/{label}: processingready или failed с текстом причины в error.

Что архив обязан выдержать:

  • это серверный пак: после снятия единственной обёртки (Server Files/ и подобных) в корне лежит mods/ или plugins/. Клиентский пак на сервере даёт пустой мир, поэтому мы его отклоняем, а не ставим;
  • никаких .., абсолютных путей и разделителей Windows в именах внутри архива;
  • без пароля, без экзотических методов сжатия (только store и deflate);
  • потолки: 60 000 файлов, 12 ГБ распакованного, коэффициент сжатия до 200×.

Провал не трогает опубликованную версию: у ваших клиентов продолжает стоять прежняя, а вы заливаете заново. Незавершённые черновики: не больше трёх на сборку, брошенные сутки чистятся сами.

Публикация, откат и снятие

ЗапросЧто делает
POST .../versions/{label}/publishСделать версию опубликованной. Ею же делается откат: публикуете прежнюю — новые серверы снова получают её
POST .../versions/{label}/archive-versionСнять версию с выбора. У кого она стоит — у того остаётся
DELETE .../versions/{label}Удалить версию вместе с файлами. Опубликованную и стоящую хоть на одном сервере удалить нельзя
GET .../versionsВерсии, доступные к выбору (публично, без токена)
GET .../versions/allВсё ваше, включая черновики и провалы
GET .../versions/rolloutСколько серверов на какой версии — видно, как расходится обновление

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

Что видит владелец сервера

В панели, в блоке премиум-сборки: какая версия стоит, какая вышла, ваш changelog и список версий с кнопкой «Перейти». Обновление не трогает мир — заменяются только файлы сборки, копию мы снимаем перед заменой. Свои моды, если вы их разрешали, после перехода придётся донести заново: сборка едет одним целым, и половина старой версии в mods/ — это падение на старте.

Версию, которую не тянет тариф владельца, мы показываем с причиной, а не прячем: человек должен видеть, что ему нужно, а не гадать, почему сборка не обновляется.

Коды ответов

КодКогдаЧто делать
403Неверный токен выдачиПроверьте X-Pack-Token. Токен привязан к одной сборке: чужим ключом он не работает
404Сборка выключена, не подключена к выдаче или нет такой версииНапишите нам
400Не разобрана дата expiresAt, плохая метка версии, пустой или слишком большой кусокСмотрите текст ошибки
409Версия уже заведена, уже разобрана, опубликована или стоит на серверахМетки неизменяемы: выпускайте следующую
429Больше 30 запросов в минуту (заливка — 600)Печатайте партией, а куски шлите крупнее

Как проверить всё до продажи

Попросите у нас пару кодов на тест: выпустите код через API, активируйте его на своём сервере на нашем хостинге, посмотрите, что пришло в вебхук и что показывает keys/status. Так вы увидите весь путь покупателя до того, как по нему пойдёт первый оплативший.