從 public request 開始
status endpoint 不需要 token。簽發前請先檢查 enabled,並從 limits 讀取 workspace 限額。
curl --fail-with-body --silent --show-error \
https://ifandonlyif.io/api/apostille/v1/status
這是 hosted REST API。公開 MCP 是另一個唯讀介面(見下方)。
使用 administrator key 驗證身分
當 GET /status 的 protocols 列出 Core 0.3 時,使用 ML-DSA-65 administrator key。首次登入會建立 private workspace,之後登入會回到該 workspace。Ed25519 key 只能登入既有的 Core 0.1 workspace(唯讀)。沒有密碼、OAuth 或 account recovery。
- 以 administrator public_key(Ed25519 為 32 bytes、ML-DSA-65 為 1952 bytes,unpadded base64url)要求 challenge。回應含 challenge_id、issuer、message 與 expires_at(五分鐘)。
- 以設定的 issuer、key 的 fingerprint、回傳的 UUID v4 challenge_id 與 canonical UTC expires_at,重建下方 message(結尾不含換行)。只接受七分鐘內到期的 challenge。
- 在本機簽署完全相同的 UTF-8 message(Core 0.1 用 Ed25519,Core 0.3 用 ML-DSA-65)。將 challenge_id、message 與 unpadded-base64url signature POST 至 /auth/verify。challenge 只能用一次,切勿傳送 private key。
- 管理員的 access_token 保存在記憶體,並以 Authorization: Bearer <access_token> 只傳至 owner routes。有效 900 秒,到期後請以新的 challenge 登入。不要把管理員 session 或簽署金鑰放進 CI。
iff-apostille/login/0.1
issuer:https://ifandonlyif.io/apostille
key_id:<administrator_key_id>
challenge:<challenge_id>
expires_at:<expires_at>
purpose:register_or_login
key_id 是 sha256: 後接原始 public key 的小寫 SHA-256 hex。此 message 不是 artifact signature。
CI 唯讀憑證
API 預覽,是否可用依各部署而定。使用前請確認目標服務 /status 的 enabled: true、features 同時含 supply_chain_releases 與 supply_chain_ci_credentials,並確認實際端點可用。
不透明的 CI bearer 固定綁定單一工作區、完全相符的 product 與 policy label,只能讀取範圍內 release、目前政策及評估中繼資料;其他 owner routes 一律拒絕。仍須指定最新 policy version,並獨立選擇 issuer/producer pins。
以 Core 0.3 管理員 session 加上已簽署的 create_release_credential 操作建立。到期時間必須明訂,最多 90 天(建議 30 天);範圍不可變更,也沒有萬用字元。token 只回傳一次,重試只回 metadata。管理員 session 可列出或撤銷憑證。每次請求都檢查到期與撤銷,但已進行中的請求可能完成。
Core 版本與 hosted Core 0.3
Hosted service 只簽發 Core 0.3(ML-DSA-65),並於 GET /status 的 protocols 列出。Core 0.1 與 0.2 的 record 仍可查驗(verification_protocols)。只有 Core 0.3 的簽章是後量子,並非整個 service;SHA-256 digest 使碰撞強度維持在 NIST category 2。託管 issuer 的 pin 在公開 repository 的 HOSTED_KEYS.md。
- GET /keys 回傳 Core 0.1 directory:用於查驗過去 bundle 的 legacy Ed25519 key;未設定時 keys 為空。GET /keys?protocol=<URL 編碼的完整 identifier> 回傳該版本的 directory(protocol、issuer、含 key_id、public_key 與 algorithm 的 keys[],以及 trust)。Core 0.3 的 key 是 ML-DSA-65,public key 為 2603 個字元。未知或不支援的版本(包括 Core 0.2):400 unsupported_protocol_version。
- ML-DSA-65(2603 字元)key 使用第一行為 iff-apostille/login/0.3 的 login message(見下方);以 pure ML-DSA-65 與空 context 簽署(簽章 4412 個字元)。Ed25519(43 字元)key 使用 Core 0.1 login message,且只能登入既有的 Core 0.1 workspace;沒有 workspace 的 key 即使簽章有效,也回傳 410 core_0_1_retired。ML-DSA key 不得退回使用 Core 0.1 登入。
iff-apostille/login/0.3
issuer:https://ifandonlyif.io/apostille
key_id:<administrator_key_id>
challenge:<challenge_id>
expires_at:<expires_at>
purpose:register_or_login
只有第一行不同。key_id 是 sha256: 後接原始 ML-DSA-65 public key 的小寫 SHA-256 hex。
- workspace 的 Core 版本由其 administrator key 的演算法決定。新 workspace 為 Core 0.3(ML-DSA-65)。既有 Core 0.1(Ed25519)workspace 為唯讀:可讀取、下載、編輯 profile、撤銷,以及更新、撤回與評估 release policy;註冊、簽發與 ERC-8004 binding 回傳 410 core_0_1_retired。Core 0.2 回傳 400 unsupported_protocol_version。
- ML-DSA-65 administrator key 會開啟自己的 workspace。Core 0.1 workspace 不會遷移:其 agent、certificate 與 profile 仍歸屬 Ed25519 key。
- 請雙向檢查版本:grant 的 protocol 等於 statement 的 protocol,回傳 bundle 的 protocol 等於所提交的 protocol。新的 certificate 請 pin Core 0.3 issuer key,過去的請 pin Core 0.1 key。
逐次授權每一次 publication
登入並不授權 publication。請用 Core SDK 或 CLI 建立 signed envelope,不要自創 serialization。
- administrator 簽署 delegation,agent 簽署 acceptance,綁定相同的 agent 與 service audience。以 POST /agents 註冊。
- 在本機對原始檔案做 hash,並建立 agent 簽署的 origin-statement。原始檔案由你的應用程式選擇並保留。
- administrator 簽署另一份 publication grant,綁定 statement digest、audience、nonce 與 private/public visibility。只將 statement 與 grant POST 至 /submissions。login token 不能取代 grant。
- visibility 由 signed grant 決定。public grant 授權散布整份 signed bundle(可連結的 key、identifier、timestamp、digest、size),不含 workspace profile。
- 下載 bundle,以獨立選定的 issuer/key pin 在本機驗證。API 傳回的 key 不會自動成為 trusted key。
Endpoint 參考
路徑均相對於 REST base URL;GET 也支援 HEAD。Owner routes 使用管理員 session,只有下列三個讀取/評估端點也接受 scoped CI。Public routes 不需要 token;公開 release 使用 public_id。
欄位清單描述回應形狀,不是可直接送出的 JSON。version 與 size 欄位是十進位字串。
GET /status
Public
讀取 issuer、簽發的 protocols、可查驗的 verification_protocols、availability 與 limits。legacy 的 protocol 欄位是 Core 0.1 identifier。列出的計畫中 provider 並非已啟用的 identity check。
- Request fields
- 無 request body
- Response fields / type
protocol (legacy: the Core 0.1 identifier), protocols[] (full identifiers the service issues; absent on a service that predates it), verification_protocols[] (full identifiers it verifies), issuer, enabled, limits {max_agents, max_daily_certificates}, features[] (supply_chain_releases advertises release API support; supply_chain_ci_credentials advertises scoped CI credentials; check enabled separately; ml_dsa_65_keys when Core 0.3 is enabled; core_0_1_issuance_retired), planned[]- Success HTTP status
200
GET /keys
Public
讀取 issuer public key 與 fingerprint;?protocol=<完整 identifier> 可選擇某個 Core 版本的 directory。directory 只是查詢,不是 trust root。
- Request fields
protocol (query, optional): full identifier, URL-encoded- Response fields / type
protocol, issuer, keys[] {key_id, public_key, algorithm}, trust- Success HTTP status
200
POST /auth/challenges
Public
建立短效 login challenge。同一 key 的第六個未使用 challenge 會使最舊的失效。
- Request fields
public_key: string (Ed25519, 43 characters; or ML-DSA-65, 2603 characters)- Response fields / type
challenge_id, message, expires_at, issuer- Success HTTP status
201
POST /auth/verify
Public
使用 challenge,取得 15 分鐘的 session。過期、遭修改或重播的 proof 都會被拒絕。
- Request fields
challenge_id: string, message: string, signature: string (Ed25519, or ML-DSA-65 with 4412 characters)- Response fields / type
access_token, token_type, expires_in, workspace: Workspace- Success HTTP status
200
GET /me
Owner
讀取你的 workspace、agent records 與近期 certificates。此 alpha 沒有 pagination。
- Request fields
- 無 request body
- Response fields / type
workspace: Workspace, agents: Agent[], certificates: Certificate[]- Success HTTP status
200
PUT /workspace
Owner
更新 workspace name 與 public-profile visibility。不會公開任何 certificate;profile 為自述。
- Request fields
name: string, is_public: boolean- Response fields / type
Workspace- Success HTTP status
200
POST /agents
Owner
註冊有效的 delegation 與 acceptance。完全相同且已授權的 replay 會回傳原始 record。僅限 Core 0.3;Core 0.1 的 request 或 workspace 回傳 410 core_0_1_retired。
- Request fields
name: string, delegation: Envelope, acceptance: Envelope- Response fields / type
Agent- Success HTTP status
201 / 200
POST /agents/{id}/revoke
Owner
不可逆地撤銷 agent 的新簽發權限。既有 signed bytes 不變;offline verification 看不到撤銷。
- Request fields
- 無 request body
- Response fields / type
Agent (revoked_at)- Success HTTP status
200
POST /submissions
Owner
驗證 agent、statement 與獨立 publication grant 後簽發 origin certificate。完全相同的 retry 仍需有效 authorization。僅限 Core 0.3;Core 0.1 的 request 或 workspace 回傳 410 core_0_1_retired。
- Request fields
statement: Envelope, grant: Envelope- Response fields / type
Certificate (id, workspace_id, agent_id, public_id, idempotency_key, body_hash, bundle, is_public, created_at)- Success HTTP status
201 / 200
GET /certificates/{id}/bundle
Owner
直接下載 signed Bundle。其他 workspace 無法取得。
- Request fields
- 無 request body
- Response fields / type
Bundle- Success HTTP status
200
POST /certificates/{id}/hide
Owner
停止公開提供證明書及依賴它的 release。無法恢復或刪除已下載副本;與 release 撤回是不同操作。
- Request fields
- 無 request body
- Response fields / type
id, is_public: false- Success HTTP status
200
GET /public/certificates/{public_id}
Public
以 public_id 讀取明確設為 public 的 certificate(private 或 hidden 回傳 404)。不提供原始檔案。
- Request fields
- 無 request body
- Response fields / type
public_id, bundle: Bundle, created_at- Success HTTP status
200
GET /public/organizations/{public_id}
Public
以 public_id 讀取明確設為 public 的 workspace profile。標記 self_declared,不含 key 與 private fields。
- Request fields
- 無 request body
- Response fields / type
profile {public_id, name, created_at}, organization_binding: self_declared- Success HTTP status
200
GET /erc8004/config
Public
讀取 ERC-8004 binding 是否啟用、支援的 registries,以及簽發的 binding profile(profiles;profile 為 legacy 的 0.1 identifier)。此為 public。
- Request fields
- 無 request body
- Response fields / type
profile (legacy: the 0.1 identifier), profiles[] (binding profiles the service issues), enabled, networks[] {chain_id, registry_address}, max_binding_age_seconds, wallet_support- Success HTTP status
200
POST /agents/{id}/erc8004
Owner
提交 administrator 簽署的 binding request 與 EOA owner 的 EIP-191 signature。回傳 private、immutable 的 issuer_checked snapshot;不送出 chain transaction。Core 0.3 workspace 簽發 binding 0.3;binding 0.1 回傳 410 core_0_1_retired。
- Request fields
request: Envelope, owner_signature: string (0x + 130 lowercase hex characters)- Response fields / type
id, agent_id, document, created_at, expires_at- Success HTTP status
201 / 200
GET /agents/{id}/erc8004
Owner
取得你最新的 private binding snapshot(其他 workspace 回傳 404)。它記錄 issuer 在單一 finalized block 觀察到的 ownership,不證明 current ownership 或 payment authority。
- Request fields
- 無 request body
- Response fields / type
id, agent_id, document, created_at, expires_at- Success HTTP status
200
POST /releases
Owner
API preview:需要 /status 的 enabled: true 與 features 含有 supply_chain_releases。登錄已由證明書涵蓋的 canonical release manifest,並附獨立的 administrator 簽署授權。不上傳 binary 或原始碼。Core 0.1 的 workspace 或 certificate 回傳 410 core_0_1_retired。
- Request fields
certificate_id: string, manifest_base64: string, visibility: private | public, authorization: {payload_base64, statement: Envelope}- Response fields / type
Release- Success HTTP status
201 / 200
GET /releases/{id}
Owner
取得自己的 release manifest、certificate bundle 與目前 hosted status。接受 owner session,或同工作區、完全相符 product 的 CI 憑證。有效簽章不代表目前允許部署。
- Request fields
- 無 request body
- Response fields / type
release: Release, bundle: Bundle, current_status: {state, withdrawn_at, reason, agent_state, as_of, basis, offline_proof: false, issuer_key_revocation: unknown}- Success HTTP status
200
GET /public/releases/{id}
Public
以 public_id 取得公開 release evidence(私有或已隱藏回傳 404)。status 是 hosted observation,不是離線撤銷證明。
- Request fields
id: release public_id- Response fields / type
public_id, product, version, manifest_base64, manifest_sha256, created_at, bundle: Bundle, current_status- Success HTTP status
200
POST /releases/{id}/status-events
Owner
以新的 administrator 簽署 withdraw_release 操作不可逆地撤回 release;release_id 必須與路徑相同。登入簽章不能代替授權。
- Request fields
release_id: string (matches path), action: withdraw, reason: security_incident | superseded | maintainer_request, authorization: {payload_base64, statement: Envelope}- Response fields / type
event: ReleaseStatusEvent, state: withdrawn- Success HTTP status
201 / 200
POST /release-policies
Owner
保存不可變的 policy version,從 "1" 開始逐次加一。Expected issuer、issuer 與 producer keys、product 及 Core protocols 都須獨立 pin;API key directory 不是信任來源。
- Request fields
policy: Policy, authorization: {payload_base64, statement: Envelope}- Response fields / type
id, version: decimal string, policy: Policy, policy_sha256, authorization, created_at- Success HTTP status
201 / 200
GET /release-policies/{id}
Owner
取得目前 policy version。接受 owner session,或同工作區、完全相符 policy label 與 product 的 CI 憑證;不能選擇舊版本繞過政策。
- Request fields
- 無 request body
- Response fields / type
Current id, version: decimal string, policy: Policy, policy_sha256, authorization, created_at- Success HTTP status
200
POST /release-policy/evaluations
Owner
依目前 policy、release、withdrawal 與 agent state 評估中繼資料。接受 owner session,或綁定同 product/policy 的 CI 憑證。allowed_by_policy 不檢查實際位元組(artifact_bytes_checked 為 false);valid_until 僅供參考,最多 30 秒且不晚於憑證到期。請在本機驗證並使用同一份實際檔案。
- Request fields
release_id: string, policy_id: string, policy_version: decimal string, artifact_name: string, artifact_sha256: string, artifact_size: decimal string- Response fields / type
decision: allowed_by_policy | blocked | unknown, reasons[], release_id, policy_id, policy_version, policy_sha256 (when found), evaluated_at, valid_until, current_status, artifact_name, artifact_sha256, artifact_size, artifact_bytes_checked: false- Success HTTP status
200
POST /release-credentials
Owner
需要 owner session 與 Core 0.3 管理員對 {name,product,policy_id,expires_at} 簽署的 create_release_credential 授權。相同 product 的政策須已存在,到期時間須在未來且最多 90 天。201 只回傳一次 token;完全相同且授權仍有效的重試回 200 metadata。遺失回應時先列出/撤銷,再以新 nonce 建立替代憑證。每工作區最多 100 個有效憑證、1,000 筆保留紀錄。
- Request fields
name: string, product: string, policy_id: string, expires_at: canonical UTC timestamp, authorization: {payload_base64, statement: Envelope}- Response fields / type
credential: {id, name, product, policy_id, created_at, expires_at, revoked_at (optional)}, token: string (201 only; absent on 200 retry)- Success HTTP status
201 / 200
GET /release-credentials
Owner
僅接受 owner session,拒絕 CI token。列出憑證 metadata,含過期/撤銷紀錄。不回傳原始 token 或雜湊,也無法復原遺失的 token。
- Request fields
- 無 request body
- Response fields / type
credentials[] {id, name, product, policy_id, created_at, expires_at, revoked_at (optional)}- Success HTTP status
200
POST /release-credentials/{id}/revoke
Owner
僅接受 owner session,以冪等操作撤銷憑證。此操作只縮減權限,不需要額外簽署授權。後續請求會失敗,但已進行中的請求可能完成;離線證據不變。
- Request fields
- 無 request body
- Response fields / type
credential: {id, name, product, policy_id, created_at, expires_at, revoked_at}- Success HTTP status
200
Retry、limits 與 expiry
Agent registration:相同 workspace、agent ID 與 delegation 回傳 200 及原始 record;衝突的 delegation 回傳 409 agent_already_registered。仍需有效 authorization。
Submission:以 grant nonce 與 body 識別 retry;相同 nonce 搭配不同內容回傳 409 idempotency_conflict。timeout 後,retry 前請檢查 /me。
ERC-8004:相同 nonce 與完全相同的 request 回傳原始 snapshot(200);不同內容回傳 409 binding_nonce_conflict。新的 observation 需要新的 signed request。
- POST/PUT body:嚴格 UTF-8 JSON,Content-Type: application/json,不超過 256 KiB。duplicate key、unknown field 與 JSON number 會被拒絕;signed 數量使用 decimal string。不支援 multipart。
- max_agents 與 max_daily_certificates 來自 /status(alpha 預設為 100)。Certificate 最長有效 24 小時,delegation 最長一年。quota 在 UTC day boundary 重設。
- Login challenge:每個 client IP 每分鐘 10 次,每個 key 最多五個未使用。ERC-8004 creation 共用 IP bucket,另限每個 workspace 每個 UTC day 100 個 new binding。收到 429 請遵守 Retry-After。
- Reference SDK 與 console 使用 10 秒 deadline 與 8 MiB response 上限,不會自動 retry write。
依 code 處理失敗
Handler error 使用如下 shape;gateway error 可能不同,請檢查 HTTP status 與 Retry-After。失敗回應不代表沒有 commit。
{"error":true,"code":"authentication_required","message":"authentication required"}
HTTP 400
invalid_request, invalid_public_key, invalid_profile, invalid_agent, invalid_submission, submission_too_large, invalid_owner_signature, invalid_source_statement, delegation_exceeds_one_year, invalid_binding_request, binding_request_expired, erc8004_registry_unsupported, unsupported_protocol_version, unsupported_key_algorithm, invalid_release, invalid_release_manifest, release_certificate_mismatch, invalid_release_status_event, invalid_release_policy, invalid_release_evaluation, invalid_release_credential
Malformed JSON、invalid field 或 signature,或無法接受的 binding request。unsupported_protocol_version:未知或不支援的 Core 版本、與 workspace 不同的版本,或 Core 0.2。unsupported_key_algorithm:Core 0.3 停用時使用 ML-DSA-65 key。
HTTP 401
authentication_required, invalid_session, invalid_authentication_proof, invalid_ci_credential
Session 遺失或過期、登入證明無效、challenge 重放,或 CI bearer 無效/過期/已撤銷。不允許的 owner route 以 invalid_session 拒絕 CI token;scoped routes 使用 invalid_ci_credential。
HTTP 403
invalid_agent_authorization, invalid_publication_grant, source_authorization_inactive, invalid_owner_signature, agent_inactive, invalid_release_authorization, release_publication_denied
administrator、agent 或 EOA owner 的證明未授權此操作,或 release 未公開。
HTTP 404
agent_not_found, certificate_not_found, profile_not_found, binding_not_found, release_not_found, release_policy_not_found, release_credential_not_found
沒有可存取的 agent、證明書、binding、release、policy、credential 或公開 profile;CI 範圍外的 release/policy 也回 not found。
HTTP 409
agent_already_registered, agent_limit_reached, idempotency_conflict, binding_nonce_conflict, erc8004_owner_mismatch, agent_inactive, release_nonce_conflict, policy_version_conflict, release_already_withdrawn, release_conflict, release_credential_nonce_conflict, release_credential_conflict
Registration 或 nonce 衝突、agent quota、inactive binding agent、owner mismatch、release 重複、policy version 衝突,或 release 已撤回。衝突不代表可以覆寫。
HTTP 410
core_0_1_retired
Core 0.1 已停止簽發。core_0_1_retired:agent 註冊、certificate 簽發、ERC-8004 binding 0.1、Core 0.1 certificate 的 register_release,或新建 Core 0.1 workspace(僅在 login 簽章驗證通過後拒絕)。既有 Core 0.1 workspace 仍可登入、讀取、編輯 profile、撤銷與管理 release policy。 CI 憑證建立也須使用 Core 0.3;Core 0.1 工作區回 core_0_1_retired。
HTTP 422
erc8004_eoa_only
ERC-8004 owner 是 contract wallet;此 alpha 僅支援 EOA ownership consent。
HTTP 429
challenge_rate_limit, daily_submission_limit, daily_binding_limit, release_write_limit, release_rate_limit, release_credential_limit
已達 IP、每日或憑證配額。有 Retry-After 時請遵守;憑證須先核對 100 個有效/1,000 筆歷史上限,勿原樣重試。
HTTP 500
session_unavailable, stored_agent_invalid, binding_unavailable
操作失敗。重試寫入前請先查看登入後的歷史紀錄。
HTTP 503
apostille_service_unavailable, challenge_unavailable, workspace_unavailable, agent_unavailable, agent_registration_unavailable, revocation_unavailable, issuance_unavailable, binding_unavailable, erc8004_unavailable, challenge_rate_limit_unavailable, core_0_3_unavailable, release_service_unavailable, release_rate_limit_unavailable, release_credential_unavailable
Hosted issuance、release/credential storage、ERC-8004 reader 或 rate-limit backend 無法使用。core_0_3_unavailable:無法簽發 Core 0.3。請以 bounded backoff retry。
Privacy 與 verification boundaries
原件、私鑰與 ZK witness 留在自己的環境。Release 登錄只上傳 canonical manifest 與授權;evaluation 只收 digest 與 size。Hash 與 key 仍可關聯。
Certificate 只在其範圍內證明 signature 與 byte-binding check,不證明 content truth、legal identity、current authorization 或撤銷狀態。
ZK budget 為實驗性功能,只在本機 Go SDK/CLI 執行,沒有 hosted ZK endpoint。單方 development setup 可能偽造 proof。
此頁面不會傳送 request,也不接收 secret。
Public MCP 是獨立介面
匿名 Streamable HTTP,唯讀,不處理金鑰。七個 tool 用於 bundle/binding verification 與 public issuer data。Verification 在 hosted server 執行,不是在你的 client 獨立進行。
https://iff-mcp-api-production.up.railway.app/mcp/apostille
傳送 bundle 或 detached-binding JSON,以及為此 request 選定且完全相符的 issuer/key pin;不保留 trust policy。切勿上傳 private key 或原件。需要獨立查驗時請在本機驗證。
限制:每個 request 一個 JSON-RPC object,request 1 MiB、response 10 MiB,每分鐘每個 IP 60 次、每個 instance 300 次,最多四個 concurrent operation,deadline 20 秒。回傳 stateless JSON,不使用 SSE。
MCP capabilities
Implementation references