Skip to content
호스팅 · 모드와 모드팩

모드팩 제작자 API: 활성화 코드와 업데이트

유료 모드팩 제작자가 Millida Hosting API를 통해 활성화 코드를 발급하고 업데이트를 게시하는 방법을 알아봐요. 모드팩 버전, 아카이브 업로드, 게시, 롤백, 코드 상태, 웹훅을 다뤄요.

업데이트 2026년 9월 6일

코드를 작성하지 않아도 돼요. 아래 설명한 모든 기능은 이제 버튼으로도 사용할 수 있어요. 모드팩이 Millida 계정에 연결되어 있다면 프로필에 “내 모드팩” 탭이 나타나요. 거기서 버전을 업로드하고, 카드를 수정하고, 랜딩 페이지를 만들 수 있어요. 연결되어 있지 않다면 저희에게 문의해 주세요. 연결해 드릴게요. API는 자체 CI에서 배포하는 분들을 위한 거예요.

이 글은 유료 모드팩을 직접 판매하고 서버 설치를 저희에게 맡기는 제작자를 위한 글이에요. 구매자는 아무것도 다운로드할 필요가 없어요. 코드를 입력하면 배포된 모드팩을 받아요. 구매자 입장에서 어떻게 보이는지 알고 싶다면 활성화 코드로 유료 모드팩 받기를 읽어 보세요.

시작하기 위해 필요한 것

  1. 모드팩의 서버 아카이브를 보내 주세요. 루트에 mods/가 있는 .zip(Server Files/ 같은 상위 폴더 없이) 또는 .mrpack이면 돼요. 아카이브는 저희 비공개 스토리지에 보관되며, 링크는 외부에 절대 공유되지 않아요.
  2. 코어, 게임 버전, 최소 메모리를 알려 주세요. 마법사가 이 정보로 모드팩이 실행되지 않을 플랜을 걸러내요.
  3. 저희에게서 모드팩 키(key, 예: arcania)와 발급 토큰을 받으세요. 회원님의 사이트에서 이 토큰으로 코드를 생성해요.

토큰은 한 번만 표시돼요. 저희는 지문만 저장해요. 분실했다면 재발급을 요청해 주세요. 기존 토큰은 작동을 멈춰요.

어떻게 작동하는지

  • 결제는 회원님 쪽에서 직접 받아요.
  • 결제 후 회원님의 사이트가 저희 API를 호출해 활성화 코드를 받아요.
  • 구매자에게 코드를 전달해요. 이메일, 봇, 또는 “감사합니다” 페이지에서요.
  • 구매자가 저희 쪽에서 코드를 입력하면 유료 플랜의 모드팩이 설치된 서버를 받아요.
  • 서버의 모드팩 파일은 잠겨 있어요. 제어판이나 SFTP로 mods를 다운로드할 수 없어요.

실제로 구매자는 서버 모드팩을 손에 넣지 못하고, 작동하는 서버만 받아요.

엔드포인트와 인증

기본 URL은 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코드 하나로 활성화할 수 있는 서버 수
expiresAtISO 날짜—코드 만료일
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": "order 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": "order 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"}.

응답은 목록과 같은 행이에요. 코드는 URL이 아니라 본문에 넣어요. URL은 프록시 로그와 브라우저 기록에 남고, 활성화 전의 코드는 유효한 키이기 때문이에요.

하이픈과 대소문자는 상관없어요. a7k29mhd4rtpqw38도 A7K2-9MHD-4RTP-QW38과 똑같이 찾아져요.

코드 폐기

POST /v2/hosting/packs/{key}/keys/revoke, 본문 {"code": "..."}.

환불, 발급 실수, 분쟁에 사용하세요. 폐기는 향후 활성화를 차단하지만 이미 배포된 모드팩을 제거하지는 않아요. 활성화한 구매자는 작동하는 서버를 계속 유지해요.

활성화 웹훅

웹훅 URL을 알려 주시면 코드가 사용되는 순간 저희가 호출해요.

POST <your-address>
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"를 확인하세요. 이렇게 하면 두 번째 시크릿을 저장할 필요가 없어요.

웹훅은 응답을 기다리지 않고 전송되며 재시도되지 않아요. 회원님의 서버가 다운됐더라도 활성화는 그대로 진행되고, 코드 목록에서 확인할 수 있어요. URL은 공개되어야 해요. 내부나 로컬 주소는 호출하지 않아요. 리다이렉트는 따라가지 않아요.

