API автора сборки: коды активации и обновления
Как автору платной сборки выдавать коды активации и публиковать обновления через API Millida Hosting: версии сборки, заливка архива, публикация, откат, статус кода и вебхук.
Обновлено 7 августа 2026 г.
Эта статья — для авторов платных сборок, которые продают их сами, а установку на сервер отдают нам. Покупателю при этом ничего скачивать не нужно: он вводит код и получает поднятую сборку. Как это выглядит с его стороны — Платная сборка по коду активации.
Что нужно, чтобы подключиться
- Прислать нам серверный архив сборки —
.zipсmods/в корне (без обёртки видаServer Files/) или.mrpack. Архив лежит у нас в приватном хранилище, ссылка наружу не отдаётся никогда. - Сказать ядро, версию игры и минимальную память — по ним мастер отсеет тарифы, на которых сборка не запустится.
- Получить от нас ключ сборки (
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–200 | 1 | Сколько кодов напечатать за вызов |
note | строка до 120 | — | Ваша пометка: номер заказа, ник покупателя |
maxServers | число 1–20 | 1 | На сколько серверов можно активировать один код |
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 | число | Планка памяти именно этой версии. Кому её не хватает — увидит причину и не потеряет мир |
archiveSha256 | hex 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}: processing → ready или 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. Так вы увидите весь путь покупателя до того, как по нему пойдёт первый оплативший.