Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

エンドポイント一覧

この文書は、公開ドキュメントとして扱う API を対象に、現行実装のレスポンス形状・要件を記載します。

対象外(内部向け)

以下は内部運用/デバッグ用途のため、この文書の詳細対象外です。

  • GET /api/debug/enable
  • POST /api/finalize/callback

デュアルランタイム構成

API ハンドラはフレームワーク非依存の共通実装で、Next.js と Hono(Lambda) の両方から利用されます。

ランタイム用途主な入口
Next.js Route Handlerローカル開発 / SSRsrc/app/api/**/route.ts
Hono on LambdaAWS デプロイ APIamplify/functions/hono-api/handler.ts

公開対象 API 一覧

メソッドパス主用途X-Session-IDX-Session-Capability
POST/api/sessionセッション作成不要不要
POST/api/vote投票送信必須不要
GET/api/progressボット投票進捗必須必須
POST/api/finalize集計/証明生成必須必須
POST/api/finalize/cancel非同期集計キャンセル必須必須
GET/api/sessions/:sessionId/status非同期集計ステータス不要必須
GET/api/verify検証ペイロード取得必須必須
POST/api/verification/runSTARK 検証実行必須必須
GET/api/verification/bundles/:sessionId/:executionIdバンドル ZIP 取得不要必須
GET/api/verification/bundles/:sessionId/:executionId/report検証レポート取得不要必須
GET/api/bulletin掲示板一覧(inspection)必須必須
GET/api/bulletin/:voteId/proof最小包含証明必須必須
GET/api/bulletin/consistency-proof整合性証明(tooling)必須必須
GET/api/botdata/:idボット投票データ(tooling)必須必須
GET/api/bitmap-proofビットマップ証明材料必須必須
GET/api/sthSTH スナップショット必須必須
GET/api/zkvm-input-hashzkVM 入力コミットメント不要必須

共通の実装上の注意

ミドルウェア構成

ミドルウェアは「全リクエスト共通の固定チェーン」ではなく、エンドポイント実装ごとに必要な検証を呼び出す方式です。セッションヘッダーの要否は上記一覧テーブルを参照してください。

区分代表エンドポイントTurnstileレート制限
セッション作成POST /api/session環境設定次第セッション作成用
投票POST /api/voteあり投票用
集計POST /api/finalizeありzkVM 用
非同期集計キャンセルPOST /api/finalize/cancelなしキャンセル専用
検証実行POST /api/verification/runなしzkVM 用
読み取り(セッションスコープ)GET /api/progress, GET /api/bulletin*, GET /api/botdata/:id, GET /api/bitmap-proof, GET /api/sth, GET /api/verifyなしなし
読み取り(path/query で session を指す)GET /api/sessions/:sessionId/status, GET /api/verification/bundles/..., GET /api/zkvm-input-hashなしなし

共通セッションエラー(ヘッダースコープ)

X-Session-ID / X-Session-Capability をヘッダーで受け取る大多数のエンドポイントは、validateSessionWithCapability() を経由し、以下の共通エラーを返し得ます。各エンドポイントの「主なエラー」欄ではこれらを省略し、固有エラーのみ記載します。

  • SESSION_ID_REQUIRED (400)
  • SESSION_CAPABILITY_REQUIRED (401)
  • SESSION_CAPABILITY_INVALID (401)
  • SESSION_CAPABILITY_EXPIRED (401)
  • SESSION_NOT_FOUND (404)

パス/クエリで session を指定するエンドポイント(/api/sessions/:sessionId/status, /api/verification/bundles/..., /api/zkvm-input-hash)も capability 検証は共通ですが、session 特定エラーの形式が異なるため、各エンドポイントで個別に記載します。

ボディサイズ制限

共通 JSON パーサーを使うエンドポイントは API_REQUEST_BODY_LIMIT_BYTES(既定 16 KiB)を超えると PAYLOAD_TOO_LARGE (413) を返します。

例外:

  • POST /api/finalize/cancel は現状 request.json() を直接使うため、この共通サイズ制限の対象外です。JSON 不正や payload 不正は handler 固有の 400 を返します。

エラーレスポンスの形式

多くのエンドポイントは errorResponse(...) を通して以下の形式を返します。

  • error(エラーコード)
  • message(メッセージ)
  • statusCode(HTTP ステータス)
  • 必要に応じて details など

例えば以下のエンドポイントでは、session/capability 失敗は標準形式ですが、handler 内部の個別検証では { error: "..." } 系の独自形式を返す場合があります。

  • POST /api/finalize/cancel
  • GET /api/sessions/:sessionId/status
  • GET /api/bulletin/consistency-proof
  • GET /api/bitmap-proof
  • GET /api/zkvm-input-hash

基本フロー API

POST /api/session

新規セッションを作成します。X-Session-ID は不要です。