모드팩 카드

GET /v2/hosting/packs/{key}는 공개이며 토큰이 필요 없어요. 구매자가 보는 것을 반환해요. 이름, 코어, 버전, 최소 메모리, 플랜 목록, 보호 플래그예요. 응답에 아카이브 링크는 없어요.

회원님 사이트의 “구매” 페이지에 편리해요. 플랜 요구 사항이 단일 출처에서 나오므로 저희 마법사가 말하는 것과 어긋나지 않아요.

카드의 상점 필드는 직접 수정해요. 토큰과 함께 PATCH /v2/hosting/packs/{key}로 name, authorName, authorUrl, iconUrl, webhookUrl을 받아요. 판매 조건(paidOnly, requireKey, lockFiles, planCodes), 상점에서 모드팩 활성화, JVM 실행 플래그는 토큰으로 변경할 수 없어요. 이는 회원님과의 합의 및 저희 노드에 관한 것이니 저희에게 문의해 주세요.

모드팩 업데이트

예전에는 업데이트하려면 저희에게 이메일을 보내고 기다려야 했어요. 이제 회원님이 직접 버전을 게시하고, 서버 소유자가 제어판에서 선택해요.

핵심은 저희가 누구에게도 조용히 업데이트하지 않는다는 거예요. 모드팩 버전 간 이동은 월드와 호환되지 않을 수 있고, 서버 소유자가 결정해요. 게시된 버전은 새 서버가 받는 것이고 이미 배포된 서버에 제안하는 것이에요. 이전 버전은 목록에 남아 있고, 그대로 유지하거나 롤백할 수 있어요.

주기가 어떻게 보이는지

# 1. Create a version
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":"Updated Create to 0.5.1, fixes crash on portals","minRamMb":10240}'

# 2. Upload the archive in chunks (32 MB each), addressing by offset
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. Say the archive is finished, and publish after parsing
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 of archive>","publish":true}'

# 4. Wait for parsing
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숫자이 버전에 필요한 최소 메모리. 메모리가 부족한 사람은 이유를 보게 되고 월드를 잃지 않아요
archiveSha25664자리 16진수파싱 전에 검증해요: 절반만 풀어놓느니 다 도착하지 않은 아카이브를 거부하는 편이 나아요

업로드

POST /v2/hosting/packs/{key}/versions/{label}/archive?offset=N, 본문 — .zip의 청크, Content-Type: application/octet-stream. 청크는 최대 32 MB, 전체 아카이브는 최대 4 GB예요.

청크는 "끝에 덧붙이기"가 아니라 오프셋으로 지정해요: 중간에 끊긴 청크는 이미 파일에 일부 들어가 있고, 재시도하면 같은 바이트가 두 번 덧붙어서 아카이브가 조용히 손상돼요. 응답은 uploadedBytes를 반환하고, 이걸로 중단 후 업로드를 이어서 할 수 있어요.

파싱

POST .../finish는 즉시 응답하고(status: "processing"), 파싱은 백그라운드에서 실행돼요: 기가바이트 크기의 서버 구성을 푸는 데는 몇 분이 걸려요. 상태는 GET .../versions/{label}에서 읽어요: processing → ready 또는 error에 이유 텍스트가 담긴 failed.

아카이브가 통과해야 하는 조건:

  • 서버 팩이어야 해요: 단일 래퍼(Server Files/ 등)를 제거한 뒤 mods/ 또는 plugins/가 루트에 있어야 해요. 서버에 클라이언트 팩을 올리면 빈 월드가 나오므로, 설치하지 않고 거부해요;
  • 아카이브 내 이름에 .., 절대 경로, Windows 구분자가 없어야 해요;
  • 비밀번호가 없어야 하고, 특이한 압축 방식(store와 deflate만)을 쓰면 안 돼요;
  • 제한: 파일 60,000개, 압축 해제 시 12 GB, 압축률 최대 200배.

실패해도 게시된 버전에는 영향이 없어요: 클라이언트는 이전 버전을 계속 실행하고, 다시 업로드하면 돼요. 미완성 초안: 서버 구성당 최대 세 개까지이며, 버려진 초안은 하루 뒤 자동으로 정리돼요.

