Skip to content

Reason codes

On this page

Rules run in order, and each one that fires returns a code and a plain sentence. The resource rule runs when the policy lists what the agent may buy; the wallet blocklist rule runs only when you enable it. This page groups the codes by what they do: deny, send to review, or inform. The response lists them in the order they ran. The sentences here are real, with the addresses and amounts of the example that produced them. Yours carry your own.

How a decision adds up

Each rule returns one of four results, and the strongest result wins.

From the response
{
  "status": "denied",
  "rules": [
    { "id": "payee_matches_402", "result": "deny",
      "sentence": "The payment is addressed to 0x2222…2222 but the seller's own 402 asked for 0x1111…1111." },
    { "id": "payee_allowlisted", "result": "info",
      "sentence": "The payee 0x2222…2222 is not in your allowlist." },
    { "id": "injection_suspected", "result": "deny",
      "sentence": "The content check flagged instructions in the page, so this payment was blocked." }
  ]
}
// the rules that passed are trimmed here. A real row carries every rule that ran, in order.
  • deny refuses the payment. One is enough to make the decision denied.
  • review sends it to a person. With no deny, one review makes the decision review.
  • info explains something without changing the outcome.
  • pass is silent and carries no sentence. Every rule that runs passing makes the decision allowed.

A denied payment is never signed or forwarded, so a decision with several deny codes is one payment that was blocked for several reasons, not several payments.

Codes that deny

  • network_allowed. The network Base (eip155:8453) is not allowed. The policy allows Base Sepolia (eip155:84532).
  • asset_allowed. The asset 0x8335…2913 on Base (eip155:8453) is not allowed by the policy. A contract call that moves the chain's own currency gets a different sentence: native currency transfers are not allowed, only the tokens the policy lists.
  • payee_denylisted. The payee 0x0000…0bad is on your denylist.
  • wallet_blocklist. Optional screening found a restriction for the recipient, or could not complete the check. The sentence distinguishes a match from unavailable screening and gives the next step. This rule is off by default. An explicit payee allowlist entry on the same network makes this rule inform instead, without bypassing other rules or an issuer's on-chain freeze. Like the manual denylist, this rule's denial is recorded without blocking in observe mode.
  • payee_matches_402. The payment is addressed to 0x2222…2222 but the seller's own 402 asked for 0x1111…1111.
  • amount_per_tx. The amount 2.50 USDC is over the per-transaction limit of 0.10 USDC.
  • amount_daily_cap. This payment of 2.50 USDC would bring today's total to 2.65 USDC, over the daily cap of 1.00 USDC.
  • injection_suspected. The content check flagged instructions in the page, so this payment was blocked. A completed primary content block returns this denial even when the seller and amount pass the payment rules.
  • contract_call_denied. The call is approve(address,uint256) with an unlimited amount for 0x4444…4444. The sentence names whatever the call actually does: an approval for an unlimited amount, an approval for every token in a collection, a transfer of contract ownership, a denylisted address or selector, or calldata that does not decode. An approval for a set amount is judged like a payment to its spender, so the payee and amount codes above cover it.

Codes that send it to review

  • resource_allowed. The agent may buy from https://merchant.example/dataset and 1 more. This payment is for https://merchant.example/addon. The list of what the agent may buy is in the policy. An empty list allows any resource, and then this row is left out of the response.
  • amount_hold_over. The amount 0.55 USDC is over your hold threshold of 0.50 USDC, so it waits for a person. The threshold is off at 0, and it sits under the per-payment limit, which denies rather than holds.
  • velocity_per_hour. This agent has had 20 payments allowed or waiting in the last hour. The policy allows 20 per hour.
  • injection_suspected. The content check did not finish, so this payment needs your review before it can proceed. Older review-only content flags also keep their original review result.
  • first_time_payee. First payment to 0x3333…3333. Auto-allow for first payments is off in your policy. With auto-allow on, the sentence names the amount and the threshold instead, and a first payment under the threshold only informs: First payment to 0x3333…3333. The amount 0.005 USDC is under the auto-allow threshold of 0.01 USDC. Under the threshold it still waits when the content check could not run: First payment to 0x3333…3333. The content check was unavailable, so this first payment waits for a person. A contract call that moves no token the guard can read gets its own sentence: First transaction to the contract 0x4444…4444, which is not in your allowlist.

Codes that only inform

  • payee_allowlisted. The payee 0x3333…3333 is not in your allowlist. On its own this never blocks or holds a payment, it explains why first_time_payee spoke up.
  • injection_suspected. An administrator disabled content enforcement, so the payment rules decide without it. The original content result stays in the decision record.

Which of these you can hit depends on your policy. The fields and their defaults are on the policy page.