レスポンス(200):

  • data.sessionId
  • data.electionId
  • data.electionConfigHash
  • data.logId
  • data.capabilityToken

備考:

  • SESSION_CREATE_TURNSTILE_REQUIRED=1 の場合、turnstileToken が必要です。

POST /api/vote

ユーザー投票を保存し、ボット投票を非同期開始します。

要件:

  • ヘッダー: X-Session-ID 必須
  • ボディ: commitment, vote, randturnstileToken は開発設定により省略可)
  • Turnstile 検証あり
  • 投票用レート制限あり

レスポンス(200):

  • data.voteId
  • data.commitment
  • data.bulletinIndex
  • data.bulletinRootAtCast
  • data.timestamp

主なエラー:

  • CAPTCHA_FAILED (403)
  • GLOBAL_LIMIT_EXCEEDED (503)
  • ALREADY_VOTED (400)
  • SESSION_FINALIZED (400)
  • INVALID_REQUEST (400; リクエスト形式不正)
  • INVALID_COMMITMENT (400)
  • DUPLICATE_VOTE (409)
  • PAYLOAD_TOO_LARGE (413)

GET /api/progress

投票進捗を取得します。

レスポンス(200):

  • data.count
  • data.total
  • data.completed
  • data.userVoted
  • data.finalized

主なエラー: 共通セッションエラー(ヘッダースコープ)のみ。

POST /api/finalize

集計と証明生成を開始します。同期/非同期の 2 形態があります。

要件:

  • ヘッダー: X-Session-ID 必須、X-Session-Capability 必須
  • ボディ: scenarioIdS0-S5), turnstileToken(環境により必須)
  • Turnstile 検証あり
  • zkVM レート制限あり

レスポンス(200, 同期):

  • data.sessionId
  • data.tally
  • data.bulletinRoot
  • data.verifiedTally
  • data.voteReceipt
  • data.receipt(同期成功レスポンスで返却)
  • data.receiptPublication(保存時)
  • data.imageId
  • data.userVote
  • data.missingSlots
  • data.invalidPresentedSlots
  • data.rejectedRecords
  • data.missingIndices
  • data.invalidIndices
  • data.countedIndices
  • data.totalExpected
  • data.treeSize
  • data.excludedSlots
  • data.excludedCount
  • data.sthDigest
  • data.seenBitmapRoot(条件付き)
  • data.includedBitmapRoot
  • data.inputCommitment
  • data.seenIndicesCount
  • data.journal
  • data.verificationStatus
  • data.verificationBundleUrl / data.verificationReportUrl / data.verificationReport(条件付き)
  • data.verificationExecutionId(条件付き)
  • data.s3BundleUrl / data.s3BundleKey / data.s3UploadedAt / data.s3BundleExpiresAt(条件付き)
  • data.tamperSummary(条件付き)

補足:

  • verificationBundleUrl は秘密データを除外した配布用アーカイブの capability 認証付き取得先です。s3BundleUrl は同内容の短命な署名付き URL です。いずれも無認証では取得できません。

レスポンス(202, 非同期):

  • executionId
  • statusUrl
  • state
  • queuenull の場合あり)

主なエラー:

  • CAPTCHA_FAILED (403)
  • INVALID_REQUEST (400)
  • VERIFICATION_FAILED (400; CT proof unavailable)
  • USER_NOT_VOTED (400)
  • VOTING_NOT_COMPLETE (400)
  • SESSION_ALREADY_FINALIZED (400)
  • ZKVM_RATE_LIMIT_EXCEEDED (429)
  • GLOBAL_LIMIT_EXCEEDED (503)
  • PAYLOAD_TOO_LARGE (413)
  • Invalid ImageID (400; 独自形式 { error: "Invalid ImageID", details: { expected, actual } })

POST /api/finalize/cancel

進行中の非同期集計をキャンセルします。

要件:

  • FINALIZE_ASYNC_MODE=true のときのみ有効
  • ヘッダー: X-Session-IDx-session-id も受理)
  • ヘッダー: X-Session-Capability 必須
  • ボディ: executionId 必須、reason 任意
  • キャンセル専用レート制限あり

レスポンス(200):

  • state

主なエラー:

  • GLOBAL_LIMIT_EXCEEDED (503)

handler 固有エラー(独自形式):

  • 404: Async finalization disabled
  • 400: Invalid JSON body / payload 不正
  • 409: 現在状態ではキャンセル不可
  • 501: ストアが cancellation 非対応

GET /api/sessions/:sessionId/status

非同期集計の状態を返します。

要件:

  • パスパラメータ sessionId 必須
  • ヘッダー: X-Session-Capability 必須

