KUMODeck
EN

リファレンス

Markdownをコピー

REST APIリファレンス

SDKとCLIは、このHTTP APIの薄いクライアントです。JavaScript SDKのないエンジンから、自分のサーバーから、あるいはツールから直接使えます。ベースURLは自分のAPI(https://api.kumodeck.com)です。ボディはすべてJSONです。

認証#

呼び出し元ヘッダー
プレイヤー(アプリやゲームにログインしている利用者)X-Kumo-Key: pk_… + Authorization: Bearer <access token>
公開のアプリのデータX-Kumo-Key: pk_…のみ
サーバー / CLI / CIX-Kumo-Key: sk_…
開発者(ダッシュボード)Authorization: Bearer kds_…

エラーは常に次の形です。

{ "error": { "code": "version_conflict", "message": "…", "details": { "currentVersion": 7 } } }

APIでは、アプリを使う人(利用者)を players(プレイヤー。/v1/players/…、playerId)と呼びます。このページもその名前のまま書きます。

どのオリジンからでも。 SDKは、どこでホストしたアプリやゲーム(KUMODeckのホスティング、自分のサーバー、itch.io、localhost)からでも動きます。CORSは開放されていて、認証はヘッダーで行います。ほかのサイトに自分の公開鍵を使わせないようにするには、kumo.config.json → web.allowedOriginsに自分のオリジンを列挙します(設定を参照)。以後、ほかのオリジンからのブラウザのリクエストは403 origin_not_allowedになります。どのモジュールも単独で動きます。セーブだけ、マルチプレイだけ、ホスティングだけ、といった使い方ができます。

機能はONにするまでOFFです(設定のfeatures)。OFFの機能をアプリや秘密鍵から呼ぶと、何かを読み書きする前に403 feature_disabled(details: { feature, configPath }。例: features.saves)が返ります。ゲストのログイン、トークンの更新、自分のプレイヤー情報、設定の読み取りはいつでも使えます。 今は提供していない機能は403 feature_unavailableを返し、ONにすることもできません。

自分が所有していないリソースは403ではなく404を返すので、存在そのものは明かされません。期限切れのアクセストークンは401 token_expiredを返します。更新してから再試行してください。残高を変えるエンドポイントはIdempotency-Keyヘッダー(A-Z a-z 0-9 _ . : -からなる1〜128文字)を受け付けます。同じキーで再試行すると、二重に適用せず最初の結果を返します。

プレイヤーと認証#

メソッドパスボディ → レスポンス
POST/v1/auth/guest{ displayName? } → セッション
POST/v1/auth/email/signup{ email, password (≥ 8), displayName? } → セッション
POST/v1/auth/email/login{ email, password } → セッション
POST/v1/auth/refresh{ refreshToken } → セッション(回転済み)。401 = 系列が失効、409 refresh_race = 別のタブが直前に回転させた
POST/v1/auth/logout{ refreshToken }
POST/v1/auth/link/email{ email, password } → { player }(ゲストのデータはすべて残る)
GET / PATCH/v1/players/me→ { player } / { displayName }

セッションは{ player: { id, displayName, isGuest, createdAt, identities }, accessToken, expiresIn, refreshToken }です。アクセストークンの有効期間は15分、リフレッシュトークンは90日(回転式)です。

メールの確認、パスワードの再設定、外部サービスでのログイン、プライバシー:

メソッドパスボディ → レスポンス
POST/v1/auth/email/verify{ token } — 確認リンクから取得
POST/v1/auth/email/resend{ redirectUrl? }(プレイヤー)
POST/v1/auth/password/forgot{ email, redirectUrl? } — 常に200
POST/v1/auth/password/reset{ token, password } — そのプレイヤーのリフレッシュトークンをすべて失効させる
POST / GET/v1/auth/oauth/:provider/start:provider = google | discord | apple | x。{ redirectUrl, challenge, mode? } → { url }。プレイヤーのAuthorizationヘッダーを付けると、そのプレイヤーにプロバイダーが連携されます。GET(クエリにkey=pk_…)はリダイレクトするので、普通のリンクに使えます
GET / POST/v1/auth/oauth/:provider/callbackプロバイダーがここに戻り、その後<redirectUrl>#kumo_code=…(または#kumo_error=…)へリダイレクト
POST/v1/auth/oauth/exchange{ code, verifier } → セッション(コードの有効期間は60秒、1回限り)
GET/v1/players/me/identities→ { identities }(ログイン手段。ゲストは含まない)
DELETE/v1/players/me/identities/:provider{ refreshToken }(この端末のもの)→ { player }。この端末以外はすべてログアウト。409 last_login_method = 最後のログイン手段(先に別の手段を追加する)
GET/v1/players/me/exportそのプレイヤーについて保存しているすべて(JSON)
DELETE/v1/players/me{ password }または{ refreshToken } — 取り消し不可

redirectUrlは設定のauth.redirectUrlsで許可されている必要があります(開発中のlocalhostと、KUMODeckでホストしているURLは常に許可されます)。プロバイダーはauth.providersで有効にするまで404 provider_disabledを返し、認証情報が足りない間(Google、Discord、Apple)は409 provider_not_configuredを返します。ログイン・認証を参照してください。

ゲームデータ(プレイヤー)#

メソッドパス補足
GET/v1/gamedata/definitions設定のうち公開してよい部分。pk_のみ
GET/v1/saves{ saves: [{ key, version, size, updatedAt }] }
GET/v1/saves/:key{ key, version, size, updatedAt, data } · 無ければ404
PUT/v1/saves/:key{ data, ifVersion? } · 409 version_conflict、413 save_too_large、409 too_many_saves
DELETE/v1/saves/:key?ifVersion=
GET/v1/stats{ stats: { key: value } }(全期間)
POST/v1/stats{ stats: { key: value } }(64キーまで) → { stats: { key: { period: value } }, rejected, unlocked }

マルチプレイ#

メソッドパス補足
GET (WebSocket)/v1/realtime最初のフレーム{ "t": "auth", "key": "pk_…", "token": "<access token>" }を5秒以内に送る
GET/v1/rooms?mode=参加受付中の公開ルーム{ rooms: [{ id, code, mode, players, maxPlayers, metadata, createdAt }] }

WebSocketのリクエストには任意でridを付けられ、{ t: "reply", rid, ok, data | error }が返ります。

tフィールド
createmode, private?, maxPlayers?, metadata?, code?, hostOnlyState?
joinroomIdまたはcode
quickMatch / cancelMatchmode / —
leave, resume—, roomId
sendtype (≤ 64), data? (≤ 16 KB), to?: playerId[]
setState / setMyStatepatch(nullでキーを削除)
locklocked(ホストのみ)
signalP2Pのルームのみ: to: playerId, kind: offer | answer | candidate | restart, data?(8 KB以下), gen?。その1人へ中継される
iceServersP2Pのルームのみ → { iceServers, iceTransportPolicy: 'relay' | 'all', expiresAt }・turn_unavailable

サーバーからのイベント: welcome、room_joined(スナップショット。常にreplyより先に届く)、player_joined、player_left、player_disconnected、player_reconnected、host_changed、state、player_state、message、locked、signal(P2Pのルーム)、room_closed、warn。切断コード: 4001 未認証、4002 トークン期限切れ(更新して再接続)、4003 BAN / 禁止、4004 新しい接続に置き換えられた、4008 アイドル、4029 レート制限の乱用。

リアルタイムの部屋#

features.realtimeChannelsをONにするまではOFFです(ガイド)。同じ/v1/realtimeのWebSocketを使います(1接続で、マルチプレイのルーム1つと部屋8つまで)。何も保存しません。メッセージは届けたら捨てます。プレイヤーIDの無い接続は{ "t": "auth", "key": "pk_…", "anon": true }を送り、自分のサーバーがopenにした部屋にだけ入れます。

tフィールドエラー
channelJoinchannelchannel_not_found、channel_forbidden、channel_banned、channel_full、player_required、too_many_channels
channelCreatechannel?(@…。省くと自動で付く)、join?、send?、maxMembers?、voice?(trueか{ mode: 'sfu' })channel_exists、player_required、voice_too_large、feature_disabled(features.voice)
channelLeavechannel—
channelSendchannel, type (≤ 64), data?not_in_channel、muted、send_forbidden、payload_too_large、rate_limited
channelModeratechannel, op, playerId, seconds? — op: invite、uninvite、allowSend、disallowSend、mute、unmute、kick、ban、unbanowner_only
voiceJoin / voiceLeavechannel — 音声通話。これと通話のほかのメッセージ(voiceSignal。中継サーバーの通話ではvoicePublish、voiceAnswer、voiceSpeaking)はSDKが送るvoice_disabled、voice_suspended、voice_unavailable、feature_disabled、player_required、not_in_channel、rate_limited

サーバーからのイベント: channel_joined(設定と今いる人。常にreplyより先に届く)、channel_message(from = プレイヤーIDか'server'、at = サーバーの時刻)、channel_player_joined、channel_player_left、channel_self(canSend、mutedUntil)、channel_closed(reason)。音声: voice_state(members: [{ id, canSpeak }])、voice_signal、voice_sfu_offer(中継サーバーの通話)、voice_closed(time_limit、suspended、unavailable)。channel_joinedにvoice: { mode: 'p2p' | 'sfu', relayOnly } | null。

自分のサーバーから(秘密鍵のみ。委任トークンでは使えません):

メソッドパス補足
PUT/v1/realtime/channels/:name@の名前のみ: { join?, send?, open?, maxMembers?, allow?: playerId[], speakers?: playerId[], voice?: true | { mode?: 'p2p' | 'sfu', relayOnly? } } → 設定、名簿、今いる人・409 voice_in_use
GET/v1/realtime/channels/:name同じもの(メッセージの本文は無い)・404 channel_not_found
DELETE/v1/realtime/channels/:name{ deleted: true }(今いる人にはchannel_closed deleted)
POST/v1/realtime/channels/:name/messages{ type, data? } → { delivered }(from: 'server'で届く)・鍵ごとに1分600回
POST/v1/realtime/channels/:name/moderate{ op, playerId, seconds? } → {}・鍵ごとに1分300回(PUT / DELETEと合わせて)

自分のiOS / Androidアプリ(プレイヤー)#

メソッドパス補足
POST/v1/auth/oauth/:provider/nativeapple / google: { idToken, nonce, platform, link?, name? } → セッション + { provider, linked }
POST/v1/players/me/age-signalOSの年齢シグナル({ platform, status, lowerBound?, upperBound?, source?, supervised? })。年齢区分を厳しくする方向にしか変えない

年齢区分(プレイヤー)#

メソッドパス補足
GET/v1/social/profile{ ageBand, declaredAgeBand, capabilities }
PUT/v1/social/age{ band: child | teen | adult }(プレイヤーは厳しくする方向にしか変えられない: 403 age_change_not_allowed)

BANへの異議申し立て(プレイヤー)#

BANしたプレイヤーは、そのBANを確認して1回だけ異議を申し立てられます。申し立ては開発者として読んで回答します(下の表)。受け入れるとBANが解除されます。異議申し立てはBANの一部なので、いつでも使えます。

メソッドパス補足
GET/v1/players/me/sanctionsプレイヤー本人へのBAN(公開メモのみ)
POST/v1/players/me/sanctions/:sanctionId/appeal{ message } → 201 · BAN 1件につき1回
POST/v1/auth/appeal{ refreshToken, sanctionId?, message } — BANされたプレイヤー向け(BANで失効したリフレッシュトークンで本人確認する。sanctionId を省くと、そのトークンを失効させたBANが対象)

POST /v1/statsは、あなたの不正対策ルール(設定のintegrity.stats: 値の範囲、1分あたりの送信回数、任意で自分のサーバーへの署名付きwebhook)も実行します。拒否された値は理由とともにrejectedで返ります。

Xでのシェア(プレイヤー / 公開)#

ここにある機能はどれも、kumo.config.json → shareでONにするまでOFFです(設定とガイドを参照)。OFFの機能は404 share_<tool>_disabledを返し、SDKはこれを「使っていない」として扱います。

メソッドパス認証補足
POST/v1/share/linksプレイヤー{ kind: plain | score | challenge, score?, showName? } → 201 { link, imageUrl, post: { text, hashtags, via } }。
GET/v1/share/links/:shareIdpk_{ link: { id, kind, score, displayName, createdAt } } — 受け取った側で挑戦を復元する
POST/v1/share/visitspk_(サインイン中ならプレイヤーも){ shareId, landed } — プレイヤーごとに1日1回だけ数える(share.tracking)
GET/v1/share/images/:label/card.png · …/:shareId.pngなし1200×600のPNGカード(share.images)。:label = 自分のslug、developmentでは<slug>--dev。キャッシュされる。不明なIDは404
GET/v1/share/tags?ks=pk_またはsk_{ html, tags, image, defaultImage, shareImageTemplate } — ページの<head>に書く<meta>タグ(シェアごとのカードは、リクエストごとに読む)
GET/v1/players/me/x-profile · PUT { visible }プレイヤープレイヤーのXのハンドル・名前・アバターと、表示を許可しているかどうか(既定: 表示しない)
GET/v1/players/x-profiles?ids=a,bpk_{ profiles: { [playerId]: { username, name, avatarUrl } } } — 許可したプレイヤーのみ(IDは最大100個)
POST/v1/auth/transferプレイヤー→ 201 { code, expiresIn: 600 } — 別のブラウザで同じプレイヤーとして続けるための1回限りのコード(share.inAppBrowser)
POST/v1/auth/transfer/redeempk_{ code } → セッション

KUMODeckでホストしているアプリは、同じカード画像をアプリ自身のドメインでも配信します: /.card.pngと/.card/<shareId>.png。Xでのログインは、:provider = xで通常のOAuthのルートを使います(ログイン・認証を参照)。ダッシュボードに自分のXアプリの資格情報が必要で、ない場合はPOST /v1/auth/oauth/x/startが409 provider_not_configuredを返します。ログインは無料(Xが料金を請求しない)なので、いまは支払いを理由に断られることはありません。将来Xが料金を取るようになった場合に限り、KUMODeckの共用Xアプリを使うアプリは残高が支払い期限を過ぎている間402 x_signin_unavailable(details.continueAsGuest: true)を返します。そのときはプレイヤーをゲストアカウントのまま続けさせてください。

サーバー(秘密鍵)#

メソッドパス補足
GET / PUT/v1/config鍵の環境のマスターデータを読む / pushする
POST/v1/deployments{ files: [{ path, sha256, size }], message? } → { deploymentId, version, missing, missingBytes }
PUT/v1/blobs/:sha256足りないファイル1つの生のバイト列(50MBまで)
POST/v1/deployments/:ref/finalize{ activate?: true } · 409 blobs_missing
POST/v1/deployments/:ref/activate公開中のバージョンを切り替える(ロールバック / 昇格)
GET/v1/deployments?limit= · /v1/deployments/:ref · /v1/hosting履歴、1つのバージョン(マニフェスト付き)、公開中のURL

:refはデプロイのIDまたはバージョン番号です。

Functions(秘密鍵またはダッシュボード)#

自分のサーバーのプログラムとデータベースです(ガイド)。既定はOFFです。各パスは、X-Kumo-Key: sk_…なら/v1/admin/<path>で、開発者セッションなら/v1/projects/:projectId/environments/:env/<path>で使えます。

メソッド<path>補足
GETfunctions{ enabled, suspended, limits, deployed, version, url, crons, durableObjects, resources, secrets }(シークレットは名前のみ)
POSTfunctions/enable · functions/disableenable: { cpuMs?, subRequests? } · 前払いのクレジットが無いと402 prepaid_required · disableしてもコードとデータは残る
PUTfunctions/limits{ cpuMs? (1–30000), subRequests? (0–1000) }
POSTfunctions/deployments{ mainModule, modules: [{ name, type, content (base64) }], bindings, vars, crons, compatibilityDate?, message? } → 201 { version, … }。通常はkumodeck functions deployが送る
GETfunctions/deployments?limit=履歴(新しい順)
DELETEfunctions?purge=trueコードを削除する。purgeを付けるとデータベース、KV、ファイル、キューも削除する
GET / PUT / DELETEfunctions/secrets · functions/secrets/:name値はそのままランタイムに渡され、保存も返却もされない
POSTfunctions/db/:binding/query · functions/db/:binding/migrate{ sql, params? } · { migrations: [{ name, sql }] } → { applied, failed, skipped }

Functionsのコードから(秘密鍵のみ): POST /v1/admin/players/verify-token { token } → { player: { id, displayName, banned } }(別の環境のトークンなら401)。コードからBANするときはPOST /v1/admin/players/:playerId/ban · /unban(下の運営の表)。

開発者(ダッシュボードのセッション)#

メソッドパス
POST/v1/developers/signup · /login · /logout · GET /v1/developers/meアカウント(meにhasPassword)。signupは任意のinviteCodeを受ける(無効なコードならアカウントを作らない: 400 invalid_invite_code / 409 invite_code_used / invite_limit_reached)
POST/v1/developers/me/invite-code{ code } → { credited: 500, currency: "usd", pending } — 招待クレジット(利用料だけに使えます・返金や出金はできません)。メールの確認が済むと入る(それまではpending: true)。開発者セッションのみ(MCPからは不可)。409 already_redeemed(1アカウントに1回)
POST/v1/developers/oauth/:provider/start · /v1/developers/oauth/exchangeexchangeは新しいアカウントのときだけ任意のinviteCodeを受ける(既存のアカウントならinvite: { ignored: true })。Google・GitHubのログイン、ログイン方法の追加(intent: "link")、本人の確認のやり直し(intent: "reauth")。PKCE。使えるプロバイダはGET /v1/platform/infoのoauthProviders
GET / DELETE / POST/v1/developers/me/identities · /me/identities/:provider · /me/passwordログイン方法: 一覧・解除(passwordかreauthTokenが必要。最後の1つは外せない)・パスワードの設定 / 変更
GET / POST/v1/projects一覧 / 作成(すべての鍵を平文で一度だけ返す)
GET / DELETE/v1/projects/:projectId
PATCH/v1/projects/:projectId{ name }(1〜80文字)→ { project, previousName, changed }。プロジェクトの名前を変える(名前は利用者に届くメールの件名と差出人に出る)。スラッグは変わらない。KUMODeckや運営を思わせる名前は400 name_reserved(作成でも同じ)。1時間に20回を超えると429
POST/v1/projects/:projectId/environments/:env/keys新しい鍵 · DELETE /v1/projects/:projectId/keys/:keyIdで失効
GET / PUT/v1/projects/:projectId/environments/:env/configマスターデータ
GET…/environments/:env/overviewプレイヤー、日ごとのアクティブ数(14日分)、設定のバージョン、鍵
GET…/environments/:env/players?q=&cursor=&limit= · …/players/:playerId検索 / 詳細
POST…/environments/:env/players/:playerId/ban · /unbanBANすると接続中の通信をすぐに切断
GET…/environments/:env/realtime動いているルームの読み取り専用の表示
GET/v1/projects/:projectId/audit?limit=&before=&env=監査ログ

ホスティングのエンドポイントも、開発者は/v1/projects/:projectId/environments/:env/…で使えます。

お金(開発者セッション)#

前払い残高と利用料です。開発者セッション(Authorization: Bearer kds_…)のみで、秘密鍵ではお金を読むことも動かすこともできません。金額は最小単位(セント)の整数です。

メソッドパス補足
GET/v1/money/prepaid · /v1/money/prepaid/ledger{ balance, owed, invite } · 明細。inviteは{ granted, remaining, pending }かnull(remainingはbalanceの内数)
POST/v1/money/prepaid/checkout{ amount ($5–$10,000), successUrl, cancelUrl } + Idempotency-Key → Stripe Checkout(3Dセキュア)。状況はGET /v1/money/prepaid/checkouts/:idでポーリング
GET/v1/money/usage?period=YYYY-MM&refresh=要素ごとの利用料(マイクロUSD)と、実際に請求した額(セント)

ゲームの運営(秘密鍵またはダッシュボード)#

どれも、X-Kumo-Key: sk_…(自分のサーバー、CLI、MCP)なら/v1/admin/<path>で、開発者セッションなら/v1/projects/:projectId/environments/:env/<path>で使えます。変更は監査ログに記録されます。

メソッド<path>補足
PUTplayers/:playerId/age{ band } — プレイヤーの年齢区分を訂正する(保護者の確認の後など)
POSTplayers/:playerId/ban · players/:playerId/unban{ reason?(500文字まで), durationHours?(0より大きく8784まで。秘密鍵のみ。省くと解除するまで)} → { player: { id, banned, bannedAt, banReason, revokedSessions, banExpiresAt } }。接続中の通信をすぐに切断。404 player_not_found。機能のスイッチはなく常に使える。どこで掛けたBANもどこからでも解除できる
GETappeals?status= · POST appeals/:appealId/resolveプレイヤーからのBANへの異議申し立て · { accept, response? } — 受け入れるとBANが解除される。いつでも使える
GETintegrity/webhook-secretstatsのwebhookが検証に使う鍵
GETshare/stats?from=&to=&shareId=&limit=共有リンクごとの訪問、新規プレイヤー、プレイ数(UTCの日単位。既定は直近30日、最大366日)
POSTshare/links{ label } → 201 { link, url, query } — 自分の投稿用の計測付きリンク
GETshare/tags?ks=/v1/share/tagsと同じ(kumodeck share tagsが使う)