게시, 롤백, 삭제

요청하는 일
POST .../versions/{label}/publish버전을 게시해요. 롤백도 이렇게 해요: 이전 버전을 게시하면 새 서버가 다시 그 버전을 받아요
POST .../versions/{label}/archive-version선택 목록에서 버전을 제거해요. 이미 받은 사람은 계속 유지해요
PATCH .../versions/{label}이미 만든 버전의 설명을 수정해요: changelog와 minRamMb. 버전 파일은 변경 불가라서 코어, 로더, Java는 바뀌지 않아요
DELETE .../versions/{label}버전을 파일과 함께 삭제해요. 게시된 버전이나 서버 하나라도 사용 중인 버전은 삭제할 수 없어요
GET .../versions선택 가능한 버전(공개, 토큰 불필요)
GET .../versions/all초안과 실패를 포함한 내 모든 버전
GET .../versions/rollout어떤 버전에 서버가 몇 개 있는지 — 업데이트가 어떻게 퍼지는지 볼 수 있어요

게시하면 코어, 게임 버전, 로더 고정, Java, 버전의 메모리 하한이 서버 구성 카드로 넘어가요: 새 서버는 별도 작업 없이 이걸 받아요.

서버 소유자가 보는 것

제어판의 프리미엄 서버 구성 블록에서: 어떤 버전이 설치됐는지, 어떤 버전이 출시됐는지, 내 changelog, 그리고 "전환" 버튼이 있는 버전 목록을 봐요. 업데이트는 월드에 영향을 주지 않아요 — 서버 구성 파일만 교체되고, 교체 전에 복사본을 만들어요. 허용한 경우 커스텀 모드는 전환 후 다시 추가해야 해요: 서버 구성은 하나의 덩어리로 옮겨지고, mods/에 이전 버전의 일부가 남으면 시작 시 크래시가 나요.

소유자의 요금제가 버전을 감당할 수 없으면 숨기지 않고 이유와 함께 보여줘요: 서버 구성이 왜 업데이트되지 않는지 추측하게 하지 않고, 필요한 걸 볼 수 있어야 하니까요.

내 서버 구성 페이지

서버 구성의 랜딩 페이지는 계정에서 직접 만들어요(프로필 → "내 서버 구성" → "서버 구성 페이지"): 첫 화면, 기능, 스크린샷, Q&A, 내 색상. 요금제와 버전 목록은 우리 데이터로 채워져서 오래된 정보가 되지 않아요.

완성된 페이지는 millida.net/sborka/<your-address>에 있어요 — 검색 엔진에 색인되고 우리 사이트맵에 포함되는 일반 웹사이트 페이지예요. 초안은 나만 볼 수 있어요.

이미지도 같은 곳, 계정에서 업로드해요: 페이지는 우리 도메인에서 제공되고 파일은 우리 쪽에 저장돼요 — 내 호스팅이 죽어도 페이지는 그대로예요.

페이지는 API로 편집할 수 없어요: 이건 화면이지 롤아웃이 아니에요.

응답 코드

코드언제무엇을 할지
403발급 토큰이 유효하지 않음X-Pack-Token을 확인하세요. 토큰은 하나의 서버 구성에 묶여 있어요: 다른 키로는 작동하지 않아요
404서버 구성이 비활성화됐거나, 발급에 연결되지 않았거나, 해당 버전이 없음저희에게 문의하세요
400expiresAt 날짜를 파싱할 수 없거나, 버전 라벨이 잘못됐거나, 청크가 비었거나 너무 큼오류 텍스트를 확인하세요
409버전이 이미 생성됐거나, 이미 파싱됐거나, 게시됐거나, 서버에 설치됨라벨은 변경 불가예요: 다음 버전을 출시하세요
429분당 30회 초과 요청(업로드는 600회)묶음으로 보내고, 청크를 더 크게 보내세요

판매 전에 모든 걸 테스트하는 방법

저희에게 테스트 코드 몇 개를 요청하세요: API로 코드를 발급하고, 우리 호스팅의 내 서버에서 활성화하고, 웹훅에 무엇이 도착했는지와 keys/status가 무엇을 보여주는지 확인하세요. 그러면 첫 유료 고객이 거치는 전체 경로를 미리 볼 수 있어요.

Minecraft 호스팅오프라인일 때도 서버가 실행돼요서버 만들기