x402 合規一致性規範 v0.1
給 Agent 支付(x402 / MCP)結算前合規的一套機讀契約:每一種合規判決對應一個穩定 reason_code、一個 signal_class、一條 retry 規則。1:1 對齊線上真實的 11 道閘,可對免費端點復現。
端點【今天就返回】 reason_code / signal_class / retry / retry_hint(HTTP 狀態碼仍是 200/403/409)。 451/-4510 的換碼 = 提議中、尚未上線(換 HTTP 狀態碼是破壞性變更,須版本協商)。
1 · 信號類別與 retry 規則
| signal_class | 含義 | retry |
|---|---|---|
| ok | 未發現攔截信號 | not_applicable |
| payment | 額度/預算(可補足) | retryable_after_funding |
| regulatory | 確定性合規 FAIL(制裁/混幣/吊銷/重放) | non_retryable |
| authorization | 歸因/授權/白名單/憑證 | retry_after_authorization |
| uncertain | 篩查不可得/不確定 | policy_dependent_backoff |
| client_error | 請求格式錯誤 | retry_after_fix |
2 · reason_code 分類(對齊真實檢查項)
| reason_code | signal_class | retry | 來自 |
|---|---|---|---|
| kya_unattributed | authorization | retry_after_authorization | KYA |
| mandate_revoked | authorization | non_retryable | KYA/Revoked |
| kya_proof_missing | authorization | retry_after_authorization | KYA/Proof |
| kyc_required | authorization | retry_after_authorization | KYA/KYC |
| invalid_input | client_error | retry_after_fix | Input |
| over_per_tx_limit | payment | retryable_after_funding | Firewall/Limit |
| over_daily_limit | payment | retryable_after_funding | Firewall/Velocity |
| payee_not_allowlisted | authorization | retry_after_authorization | Firewall/Allowlist |
| mandate_intent_mismatch | authorization | retry_after_authorization | Mandate |
| sanctioned_or_high_risk_payee | regulatory | non_retryable | Screening/AML |
| behavioral_anomaly | uncertain | policy_dependent_backoff | Behavior/Anomaly |
| replay_detected | authorization | non_retryable | Mandate/Replay |
| clear | ok | not_applicable | allow |
| elevated_risk_payee | uncertain | policy_dependent_backoff | screening: review |
| screening_unavailable | uncertain | policy_dependent_backoff | screening unavailable |
| free_allowance_exhausted | payment | retryable_after_funding | anonymous monthly allowance used up on /api/decide, /api/risk or /api/payee/decide (HTTP 402): pay per call or use a free key |
| screening_partially_unavailable | uncertain | policy_dependent_backoff | screening: part of the on-chain data could not be fetched and nothing else was found; re-check later |
| payment_request_untrusted | authorization | non_retryable | POST /api/payment-request: spoofed sender, phishing link, listed payee, AI-aimed instructions, or a changed-payment-details pattern |
| payment_request_needs_confirmation | uncertain | retry_after_authorization | POST /api/payment-request: suspicious traits worth confirming through a trusted channel |
| phishing_endpoint | regulatory | non_retryable | GET /api/endpoint: the URL or its parent domain is on a phishing-domain list |
| elevated_risk_endpoint | uncertain | policy_dependent_backoff | GET /api/endpoint: suspicious hostname shape or an unknown host |
| payee_differs_from_listing | authorization | retry_after_authorization | POST /api/decide: payment_intent.payee differs from the payout wallet listed for resource_ref in the public x402 directory |
| payee_changed_since_previous | authorization | retry_after_authorization | POST /api/decide: payee, network or asset differs from previous_payment_intent |
| payee_not_bound_to_origin | authorization | retry_after_fix | POST /api/decide: the origin of payment_intent.resource_ref quotes a different payee (RAP §6.5, proposed) |
| payee_origin_binding_unavailable | uncertain | policy_dependent_backoff | POST /api/decide: the origin of payment_intent.resource_ref could not be checked (RAP §6.5, proposed) |
| payee_not_authorized_by_origin | authorization | retry_after_authorization | POST /api/decide: the controller of the resource_ref origin published a signed payout-address list for this network that does not include the payee (payee_authorization.status not_bound); raises allow to review |
| payee_change_not_authorized_by_origin | authorization | retry_after_authorization | POST /api/decide: the payee changed since previous_payment_intent and the origin's signed payout-address list excludes the new payee; decline |
| payee_is_token_contract | client_error | retry_after_fix | screening: payee is a token contract address, not a recipient |
| payer_screening_declined | regulatory | non_retryable | x402 paid endpoints: the paying wallet is on a sanctions or risk list, so OceanAlt does not settle the payment |
| idempotency_key_invalid | client_error | retry_after_fix | POST /api/pay: malformed Idempotency-Key (400) |
| idempotency_key_reused | client_error | retry_after_fix | POST /api/pay: Idempotency-Key reused with a different body (422) |
| idempotency_request_in_progress | uncertain | policy_dependent_backoff | POST /api/pay: original request with this Idempotency-Key still running (409) |
| key_scope_denied | authorization | retry_after_authorization | API key restricted to other scopes by its holder (403) |
| key_ip_denied | authorization | retry_after_authorization | API key restricted to an IP allowlist by its holder; this request came from elsewhere (403) |
3 · 可復現測試向量(對免費端點)
curl "https://oceanalt.com/api/risk?addr=0x8589427373D6D84E98730D7795D8f6f8731FDA16" # → verdict:"risky", reason_code:"sanctioned_or_high_risk_payee", signal_class:"regulatory", retry:"non_retryable"
curl "https://oceanalt.com/api/risk?addr=0x742d35Cc6634C0532925a3b844Bc454e4438f44e" # → verdict:"clear", reason_code:"clear", signal_class:"ok", retry:"not_applicable"

