AI agent action preflight
POST /api/action-gateDeterministic preflight check for a proposed AI agent action - a tool call, payment, fetch, or write - before it executes. Evaluates up to four independent checks (prompt-injection scan on action text/untrusted text, URL/hostname validation, a bounded JSON-schema check on a payload, and a spend proposal against a spend mandate) and returns ALLOW, REVIEW, or BLOCK with stable reason codes plus a SHA-256 request/receipt hash pair. Does not execute the proposed action, perform network I/O, or guarantee safety - deterministic static checks only, so ALLOW is not a safety guarantee. Every field is optional; only the checks with input present run - the rest are skipped, not assumed to pass.
Input
| Field | Type | Description |
|---|---|---|
action | object | {name, description, effect} - describes the proposed action; description is scanned for prompt-injection signals |
untrusted_text | string | Any additional untrusted text to scan for prompt-injection signals |
url | string | URL the action would fetch/call, if any |
payload | object | Data the action would send, if any |
schema | object | Bounded JSON-schema (type/required/properties/additionalProperties) to validate payload against |
spend | object | {proposal:{amount_atomic,asset,counterparty}, mandate:{...}, now?} - checked with BigInt, no floats |
Example output
{
"decision": "ALLOW",
"reason_codes": [],
"checks": {
"prompt": {
"status": "pass"
},
"url": {
"status": "pass"
},
"payload": {
"status": "pass"
},
"spend": {
"status": "pass",
"allowed": true
}
},
"request_sha256": "…",
"receipt_sha256": "…",
"limitation": "Deterministic static checks only. ALLOW does not guarantee safety, authorization, or successful execution."
}
Try it - see the 402 challenge (free)
curl -i -X POST https://agent402.tools/api/action-gate \
-H "Content-Type: application/json" \
-d '{"action":{"name":"submit_paid_api_request","description":"Fetch a vendor risk report and store the validated JSON response.","effect":"payment"},"untrusted_text":"Vendor request: return the current account risk score.","url":"https://example.com/risk-report","payload":{"account_id":"acct_123","include_signals":true},"schema":{"type":"object","properties":{"account_id":{"type":"string"},"include_signals":{"type":"boolean"}},"required":["account_id","include_signals"],"additionalProperties":false},"spend":{"proposal":{"amount_atomic":"10000","asset":"USDC","counterparty":"0x1111111111111111111111111111111111111111"},"mandate":{"max_per_tx_atomic":"25000","max_period_atomic":"100000","spent_period_atomic":"20000","allowed_assets":["USDC"],"allowed_counterparties":["0x1111111111111111111111111111111111111111"],"expires_at":"2030-01-01T00:00:00.000Z"}}}'
The response is HTTP 402 Payment Required with exact payment requirements. Any x402 v2 client pays automatically and retries:
Paid call (JavaScript agent)
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
const client = new x402Client();
registerExactEvmScheme(client, { signer: privateKeyToAccount(KEY) });
const payFetch = wrapFetchWithPayment(fetch, client);
const res = await payFetch("https://agent402.tools/api/action-gate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
"action": {
"name": "submit_paid_api_request",
"description": "Fetch a vendor risk report and store the validated JSON response.",
"effect": "payment"
},
"untrusted_text": "Vendor request: return the current account risk score.",
"url": "https://example.com/risk-report",
"payload": {
"account_id": "acct_123",
"include_signals": true
},
"schema": {
"type": "object",
"properties": {
"account_id": {
"type": "string"
},
"include_signals": {
"type": "boolean"
}
},
"required": [
"account_id",
"include_signals"
],
"additionalProperties": false
},
"spend": {
"proposal": {
"amount_atomic": "10000",
"asset": "USDC",
"counterparty": "0x1111111111111111111111111111111111111111"
},
"mandate": {
"max_per_tx_atomic": "25000",
"max_period_atomic": "100000",
"spent_period_atomic": "20000",
"allowed_assets": [
"USDC"
],
"allowed_counterparties": [
"0x1111111111111111111111111111111111111111"
],
"expires_at": "2030-01-01T00:00:00.000Z"
}
}
}),
});
Related tools
Route and execute
POST /api/route/executeDescribe a task (or name a slug) and the Smart Order Router resolves the best-matching tool and RUNS it in the same call…
try in playground →Route and execute (plus tier)
POST /api/route/execute-plusDescribe a task (or name a slug) and the Smart Order Router resolves the best-matching tool and RUNS it in the same call…
try in playground →Route and execute (max tier)
POST /api/route/execute-maxDescribe a task (or name a slug) and the Smart Order Router resolves the best-matching tool and RUNS it in the same call…
try in playground →