Hosted Buyer Path

Run the live Wallet Action Preflight API on Base.

The shortest live buyer proof is the Wallet Action Preflight API at https://x402.bankr.bot/0xc04d0d464752a58b046105b45089d579eaf54036/bankr-preflight. It charges 0.002 USDC on Base and returns one pre-execution decision contract for Bankr transfer and approval actions after the native x402 payment step.

Buyer Path

Run the hosted Wallet Action Preflight API

Exact live URL

Use this hosted Bankr route for the cleanest buyer-safe entry point: Wallet Action Preflight API. It is a POST-only surface, so browser GET checks will not prove the route.

Name recommendation

Recommend Wallet Action Preflight API, not Approval Roast API. The live contract covers both transfers and approvals, and buyers can infer the exact job from the name without reading roadmap context.

Need the broader TXRISK route catalog?

Keep reading below for the direct TXRISK routes on txrisk.xyz, including POST /v1/action/authorize, discovery metadata, and MCP guidance.

Need the partner-review bundle?

Open /partner-evaluator.html for the listing-friendly packet that still bundles review order, discovery metadata, MCP metadata, and the broader TXRISK proof links.

  1. POST one Bankr transfer or approval action to the hosted URL with content-type: application/json.
  2. Expect a Bankr-managed 402 payment_required on the first unpaid request.
  3. Complete the x402 payment step on Base for 0.002 USDC.
  4. Retry the same request with the Bankr payment artifact.
  5. Confirm the final body includes mode=bankr_preflight, a normalized action, TXRISK risk output, and a Bankr execution decision.
export BANKR_PREFLIGHT_URL="https://x402.bankr.bot/0xc04d0d464752a58b046105b45089d579eaf54036/bankr-preflight"
payload='{
  "action": {
    "kind": "approval",
    "chain": "base",
    "actor": "0x1111111111111111111111111111111111111111",
    "tokenAddress": "0x3333333333333333333333333333333333333333",
    "spender": "0x2222222222222222222222222222222222222222",
    "amountUsd": 299,
    "allowanceUsd": 299,
    "approvalScope": "exact"
  },
  "requestContext": {
    "intentId": "intent_subscription_purchase",
    "merchantAccountId": "merchant_subscription"
  }
}'

curl -i -X POST "$BANKR_PREFLIGHT_URL" \
  -H "content-type: application/json" \
  -d "$payload" | tr -d '\r' | awk -F': ' '/^payment-required: / {print $2}'
          
# After the Bankr x402 payment step succeeds, retry the same POST and expect:
{
  "mode": "bankr_preflight",
  "normalizedAction": {
    "version": "bankr-preflight-v1",
    "kind": "approval",
    "chain": "base"
  },
  "txrisk": {
    "riskScore": 58,
    "riskBand": "medium"
  },
  "bankrDecision": {
    "decision": "warn"
  },
  "executionOutcome": "require_explicit_confirmation"
}

Direct TXRISK Surface

Broader routes still live on txrisk.xyz

The hosted Wallet Action Preflight API above is the shortest buyer path. The broader TXRISK contract remains on txrisk.xyz for direct HTTP routes, discovery metadata, and the bounded remote MCP wrapper.

Policy Templates

Four buyer-safe actions with deterministic outcomes

Treasury transfer

Use this to show a hard stop before a risky outbound treasury send is submitted.

  • Action: transfer
  • Expected decision: deny
  • Operator step: deny_and_rewrite_action

Vendor payout

Use this to show a clean pass on a low-risk vendor payment.

  • Action: transfer
  • Expected decision: allow
  • Operator step: proceed_to_submit

Subscription purchase

Use this to show a policy review gate on an approval-backed SaaS spend.

  • Action: approval
  • Expected decision: review
  • Operator step: require_operator_review

Browser checkout

Use this to show a bounded browser-agent approval that can pass automatically.

  • Action: approval
  • Expected decision: allow
  • Operator step: proceed_to_submit

API Catalog

Paid endpoints

