Payments your agent makes on-chain. Nothing else.
The check answers one question: is this exactly the payment my agent means to make? It is built for that one kind of transaction, and says so rather than guessing at others.
Checked
- An agent paying: sending a token to one recipient
- As a transaction, or as a gasless signed payment (EIP-3009, used by x402)
- On Base, Ethereum and Polygon
- In USDC, USDT, DAI, WETH or the chain’s own coin (ETH, POL)
Not checked
- Swaps, trades and bridging
- Staking, lending and deposits into a protocol
- Buying or minting NFTs, contract deployments, governance votes
- Approvals or permits as the goal
- Other chains, other tokens, and card or off-chain payments
It never waves through what it was not built for. Ask about anything other than a payment and the request is refused, uncharged. Send a transaction that does more than the stated payment (a swap, a deposit, a mint) and it is blocked.
| Chain | chain_id | Tokens |
|---|---|---|
| Base | 8453 | ETH, USDC, DAI, WETH |
| Ethereum | 1 | ETH, USDC, USDT, DAI, WETH |
| Polygon | 137 | POL, USDC, USDT, DAI, WETH |
An agent cannot read calldata. We can.
A person paying a merchant looks at the wallet screen before approving. An agent paying on its own has no such moment: it trusts the transaction it was given. A swapped recipient, a look-alike token, an extra transfer tucked inside a batch, an unlimited approval, or a call that quietly hands the wallet to someone else all look like any other hex string.
The check gives the agent that moment back, as an API call. It compares what the transaction would actually do on the current chain with what the agent says it intends, and refuses anything that does not match.
Rule-based, not a model. Every check is a fixed comparison: the same transaction and intent always get the same verdict, and nothing the agent was shown can talk its way past it.
Every payment, against eight questions
The transaction is run against the latest block, and its real effects are compared with the stated intent. Payments routed through a router or a smart wallet still match: what counts is what leaves the sender and what reaches the recipient.
| Check | What it confirms | If it fails |
|---|---|---|
| Official token | The money leaving is the real USDC (or other listed token), not a look-alike contract with the same name | Block |
| Exact amount out | Exactly the stated amount leaves the sender, not a cent more | Block |
| Right recipient | Exactly the stated amount reaches the stated recipient | Block |
| Nothing else leaves | No other token, native coin or NFT leaves the sender | Block |
| No spending rights | The payment grants no one the right to spend the wallet’s tokens later. A limited approval warns; an unlimited one, an NFT operator or a Permit2 allowance blocks | Warn / block |
| It succeeds | The transaction does not revert | Block |
| No change of control | Nowhere in the transaction does control of anything change: no new Safe owner, module or guard, no ownership handover, no proxy upgrade, no module install, no role grant, no timelocked call queued, and no EIP-7702 delegation of the wallet | Block |
| Balances agree | Token balances measured before and after agree with what the transaction reports moving, which catches a token that moves money without saying so | Block |
Your own policy, optional. Add a maximum amount, a list of allowed tokens or a list of allowed recipients, and anything outside them is blocked too.
Gasless payments, checked field by field
Many agent payments, x402 among them, are a signed message rather than a transaction. Send the message instead and we decode it on our servers, without touching the chain:
- It must be a standard USDC-style transfer authorization (EIP-3009), for the official token on the requested chain.
- The amount, the recipient and the payer must be exactly the ones stated.
- It must be valid now: an expired one blocks, a post-dated one warns.
- Any permit, and any message for Permit2, blocks: a payment never needs to grant spending rights.
One request before every signature
Use the same API key your agent already uses for audits (create one in the workspace under Create API key). Send the transaction exactly as it will be signed:
POST https://check.grisoco.com/v1/check
Authorization: Bearer grisoco_sk_…
{
"chain_id": 8453,
"from": "0xYourAgentWallet…",
"intent": { "type": "payment", "token": "USDC", "amount": "5.00", "recipient": "0xMerchant…" },
"tx": { "to": "0x…", "data": "0x…", "value": "0x0" },
"policy": { "max_amount": "50", "allowed_recipients": ["0xMerchant…"] }
}
The answer is one verdict to act on, with everything behind it: every check with its
result and a plain-English reason, what would leave the wallet, and the block it was checked
at. Any failed check means block; otherwise any warning means
warn; otherwise allow.
{
"check_id": "chk_…",
"verdict": "block",
"summary": "The recipient 0xMerchant… would receive nothing, not 5 USDC.",
"checks": [
{ "id": "I1", "status": "pass", "message": "The USDC leaving is the official USDC." },
{ "id": "I3", "status": "fail", "message": "The recipient 0xMerchant… would receive nothing, not 5 USDC." },
…
],
"sender_changes": [ { "symbol": "USDC", "amount": "-5000000", "display": "-5 USDC", … } ],
"block": 21894411,
"charged_cents": 3
}
Send "signature": { "typed_data": … } in place of "tx" for a message to sign.
Read by machines, too
If you are an agent, or building one, everything here is available in a form you can load:
- OpenAPI 3.1 spec: grisoco.com/transaction-check/openapi.json
- Plain-text summary: grisoco.com/llms.txt
- Endpoint:
POST https://check.grisoco.com/v1/check, bearer API key
Two rules, or the check means nothing.
- The intent comes from your user’s task, never from the payment request. Take the token, amount and recipient from what your user asked for, not from the checkout page or merchant. If the same party supplies the transaction and the intent, the check only confirms they match each other.
- Fail closed. Sign only on
allow. No answer, an error, a timeout or a 400 all mean do not sign. Retry a 503 afterRetry-After, back off on a 429, and allow about 10 seconds per call: the first check after a quiet spell starts the service.
How to act on the answer:
| Verdict | What your agent should do |
|---|---|
| allow | Sign. No risks were detected at the block named in the answer |
| warn | Do not sign on its own. Something needs a decision first, such as a limited approval or a payment authorization that is not valid yet |
| block | Do not sign. The checks list says which check failed and why |
0.03 USDC per verdict
- One flat price, allow or block alike, paid from the same prepaid balance as your audits.
- Never charged: a malformed request, a check refused by your key’s rate or spend limit, and any check that fails on our side.
- Checks count toward the daily spend cap you set on each key, and each key can make up to 60 checks a minute.
See pricing.
Checked, then forgotten
- The transaction, the message, the intent and your policy are held in memory only while the verdict is produced. They are never stored and never logged.
- No AI provider ever sees them.
- We keep a short usage record for billing (time, chain, verdict, which checks failed), with no addresses and no transaction data, for 90 days.
The details are in section 4 of our privacy policy.
Give your agent a second look at every payment
One API key, a funded balance, and one call before each signature.