接続先を入力
iPhoneのログイン画面で、対応サーバーのHTTPS URLを入力します。
iPhoneアプリの「接続先URL」に指定できるサーバーを作るための、公開APIガイドです。認証からゲームデータまで、アプリが期待する通信仕様をまとめました。
iPhoneのログイン画面で、対応サーバーのHTTPS URLを入力します。
サーバーが本人確認し、iPhoneへ一回限りのコードを返します。
同じセッションでツム・設定を取得し、スコアや所持データをやり取りします。
初期接続先は https://tsumu.tarohida.jp。別サーバーを使う場合は、以下のAPIとDiscord OAuthを実装してください。単にDiscord対応のサイトを入力しても接続できません。
https://games.example.com
https://games.example.com:8443/ は除去、スキーム省略時はHTTPSを補完、443番ポートは省略形に正規化します。| 区分 | メソッド / パス | 役割 |
|---|---|---|
| 認証 | GET /auth/loginGET /auth/callback | ブラウザでDiscord認証 |
| 認証 | POST /auth/tokenPOST /auth/logout | コード交換・セッション失効 |
| 必須 | GET /api/game-data | iPhoneの初期データ一括取得 |
| 共通機能 | POST /api/rankingsPOST /api/gacha/pull | スコア保存・ガチャ |
| 条件付き | POST /api/skills/resolve | カスタムスキルを割り当てる場合 |
| Web・個別取得 | GET /api/meGET /api/rankingsGET /api/user-tsums | ユーザー・ランキング・所持数 |
| Web互換 | GET /api/tsumsGET /api/settingsGET /api/stages/activeGET /api/fan-btn | 設定等の個別取得 |
iPhone 2.2は一覧・残高・設定を /api/game-data から取得します。/api/settings を除くゲームAPIは認証必須。管理API、スキル作成UI、旧Android専用認証はこの接続仕様の対象外です。
DiscordのアクセストークンをiPhoneへ返すのではありません。本人確認はサーバーが行い、そのサーバー専用のTSUMUセッションを発行します。Discordのclient secretはサーバー内だけに置きます。
システム認証ブラウザで /auth/login?client=ios&code_challenge=…&client_state=… を開きます。
独立したランダムstateを保存し、oauth_state Cookieにも設定。Discordへリダイレクトし、/auth/callback で両方のstateを検証します。
成功時はHTTP 302で tsumu://auth?code=ONE_TIME_CODE&state=CLIENT_STATE へ。URLにセッショントークンを含めません。
POST /auth/token にコードとverifierを送信。交換したセッションをKeychainへ保存し、その後のAPIにBearerとして付けます。
| パラメーター | iOSでの条件 |
|---|---|
client | ios を指定。省略時はWeb認証。 |
code_challenge | 43文字のBase64URL(A–Z / a–z / 0–9 / _ / -)。BASE64URL(SHA256(code_verifier))、パディングなし。 |
client_state | 32〜128文字のBase64URL文字集合。アプリが発行し、アプリへのコールバックで同じ値を返します。 |
S256固定です。code_challenge_method は送信しません。サーバー側stateは別に生成し、Cookieと紐づけて有効期間300秒・一回限りとします。Cookieは HttpOnly; Secure; SameSite=Lax。通常の成功応答はDiscordへのHTTP 307です。
https://あなたのホスト/auth/callback に一致させます。現行バックエンドでは DISCORD_CLIENT_ID、DISCORD_CLIENT_SECRET、DISCORD_REDIRECT_URI を設定し、identify スコープで本人確認します。ALLOWED_USERNAMES がある場合はそのアクセス制限も適用されます。リバースプロキシ配下でも外向きHTTPSを正しく認識させてください。Discordからの code と state を受け、Cookieのstate・サーバー保存のstateを照合して消費します。Discordユーザーを許可できたらTSUMUセッションと一回限りコードを発行します。
HTTP/1.1 302 Found
Location: tsumu://auth?code=ONE_TIME_CODE&state=ORIGINAL_CLIENT_STATE
Cache-Control: no-store
Referrer-Policy: no-referrer認証拒否は tsumu://auth?error=access_denied&state=…、Discord通信エラーは error=discord_error を返します。state自体が不正な場合はアプリへ戻さず、/login.html?error=invalid_state へリダイレクトします。Web認証は session Cookieを発行して / へ戻します。
{
"code": "SERVER_ISSUED_ONE_TIME_CODE",
"code_verifier": "APP_GENERATED_VERIFIER_AT_LEAST_43_CHARACTERS_LONG"
}{
"access_token": "TSUMU_SESSION_TOKEN",
"token_type": "Bearer",
"expires_in": 604800
}code は20〜128文字、code_verifier は43〜128文字で A–Z a–z 0–9 . _ ~ - のみ。一回限りコードは60秒で失効し、正しいverifierと交換できた時だけ消費します。期限切れ・不一致・再使用はHTTP 400。セッションは作成から7日で失効し、refresh tokenはありません。
GET /api/game-data HTTP/1.1
Authorization: Bearer TSUMU_SESSION_TOKEN
Accept: application/jsonWebは同じセッションをHttpOnly Cookieで送ります。BearerとCookieを同じユーザー検証に接続し、Bearerが不正なときにCookieへフォールバックしないでください。個人データと認証応答には Cache-Control: no-store を付けます。
POST /auth/logout は現在のセッションを失効して {"status":"ok"} を返します。未認証でも同じ応答です。HTTP 401を受けたiPhoneは認証情報を破棄してログイン画面へ戻ります。保存するトークンは接続先ごとに分離されます。
認証後に最初に読むスナップショットです。以下は架空の値による例です。/uploads/sample.png は例示URLで、ファイルを提供しているわけではありません。最小構成はデフォルトプリセットのJSONを参照してください。
{
"version": 1,
"user": {
"discord_id": "demo-user",
"username": "サンプル",
"jewels": 100,
"bestScore": 1200,
"gamesPlayed": 3
},
"tsums": {
"overrides": {
"mickey": {
"name": "サンプルツム",
"imageUrl": "/uploads/sample.png",
"skillId": "skill_example",
"skillName": "タイムプラス"
}
}
},
"settings": {
"combo_timeout": 3000,
"game_duration": 60,
"fever_duration": 8000,
"fever_multiplier": 3,
"min_chain": 3,
"bomb_chain_threshold": 7,
"connect_gap_tolerance": 26
},
"stage": null,
"fan": {
"url": null,
"color": "#4fc3f7"
},
"collection": {
"mickey": 2
},
"rankings": [
{
"name": "サンプル",
"score": 1200,
"tsumUsed": "mickey",
"createdAt": 1790000000
}
]
}| キー | 型 / 意味 |
|---|---|
version | 整数。現行レスポンスは 1。iPhone 2.2はバージョン交渉を行いません。 |
user | discord_id・username は文字列、jewels・bestScore・gamesPlayed は整数。5項目必須。プレイ数は保存済みランキングの件数です。 |
tsums | overrides オブジェクト必須。未設定なら {}。ツムIDごとに name / imageUrl / skillId / skillName を文字列で任意指定。未設定は省略またはnull。 |
settings | 数値の辞書。欠けた設定はiPhoneの標準値を使用。文字列の数値は不可。 |
stage | 未設定は null。設定時は文字列またはnullの値からなるオブジェクト。詳細は素材の節。 |
fan | color 文字列必須、url は画像URLまたはnull。iPhone 2.2は画像を使用し、色の指定はWeb向けです。 |
collection | ツムID → 所持数(整数)の辞書。未所持は省略可。所持数によるプレイ制限は現在ありません。 |
rankings | 配列。各要素の name は文字列、score は整数、createdAt はUTC Unix秒(数値)。tsumUsed はツムIDまたはnull。スコア降順。 |
トップレベルの8キーは常に返してください。追加の未知フィールドはiPhoneで無視されます。skillCode / skillType が含まれていても、iPhoneはコードを実行せず skillId の有無でカスタムスキルを判定します。
| typeIndex | ツムID | 標準名 |
|---|---|---|
| 0 | mickey | ミッキー |
| 1 | donald | ドナルド |
| 2 | goofy | グーフィー |
| 3 | pluto | プルート |
| 4 | daisy | デイジー |
| 5 | minnie | ミニー |
名前・画像は変更できますが、IDとインデックスの順序は固定です。ツムの追加種類や基本スコアの変更をこのAPIだけで行うことはできません。
| キー | 標準値 | 単位 / 役割 |
|---|---|---|
game_duration | 60 | 秒 / プレイ時間 |
combo_timeout | 3000 | ミリ秒 / コンボ期限 |
fever_duration | 8000 | ミリ秒 / フィーバー時間 |
fever_multiplier | 3 | 倍率 |
min_chain | 3 | 個 / 消去に必要なチェーン長 |
bomb_chain_threshold | 7 | 個 / ボム生成チェーン長 |
connect_gap_tolerance | 26 | Web論理座標の距離 / 接続許容間隔 |
iPhoneでは安全のため、プレイ時間1〜86400秒、倍率1〜100、チェーン条件2〜50、接続許容間隔0〜300に丸めます。コンボ・フィーバー時間の下限は100msです。互換性を保つには標準値から始めてください。
{
"name": "サンプル",
"score": 1200,
"tsum_used": "mickey",
"request_id": "11111111-1111-4111-8111-111111111111"
}name は1〜20文字、score は0〜2,147,483,647の整数。tsum_used は標準ツムIDまたはnullです。成功時は {"status":"ok"} をHTTP 200で返します。現行実装はクライアント申告のスコアを保存し、サーバーによるプレイ内容の再検証はしません。
request_id はUUID。同じユーザーとIDの組み合わせでは最初の記録だけを保存します。同じIDで名前やスコアを変更しても更新されません。サーバーでは省略可能ですが、互換クライアントは必ず付けて再送時に同じ値を使ってください。{
"request_id": "22222222-2222-4222-8222-222222222222"
}{
"tsumId": "donald",
"jewelsRemaining": 0
}1回100ジュエル、標準6種類から均等に選択、重複あり。残高減算・所持追加・処理済みIDの保存は1トランザクションで行います。残高不足はHTTP 400です。
同じユーザーと request_id の再送では二重消費せず、同じ tsumId を返します。jewelsRemaining は再送した時点の現在残高です。未確定IDは結果が判明するまで保存し、新しいガチャ操作にだけ新しいIDを発行してください。
スコア保存だけでジュエルは増えません。ゲストや旧オフライン版の残高・スコアはサーバーへ移行・合算しません。GET /api/user-tsums は {"mickey":2,"donald":1} のような辞書を返します。
GET /api/me はスナップショットの user と同じ形式。GET /api/rankings は rankings と同じ配列で、現行APIはページングなしです。全件をスコア降順で返します。
ツムに skillId を割り当てる場合に必要です。iPhoneは盤面を送信し、サーバーが返すアクションをネイティブで実行します。リクエストにJavaScriptコードを含めず、サーバー側でそのツムに割り当てられたスキルを選びます。
{
"myTsumIndex": 0,
"active": [
{
"id": "piece-1",
"typeIndex": 1,
"body": {
"x": 120,
"y": 300
}
},
{
"id": "piece-2",
"typeIndex": 0,
"body": {
"x": 170,
"y": 330
}
}
]
}active はボムを除く最大100個。id は1〜80文字で配列内で一意、typeIndex / myTsumIndex は0〜5の整数。座標は有限の数値(受理範囲−1000〜2000)です。左上原点、xは右向き、yは下向き。プレイエリアは {x:38,y:170,width:299,height:410}。iPhoneの盤面座標はこの論理座標に変換して送られます。
{
"actions": [
{
"type": "time",
"value": 3
},
{
"type": "boost",
"value": 5000
},
{
"type": "clear",
"ids": [
"piece-1"
]
}
]
}| type | 値 | 意味 |
|---|---|---|
clear | ids: string[] | 該当ツムを消去し、通常の消去スコアを加算 |
transform | ids: string[] | 該当ツムを今回のマイツムに変更 |
bomb | x, y: number | 指定座標にボム生成。x: 0〜375、y: 0〜1000 |
time | value: 0〜3600 | 残り時間を追加(秒) |
score | value: 0〜1,000,000 | スコアを直接加算 |
boost | value: 0〜3,600,000 | スコア2倍の継続時間(ミリ秒) |
fever | 追加フィールドなし | 未発動ならフィーバーを開始。このアクション自体では時間ボーナスを加えない |
アクションは最大64個、対象IDはリクエストの盤面に存在するものだけを返します。通信中は両クライアントの盤面・タイマーを停止。成功した時だけゲージを消費し、失敗時は再試行できます。このAPIにはrequest_idによる同一結果の再送保証はありません。
制限付きQuickJSで割り当て済みコードを評価します。CPU 50ms・メモリ8MB・スタック256KB。ネットワーク、ファイル操作、Pythonコールバックは提供しません。
ctx.clearTsums / transformTsums / spawnBomb / addTime / addScore / setScoreBoost / activateFever と、getTsumsInArea / getTsumsInRect / randomTsums / getMyTsums / getNonMyTsums を提供します。戻り値形式の clear / transform / score_boost も互換対応しています。
別サーバーでQuickJSを採用する必要はありません。同じ入力とアクション契約を守れば、サーバー側実装言語は自由です。
URLは /uploads/your-file.png のようなルート相対URLを推奨します。同一オリジンの絶対URLも利用できます。素材が認証必須なら、APIと同じBearer / Cookieを受け付けてください。HTTP 200で素材のバイト列を返し、ログインHTMLへ転送しないでください。
{
"id": "stage_example",
"name": "サンプルステージ",
"bgUrl": "/uploads/background.png",
"bgmUrl": "/uploads/music.m4a",
"seconnectUrl": null,
"seclearUrl": "/uploads/clear.wav",
"sebombUrl": null,
"seskillUrl": null,
"sefeverUrl": null,
"secomboUrl": null,
"seresultUrl": null
}SEキーは大文字小文字に注意してください。たとえば seclearUrl であって seClearUrl ではありません。未設定はnull。画像はPNG / JPEG、音声はWAV / AAC(M4A)を推奨します。Web用にアップロード可能な形式でも、iOSのUIImage / AVAudioPlayerがデコードできる形式である必要があります。
素材取得に失敗した場合は標準画像・同梱音声にフォールバックし、再読み込み案内を表示します。iPhoneの通信タイムアウトはリクエスト20秒・リソース全体40秒です。ログインURLのブラウザ遷移はこのAPI通信設定とは別です。
| 症状 / ステータス | 確認すること |
|---|---|
| 接続先URLを受け付けない | HTTPSか、パス・クエリ・認証情報が含まれていないかを確認。ポートは1〜65535。 |
| Discord認証後に戻れない | Redirect URI、oauth_state Cookie、stateの300秒期限、tsumu://auth とclient_stateを確認。TLS・プロキシ設定も確認。 |
| 400 / コード交換失敗 | 認可コードの60秒期限、再使用、verifierの不一致。ログインをやり直す。 |
| 401 / ログインし直してください | TSUMUセッションの失効・未送信・接続先違い。Discordアクセストークンを送っていないか確認。 |
| 404 / カスタムスキルなし | skillId とサーバーの割り当てを一致させる。スキル未設定ならskillIdを省略またはnullにする。 |
| 422 / 入力・スキルエラー | 名前・UUID・整数範囲・盤面を確認。スキルならコードの例外・実行時間・メモリ制限を確認。 |
| 正しいデータを取得できない | HTTP 200の本文がJSONか、必須キー・型・nullが仕様通りか確認。 |
| 画像や音声だけ読み込めない | 同一オリジン、Bearer対応、HTTP応答、実ファイル形式、ファイルサイズと通信時間を確認。 |
| ガチャ残高が足りない | サーバー残高が100以上必要。ゲストや以前の端末内残高は使わない。 |
{"detail":"Unauthorized"}通常の detail は文字列ですが、FastAPIの入力検証エラー(422)では配列になります。サーバーのログにclient secret、Bearer、Cookie、認可コード、verifierを記録・公開しないでください。スクリーンショットを共有するときも伏せてください。
このページは2026年9月22日時点のiPhone 2.2 / Client API v1の実装に対応しています。OpenAPIの文書バージョンは1.0.0。実際の互換対象は game-data.version = 1 です。管理画面を含むサーバー全APIを公開するSwaggerではなく、クライアント接続に必要な契約を抜き出した文書です。