COMMON MAILBOX / API V1

보상은 한 우편함에서, 지급은 각 게임 서버에서.

KOISCORE 젬과 게임 전용 재화의 원장을 섞지 않으면서 포털에서 모든 보상 우편을 발견하고 안전하게 수령합니다.

OWNERSHIP

공통 상태, 분리된 재화 원장

보상사용자 경험지급 권한
platform / koi_gem포털 우편함에서 즉시 받기KOISCORE Core가 같은 DB transaction에서 지급
game / billiards_coin포털에서 게임 열기 또는 받기 → 국제당구로 이동국제당구 서버가 자기 지갑 transaction에서 지급
게임 클라이언트가 보낸 player ID, 보상 수량, 재화 키를 신뢰하지 마세요. 발송 내용은 KOISCORE에 저장된 우편을 사용하고, 수령자는 게임 서버가 검증한 KOISCORE identity에서 가져와야 합니다.

SERVER KEY

키 발급과 복사

  1. Google 로그인 후 개발자 콘솔에서 게임 초안을 등록합니다.
  2. 공통 우편함 API → 새 키 자동 발급에서 게임과 만료일을 선택합니다.
  3. 발급 직후 표시되는 키 복사 버튼을 누릅니다.
  4. 게임 서버의 환경변수 또는 secret manager에 저장합니다.
  5. 분실하면 기존 키를 폐기하고 새 키를 발급합니다.
KOISCORE_MAILBOX_API_KEY=koi_mail_...
KOISCORE_GAME_ID=billiards
키 원문은 발급 응답에서 한 번만 표시됩니다. KOISCORE DB에는 SHA-256 해시와 접두사만 저장하므로 이후 원문을 다시 표시할 수 없습니다.

AUTHENTICATION

서버에서만 Bearer 키 사용

Authorization: Bearer koi_mail_...
X-KOISCORE-Game-Id: billiards
Content-Type: application/json
  • 모든 호출은 HTTPS 게임 서버에서 수행합니다.
  • 키를 JavaScript 번들, URL, 앱 저장소, 로그, Git에 넣지 않습니다.
  • 키는 발급 대상 game ID에만 유효합니다.
  • 폐기·만료된 키와 다른 게임의 키는 즉시 401로 거부됩니다.

DELIVERY

게임 전용 보상 우편 발송

POST
/api/platform/v1/mailbox/deliveries

현재 게임의 전용 재화 보상 우편을 한 사용자에게 발송합니다.

{
  "sourceEventId": "season:2026-08:reward:match-1042",
  "recipientPlayerId": "ply_...",
  "title": {
    "ko": "국제당구 1,000코인",
    "en": "1,000 Billiards Coins",
    "ja": "国際ビリヤードコイン1,000枚"
  },
  "body": {
    "ko": "국제당구에 들어가서 받아 주세요.",
    "en": "Open Billiards to receive it.",
    "ja": "国際ビリヤードを開いて受け取ってください。"
  },
  "reward": { "key": "billiards_coin", "amount": 1000 }
}

sourceEventId는 경기·이벤트마다 고유해야 합니다. 같은 ID를 재전송하면 새 우편을 만들지 않고 기존 mailIdduplicate: true를 반환합니다.

PORTAL UX

게임별 우편은 포털에서 바로 열기

우편에 sourceGameId 또는 게임 보상 reward.gameId가 있으면 포털 우편함(/mailbox/{locale})에 게임 열기가 표시됩니다. 사용자는 보상 수령 전에 해당 게임을 바로 실행할 수 있습니다.

/portal/{locale}?game={sourceGameId}
  • 게임 열기는 포털 플레이어로 이동합니다. 게임 보상 claim이 아닙니다.
  • 받기(게임 보상)는 등록된 runtime_url로 이동하며 fragment에 koiscoreMailbox만 붙습니다.
  • 구독 청구 등 category: notice 우편은 결제하기(/subscribe/{gameId})와 게임 열기를 함께 보여줄 수 있습니다.
  • 만료된 우편에는 게임 열기·결제 버튼을 노출하지 않습니다.

FULFILLMENT

게임 진입 후 수령 확정

  1. 사용자가 포털 우편함에서 게임 열기로 포털 플레이를 열거나, 받기로 등록된 게임 runtime으로 이동합니다.
  2. 받기 경로에서는 fragment의 koiscoreMailbox에 권한 없는 우편 UUID만 들어갑니다.
  3. 게임 서버는 KOISCORE identity assertion을 검증해 player ID를 결정합니다.
  4. 게임 서버가 아래 API를 호출하고 반환된 grant를 자기 DB에서 지급합니다.
POST
/api/platform/v1/mailbox/redemptions/consume

우편 소유자와 게임을 확인하고 멱등 fulfillment grant를 반환합니다.

{
  "gameId": "billiards",
  "playerId": "<server-verified game-scoped ply_... ID>",
  "mailId": "<koiscoreMailbox UUID>"
}
{
  "ok": true,
  "duplicate": false,
  "grant": {
    "mailId": "...",
    "fulfillmentKey": "mail:...",
    "gameId": "billiards",
    "rewardKey": "billiards_coin",
    "rewardAmount": 1000
  }
}
fulfillmentKey를 게임 DB의 UNIQUE 컬럼으로 저장하고 코인 적립과 같은 transaction에서 기록하세요. 응답 유실 후 재시도하면 같은 grant가 duplicate: true로 반환됩니다.

OPERATIONS

키 교체와 장애 처리

  1. 새 키를 발급하고 게임 서버 secret을 새 키로 교체합니다.
  2. 새 키 호출 성공과 최근 사용 시각을 개발자센터에서 확인합니다.
  3. 기존 키를 폐기합니다.
  4. 키 노출이 의심되면 순서를 기다리지 말고 즉시 폐기합니다.