POST /v1/wallet/risk-snapshot

  • Inputs: walletAddress, chainId, optional exposure/signal window.
  • Output: riskScore, riskBand, watch flags, billing block.
  • Usage price: 0.0020 USDC per admitted call.

POST /v1/webhook/verify

  • Inputs: tenant id, provider, endpoint id, event id, timestamp, raw body string, signature.
  • Output: verified/replay/signature metadata plus billing state.
  • Usage price: 0.0020 USDC per admitted call.

POST /v1/lead/qualify

  • Inputs: lead profile and ICP arrays for industries/pain points.
  • Output: fit score, tier, disqualify reasons, outreach angles, billing block.
  • Usage price: 0.0020 USDC per admitted call.

POST /v1/action/authorize

  • Inputs: transfer or approval action plus optional request context.
  • Output: allow/review/deny decision, policy reasons, operator next step, billing block.
  • Usage price: 0.0020 USDC per admitted call.

POST /v1/account/recovery-authorize

  • Inputs: sensitive recovery action, support channel, account age, optional value/login/signal context.
  • Output: allow/review/deny decision, risk score, challenge type, operator queue, billing block.
  • Usage price: 0.0020 USDC per admitted call.

JSON Examples

Request + response samples

# POST /v1/wallet/risk-snapshot
# Use it when: you need a fast risk check before approving a wallet-linked action.
{
  "walletAddress": "PAYEE_ADDRESS",
  "chainId": 8453,
  "exposureUsd": 15000.25,
  "signalWindowHours": 24
}

# response
{
  "walletAddress": "PAYEE_ADDRESS",
  "chainId": 8453,
  "riskScore": 42,
  "riskBand": "medium",
  "topDrivers": [{"code": "volume_spike", "impact": 0.27}],
  "watchFlags": ["new_wallet"],
  "traceId": "risk_123456789abc",
  "billing": {"charged_usdc": "0.0020", "remaining_balance_usdc": "9.9980"}
}
# POST /v1/webhook/verify
# Use it when: you need TXRISK to resolve the signing secret server-side and block spoofed or replayed events.
{
  "tenantId": "tenant_demo",
  "provider": "stripe",
  "endpointId": "payments-primary",
  "eventId": "evt_123",
  "timestamp": "2026-03-25T00:00:00Z",
  "body": "{\"event\":\"invoice.paid\",\"id\":\"evt_123\"}",
  "signature": "sha256=<provider signature>"
}

# response
{
  "tenantId": "tenant_demo",
  "provider": "stripe",
  "endpointId": "payments-primary",
  "eventId": "evt_123",
  "verified": true,
  "replayDetected": false,
  "signatureValid": true,
  "signatureScheme": "stripe-hmac-sha256",
  "policyAction": "allow",
  "verificationId": "whv_123456789abc",
  "billing": {"charged_usdc": "0.0020", "remaining_balance_usdc": "9.9960"}
}
# POST /v1/lead/qualify
# Use it when: you want to rank inbound leads and prioritize high-fit outreach quickly.
{
  "lead": {
    "company": "Acme Treasury",
    "domain": "acmetreasury.com",
    "industry": "fintech",
    "painPoints": ["manual_risk_reviews", "chargebacks"]
  },
  "icp": {
    "industries": ["fintech", "defi"],
    "mustHavePainPoints": ["manual_risk_reviews"]
  }
}

# response
{
  "company": "Acme Treasury",
  "fitScore": 81,
  "tier": "a",
  "matchedSignals": {"industryMatch": true, "painPointMatches": 1, "painPointTotal": 1},
  "disqualifyReasons": [],
  "outreachAngles": ["manual review automation", "chargeback prevention"],
  "qualificationId": "ldq_123456789abc",
  "billing": {"charged_usdc": "0.0020", "remaining_balance_usdc": "9.9940"}
}
# POST /v1/action/authorize
# Use it when: you need a paid policy gate before a treasury send, vendor payout, subscription purchase, or browser checkout executes.
{
  "action": {
    "kind": "approval",
    "chain": "base",
    "actor": "0x1111111111111111111111111111111111111111",
    "tokenAddress": "0x3333333333333333333333333333333333333333",
    "spender": "0x2222222222222222222222222222222222222222",
    "amountUsd": 299,
    "allowanceUsd": 299,
    "approvalScope": "exact"
  },
  "requestContext": {
    "intentId": "intent_subscription_purchase",
    "merchantAccountId": "merchant_subscription"
  }
}