レスポンス(200):

  • sessionId
  • finalizationStatenull の場合あり)
  • queuenull の場合あり)
  • progress(条件付き)
  • finalizationResultnull の場合あり)
  • stepFunctionsnull の場合あり)
  • asyncFinalizationModeenabled / disabled

主なエラー:

  • SESSION_CAPABILITY_REQUIRED (401)
  • SESSION_CAPABILITY_INVALID (401)
  • SESSION_CAPABILITY_EXPIRED (401)

handler 固有エラー(独自形式):

  • 400: Session ID is required
  • 404: Session not found

検証 API

GET /api/verify

検証画面向けの統合ペイロードを返します。

要件:

  • クエリ: refreshS3=1, includeJournal=1(任意)

レスポンス(200):

  • data.electionId
  • data.electionConfigHash
  • data.logId
  • data.tally
  • data.bulletinRoot
  • data.scenarioId
  • data.verificationStatus
  • data.verificationBundleUrl / data.verificationReport(条件付き)
  • data.verificationSteps / data.verificationChecks
  • data.s3BundleUrl / data.s3UploadedAt / data.s3BundleExpiresAt(条件付き)
  • data.imageId
  • data.tamperDetected
  • data.verifiedTally
  • data.missingSlots
  • data.invalidPresentedSlots
  • data.rejectedRecords
  • data.missingIndices
  • data.invalidIndices
  • data.countedIndices
  • data.totalExpected
  • data.treeSize
  • data.excludedSlots
  • data.excludedCount
  • data.sthDigest
  • data.seenBitmapRoot(条件付き)
  • data.includedBitmapRoot
  • data.inputCommitment
  • data.seenIndicesCount(条件付き)
  • data.journalStatus
  • data.journalincludeJournal=1 のとき)
  • data.voteReceipt(条件付き)
  • data.userVote
  • data.botVotesSummary(条件付き)
  • data.verificationExecutionId(条件付き)
  • data.tamperSummary(条件付き)

fail-closed 応答:

  • verificationStatus が許容セット外でも、ストアから取得可能な finalized session に対しては 200 で通常の data payload を返します。data.verificationStatusfailed に正規化され、verificationSteps / verificationChecks に fail-closed な結果が入ります。

主なエラー:

  • SESSION_NOT_FINALIZED (400)
  • USER_NOT_VOTED (400)

POST /api/verification/run

サーバー側で STARK レシート検証を実行します。

