---
name: txguard
description: Deterministic Base transaction and x402 payment preflight for agents, paid per call.
---

# TxGuard

TxGuard tells an agent what a Base transaction actually does before it signs one. It decodes calldata against verified ABIs, resolves every known proxy pattern including the legacy slot Base USDC really uses, unwraps multicall wrappers recursively, classifies allowances against the token's own supply rather than a list of sentinel values, and runs the full x402 authorization check table against the quote a payment claims to satisfy. There is no model anywhere in it. When a four-byte selector matches more than one signature it returns unknown and hands back every candidate, because a confident decode of an ambiguous selector is how a preflight API becomes dangerous.

## When to use this

Use `POST https://txguard.schemasure.com/v1/tx/preflight` when you need: Explain and check a Base transaction or x402 payment authorization before signing it.

## How to pay

1. Send the request without payment. You receive HTTP 402 and a base64 `PAYMENT-REQUIRED` header.
2. Decode it, sign one of the `accepts` entries with your wallet locally.
3. Retry the identical request with the `PAYMENT-SIGNATURE` header.
4. A successful response carries a `PAYMENT-RESPONSE` receipt.

Cost: $0.01 in USDC on Base mainnet. Failed calls are free.
Your private key never leaves your process.

## Request

```json
{
  "unsigned_tx": {
    "from": "0x9F2C5E4A8db1C3a7E6B0d4f8C1E2a5b7D9C0e3F4",
    "to": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "value": "0",
    "data": "0xa9059cbb0000000000000000000000005d3e1a9b7c2f4e8a0b6d3c5f9e1a7b4d2c8f0a6e0000000000000000000000000000000000000000000000000000000000002710"
  },
  "expected_quote": {
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "10000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo": "0x1a2B3c4D5E6F7a8B9c0D1e2F3A4b5C6d7E8F9a0b",
    "maxTimeoutSeconds": 60,
    "extra": {
      "name": "USD Coin",
      "version": "2"
    }
  }
}
```

## Response

```json
{
  "ok": true,
  "verdict": "block",
  "confidence": 1,
  "risk_codes": [
    "RECIPIENT_MISMATCH",
    "RPC_UNAVAILABLE"
  ],
  "evidence": [
    {
      "code": "RECIPIENT_MISMATCH",
      "severity": "critical",
      "detail": "Pays 0x5D3e1a9b7c2f4E8A0b6d3c5F9E1A7b4D2C8f0a6E, but the quote names 0x1a2B3c4D5E6F7a8B9c0D1e2F3A4b5C6d7E8F9a0b. Signing this pays someone other than the party you are buying from.",
      "source": "quote-comparison",
      "data": {
        "field": "payTo",
        "expected": "0x1a2B3c4D5E6F7a8B9c0D1e2F3A4b5C6d7E8F9a0b",
        "actual": "0x5D3e1a9b7c2f4E8A0b6d3c5F9E1A7b4D2C8f0a6E"
      }
    },
    {
      "code": "RPC_UNAVAILABLE",
      "severity": "medium",
      "detail": "No Base RPC endpoint is configured, so chain-dependent fields are unknown rather than assumed. See result.unresolved.",
      "source": "rpc"
    }
  ],
  "result": {
    "input_shape": "unsigned_tx",
    "chain": "eip155:8453",
    "intent": {
      "kind": "erc20_transfer",
      "summary": "Transfer 10000 base units of token 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 to 0x5D3e1a9b7c2f4E8A0b6d3c5F9E1A7b4D2C8f0a6E.",
      "decode_source": "bundled-abi",
      "selector": "0xa9059cbb",
      "signature": "transfer(address,uint256)",
      "function_name": "transfer",
      "standard": "erc20",
      "target": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "value_wei": "0",
      "args": [
        {
          "name": "to",
          "type": "address",
          "value": "0x5D3e1a9b7c2f4E8A0b6d3c5F9E1A7b4D2C8f0a6E"
        },
        {
          "name": "amount",
          "type": "uint256",
          "value": "10000"
        }
      ],
      "calls": [],
      "depth": 0,
      "truncated": false
    },
    "expected_transfers": [
      {
        "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "asset_kind": "erc20",
        "from": "0x9f2C5E4a8DB1C3A7e6b0d4f8C1e2A5b7d9c0E3f4",
        "to": "0x5D3e1a9b7c2f4E8A0b6d3c5F9E1A7b4D2C8f0a6E",
        "amount": "10000",
        "token_id": null,
        "source": "decode"
      }
    ],
    "approvals": [],
    "permit_scope": null,
    "spender": {
      "address": null,
      "is_contract": null,
      "detail": "this transaction grants no allowance, so it has no spender"
    },
    "proxy": {
      "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "kind": "unknown",
      "implementation": null,
      "admin": null,
      "beacon": null,
      "upgradeable": null,
      "slots_probed": [],
      "detail": "no RPC endpoint is configured, so no slot could be read"
    },
    "authorization_checks": [],
    "quote_comparison": {
      "present": true,
      "matches": false,
      "fields": [
        {
          "field": "payTo",
          "expected": "0x1a2B3c4D5E6F7a8B9c0D1e2F3A4b5C6d7E8F9a0b",
          "actual": "0x5D3e1a9b7c2f4E8A0b6d3c5F9E1A7b4D2C8f0a6E",
          "matches": false
        },
        {
          "field": "amount",
          "expected": "10000",
          "actual": "10000",
          "matches": true
        },
        {
          "field": "asset",
          "expected": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "actual": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "matches": true
        },
        {
          "field": "chainId",
          "expected": "8453",
          "actual": null,
          "matches": null
        },
        {
          "field": "extra.name",
          "expected": "USD Coin",
          "actual": null,
          "matches": null
        },
        {
          "field": "extra.version",
          "expected": "2",
          "actual": null,
          "matches": null
        }
      ],
      "detail": "2 of 3 comparable fields match"
    },
    "simulation": {
      "requested": false,
      "status": "not_requested",
      "asset_changes": [],
      "gas_used": null,
      "block_number": null,
      "detail": "simulation was not requested; send simulate: true to run one"
    },
    "candidate_signatures": [],
    "denylist_hits": [],
    "unresolved": [
      "proxy status of 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 is unknown: no RPC endpoint is configured, so no slot could be read"
    ],
    "rpc": {
      "configured": false,
      "reachable": null,
      "endpoints": []
    }
  },
  "policy_version": "2026-08-03",
  "request_hash": "sha256:6d5c717eb5eede165dada2645ad0944430ff492739cf58d0c2dad2b812f0ddb4",
  "data_versions": {
    "denylist": "2026-08-03.1",
    "abi_packs": "2026-08-03.1",
    "signature_index": "2026-08-03.1",
    "policy": "2026-08-03",
    "chain": "eip155:8453"
  },
  "warnings": []
}
```

## Reading the verdict

- `resolved` / `pass` / `allow` — the service answered and the answer is usable.
- `warn` — usable, but `evidence` contains findings you should act on.
- `block` — the service is telling you not to proceed. Read `risk_codes`.
- `unknown` — the service could not determine the answer. **Do not treat this as safe.**