# response
{
  "mode": "action_authorize",
  "authorizationId": "auth_123456789abc",
  "decision": "review",
  "policy": {"profile": "operator_guard_v1"},
  "operator": {"step": "require_operator_review"},
  "billing": {"charged_usdc": "0.0020", "remaining_balance_usdc": "0.0000"}
}
# POST /v1/account/recovery-authorize
# Use it when: support needs a paid allow/review/deny gate before resetting credentials or changing a payout destination.
{
  "recovery": {
    "tenantId": "merchant_demo",
    "accountId": "acct_4477",
    "action": "payout_destination_change",
    "channel": "support_chat",
    "accountAgeDays": 18,
    "sessionAgeMinutes": 4,
    "requestedValueUsd": 5400,
    "failedLoginCount": 3,
    "signals": ["new_device", "geo_velocity", "high_value_destination_change"]
  },
  "policyContext": {
    "queue": "support_tier2",
    "operatorId": "agent_ava"
  }
}

# response
{
  "mode": "account_recovery_authorize",
  "recoveryAuthorizationId": "rec_123456789abc",
  "decision": "deny",
  "riskScore": 77,
  "riskBand": "high",
  "policy": {"challenge": "hard_block_and_lock"},
  "operator": {"step": "deny_request_and_lock_account"},
  "billing": {"charged_usdc": "0.0020", "remaining_balance_usdc": "0.0000"}
}

More Examples

Webhook, lead, authorization, and recovery curl

timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
body='{"event":"invoice.paid","id":"evt_123"}'
tenant_id='tenant_demo'
endpoint_id='payments-primary'
sig='sha256=<provider signature>'

curl -sS -X POST "$API_BASE_URL/v1/webhook/verify" \
  -H "content-type: application/json" \
  -H "x-api-key: $X_API_KEY" \
  -d "{\"tenantId\":\"$tenant_id\",\"provider\":\"stripe\",\"endpointId\":\"$endpoint_id\",\"eventId\":\"evt_123\",\"timestamp\":\"$timestamp\",\"body\":$body,\"signature\":\"$sig\"}" | jq
curl -sS -X POST "$API_BASE_URL/v1/lead/qualify" \
  -H "content-type: application/json" \
  -H "x-api-key: $X_API_KEY" \
  -d '{
    "lead": {
      "company": "Acme Treasury",
      "domain": "acmetreasury.com",
      "industry": "fintech",
      "painPoints": ["manual_risk_reviews", "chargebacks"]
    },
    "icp": {
      "industries": ["fintech", "defi"],
      "mustHavePainPoints": ["manual_risk_reviews"]
    }
  }' | jq
payload='{
  "action": {
    "kind": "approval",
    "chain": "base",
    "actor": "0x1111111111111111111111111111111111111111",
    "tokenAddress": "0x3333333333333333333333333333333333333333",
    "spender": "0x2222222222222222222222222222222222222222",
    "amountUsd": 2500,
    "allowanceUsd": 25000,
    "approvalScope": "unlimited"
  },
  "requestContext": {
    "intentId": "intent_x402_recovery"
  }
}'

payment_required=$(curl -isS -X POST "$API_BASE_URL/v1/action/authorize" \
  -H "content-type: application/json" \
  -H "x-chain: $X_CHAIN" \
  -d "$payload" | tr -d '\r' | awk -F': ' '/^payment-required: / {print $2}')