要件:

  • ボディ: JSON オブジェクト(通常は空オブジェクト {}
  • zkVM レート制限あり

レスポンス(200):

  • data.verificationStatussuccess / failed / dev_mode / not_run / running
  • data.verificationExecutionId
  • data.estimatedDurationMs
  • data.idempotent

挙動:

  • 既存結果がある場合や実行中の場合は、再実行せず idempotent: true を返します。

主なエラー:

  • SESSION_NOT_FINALIZED (400)
  • INVALID_REQUEST (400)
  • ZKVM_RATE_LIMIT_EXCEEDED (429)
  • GLOBAL_LIMIT_EXCEEDED (503)
  • PAYLOAD_TOO_LARGE (413)
  • INTERNAL_ERROR (500)

バンドル取得 API

両エンドポイントとも X-Session-Capability ヘッダーによる capability 保護が必須です。S3 配信が有効な場合、または Lambda ランタイムでは 302 で期限付き presigned URL にリダイレクトします。

GET /api/verification/bundles/:sessionId/:executionId

秘密データを含まない配布対象アーカイブ bundle.zip を返します。

レスポンス:

  • 200: ZIP バイナリ
  • 302: S3 presigned URL へリダイレクト

主なエラー:

  • SESSION_CAPABILITY_REQUIRED (401)
  • SESSION_CAPABILITY_INVALID (401)
  • SESSION_CAPABILITY_EXPIRED (401)
  • 400: パラメータ不正
  • 404: バンドル未検出
  • 500: ダウンロード URL 生成失敗 / 読み込み失敗

GET /api/verification/bundles/:sessionId/:executionId/report

検証レポート verification.json を返します。これは capability 保護された非公開レポートであり、公開バンドルには含まれません。

レスポンス:

  • 200: JSON
  • 302: S3 presigned URL へリダイレクト

主なエラー:

  • SESSION_CAPABILITY_REQUIRED (401)
  • SESSION_CAPABILITY_INVALID (401)
  • SESSION_CAPABILITY_EXPIRED (401)
  • 400: パラメータ不正
  • 404: レポート未検出
  • 500: ダウンロード URL 生成失敗 / 読み込み失敗

掲示板 API

GET /api/bulletin

掲示板一覧を返します。

要件:

  • クエリ: offset, limit(任意)

レスポンス(200):

  • commitments
  • bulletinRoot
  • treeSize
  • timestamp
  • rootHistory(条件付き)
  • nextOffset / hasMore(ページング時)

主なエラー:

  • INVALID_OFFSET (400)
  • INVALID_LIMIT (400)
  • INVALID_REQUEST (400; details=BULLETIN_STATE_UNAVAILABLE)

GET /api/bulletin/:voteId/proof

最小形式の包含証明を返します。

要件:

  • セッションは finalized 必須
  • パス: voteId(UUID v4 形式)

アクセス制御:

  • 原則は「そのセッションのユーザー投票」のみ
  • 例外としてシナリオ S3/S4 では対象ボット票を許可

レスポンス(200):

  • voteId
  • proof.leafIndex
  • proof.merklePath
  • proof.treeSize
  • proof.bulletinRootAtCast
  • proof.proofMode

キャッシュ:

  • Cache-Control: private, no-store
  • Vary: X-Session-ID, X-Session-Capability

主なエラー:

  • INVALID_VOTE_ID (400)
  • SESSION_NOT_FINALIZED (400)
  • VOTE_NOT_FOUND (404)
  • VERIFICATION_FAILED (400; CT proof unavailable)

GET /api/bulletin/consistency-proof

RFC6962 整合性証明を返します。

補足:

  • shipped /verify ページの verdict authority には含まれません
  • 現在は secondary tooling / inspection 用の surface として扱います

要件:

  • クエリ: oldSize, newSize 必須

レスポンス(200):

  • oldSize
  • newSize
  • rootAtOldSize
  • rootAtNewSize
  • proofNodes
  • oldSubtreeHashes / appendSubtreeHashes(条件付き)
  • timestamp

主なエラー(handler 固有、独自形式):

  • 400: oldSize / newSize 欠落・不正・範囲外、掲示板未初期化、proof 生成失敗
  • 500: consistency proof 生成中の内部エラー

GET /api/botdata/:id

ボット投票(1..63)のデータと証明を返します。

補足:

  • 将来の bot verification UI の building block であり、現行 /verify ページの authority には含まれません

要件:

  • セッション finalized 必須

レスポンス(200):

  • data.id
  • data.vote
  • data.random
  • data.commitment
  • data.voteId
  • data.timestamp
  • data.proofleafIndex, merklePath, treeSize, bulletinRootAtCast, proofMode

主なエラー:

  • INVALID_BOT_ID (400)
  • SESSION_NOT_FINALIZED (400)
  • BOT_DATA_NOT_FOUND (404)
  • INTERNAL_ERROR (500; CT proof を組み立てられない場合を含む)

補助 API

GET /api/bitmap-proof

ビットマップ証明の材料を返します。

要件:

  • クエリ: i(0 以上整数)必須
  • クエリ: kind 任意(included / seen、省略時は included

備考:

  • 全ストア実装で sessionId をキーに保存済み bitmap を参照します。
  • included は counted された index、seen は prover に提示された index を対象にします。

レスポンス(200):

  • leafChunk
  • auditPath

キャッシュ:

  • ETag 対応
  • If-None-Match 一致時 304
  • Cache-Control: private, max-age=86400, stale-while-revalidate=3600, immutable
  • Vary: X-Session-ID, X-Session-Capability

主なエラー(handler 固有、独自形式):

  • INVALID_INDEX (400)
  • INVALID_BITMAP_KIND (400)
  • BITMAP_NOT_FOUND (404)
  • INTERNAL_ERROR (500)

GET /api/sth

STH スナップショットを返します。

要件:

  • finalized セッションのみ

レスポンス(200):

  • sth.sthDigest
  • sth.bulletinRoot
  • sth.treeSize
  • sth.timestamp
  • sth.logId

備考:

  • 現行実装の sth.timestamp はジャーナル内時刻ではなく、session.lastActivity を返します。

主なエラー:

  • SESSION_NOT_FINALIZED (404; このエンドポイント固有の扱い)
  • INTERNAL_ERROR (500; 例: finalized 済みだが journal が欠落している場合)

GET /api/zkvm-input-hash

セッション由来の zkVM 入力コミットメントを返します。

要件:

  • クエリ: sessionId 必須
  • ヘッダー: X-Session-Capability 必須
  • クエリ: includeData 任意(true / 1 / yes で有効)
  • includeData=true は debug authorization が必要

レスポンス(200):

  • inputCommitment
  • dataincludeData 有効時のみ)

主なエラー:

  • SESSION_CAPABILITY_REQUIRED (401)
  • SESSION_CAPABILITY_INVALID (401)
  • SESSION_CAPABILITY_EXPIRED (401)

handler 固有エラー(独自形式):

  • INVALID_REQUEST (400)
  • SESSION_NOT_FOUND (404)
  • SESSION_NOT_FINALIZED (400)
  • CT_PROOF_UNAVAILABLE (400)
  • INCLUDE_DATA_FORBIDDEN (403)
  • INTERNAL_ERROR (500)