quote_id=$(printf '%s' "$payment_required" | base64 --decode | jq -r '.accepts[0].extra.txrisk.paymentQuote.quoteId')
verify_settlement_url=$(printf '%s' "$payment_required" | base64 --decode | jq -r '.accepts[0].extra.txrisk.paymentQuote.verifySettlementUrl')
payment_signature=$(curl -sS -X POST "$verify_settlement_url" \
  -H "content-type: application/json" \
  -d "{\"quoteId\":\"$quote_id\",\"chain\":\"$X_CHAIN\",\"txHash\":\"$PAYMENT_TX_HASH\"}" | jq -r '.x402.payment_signature')

curl -sS -X POST "$API_BASE_URL/v1/action/authorize" \
  -H "content-type: application/json" \
  -H "x-chain: $X_CHAIN" \
  -H "payment-signature: $payment_signature" \
  -d "$payload" | jq
payload='{
  "recovery": {
    "tenantId": "merchant_demo",
    "accountId": "acct_4477",
    "action": "payout_destination_change",
    "channel": "support_chat",
    "accountAgeDays": 18,
    "sessionAgeMinutes": 4,
    "requestedValueUsd": 5400,
    "failedLoginCount": 3,
    "signals": ["new_device", "geo_velocity", "high_value_destination_change"]
  },
  "policyContext": {
    "queue": "support_tier2",
    "operatorId": "agent_ava"
  }
}'

payment_required=$(curl -isS -X POST "$API_BASE_URL/v1/account/recovery-authorize" \
  -H "content-type: application/json" \
  -H "x-chain: $X_CHAIN" \
  -d "$payload" | tr -d '\r' | awk -F': ' '/^payment-required: / {print $2}')

quote_id=$(printf '%s' "$payment_required" | base64 --decode | jq -r '.accepts[0].extra.txrisk.paymentQuote.quoteId')
verify_settlement_url=$(printf '%s' "$payment_required" | base64 --decode | jq -r '.accepts[0].extra.txrisk.paymentQuote.verifySettlementUrl')
payment_signature=$(curl -sS -X POST "$verify_settlement_url" \
  -H "content-type: application/json" \
  -d "{\"quoteId\":\"$quote_id\",\"chain\":\"$X_CHAIN\",\"txHash\":\"$PAYMENT_TX_HASH\"}" | jq -r '.x402.payment_signature')

curl -sS -X POST "$API_BASE_URL/v1/account/recovery-authorize" \
  -H "content-type: application/json" \
  -H "x-chain: $X_CHAIN" \
  -H "payment-signature: $payment_signature" \
  -d "$payload" | jq

Auth + Billing

Headers, payment behavior, and recovery

Remote MCP

Use TXRISK from Claude/Codex-style connectors

curl -sS "$API_BASE_URL/.well-known/mcp/server.json" | jq
curl -sS -X POST "$API_BASE_URL/mcp" \
  -H "content-type: application/json" \
  -H "x-api-key: $TXRISK_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "capabilities": {},
      "clientInfo": { "name": "txrisk-docs-example", "version": "1.0.0" }
    }
  }' | jq
curl -sS -X POST "$API_BASE_URL/mcp" \
  -H "content-type: application/json" \
  -H "x-api-key: $TXRISK_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "risk_snapshot",
      "arguments": {
        "walletAddress": "0xabc0000000000000000000000000000000000000",
        "chainId": 8453,
        "exposureUsd": 12.5,
        "signalWindowHours": 24
      }
    }
  }' | jq

Error Guide

Auth, payment, and retry semantics

Status Error Code Meaning Client Action
400 validation_error or invalid_json Request body or field schema is invalid. Fix payload. Do not retry unchanged request.
402 payment_required Public route requires a verified settlement receipt. Decode PAYMENT-REQUIRED, verify the quoted settlement, then retry with the returned single-use PAYMENT-SIGNATURE.
401 / 403 unauthorized / forbidden Internal fallback/test-harness route is missing or has an invalid x-api-key. Attach or rotate the internal key, then retry.
405 method_not_allowed Endpoint requires POST. Switch method to POST. No blind retries.
404 not_found Unknown route. Correct path before retrying.