Decision object
Schema + three examples. This is the product.
Request
| Field | Type | Notes |
|---|---|---|
amount | number | Required. USD (the only currency today). |
merchant | string | Required. |
category | string | Required, e.g. AI & Compute. |
rail | stripe | ramp | crypto | Default stripe. |
reasoning | string ≤4000 | Why the agent wants to buy. Stored in the audit log. |
prompt_chain | [{role, content}] | Optional conversation context. |
webhook_url | https URL | Optional. Receives the human decision. |
idempotency_key | string ≤200 | Optional. Same key + same body replays the original decision; changed body → 409. |
recipient_address | string | Required for crypto. |
mode | authorize | report | report = log-only, a payment already made. |
The agent is identified by its API key, not a body field. currency is fixed to USD and idempotency_key (optional) makes retries safe — see Idempotency.
Response
| status | HTTP | Meaning |
|---|---|---|
approved | 201 | Within all rules. payment holds the card / tx if a rail is configured. |
flagged | 202 | Needs a human. Poll poll_url or wait for webhook. |
blocked | 403 | Do not buy. error_code POLICY_BLOCKED. |
approved
{
"transaction_id": "7f3c…",
"status": "approved",
"decision": "approved",
"reason": "Within all agent limits and attached policies — auto-approved.",
"evaluations": [
{ "policyName": "Agent limits", "rule": "Per-transaction limit", "outcome": "pass", "detail": "$45.00 ≤ $500.00" },
{ "policyName": "Agent limits", "rule": "monthly spend cap", "outcome": "pass", "detail": "$45 of $455 remaining" }
],
"payment": { "status": "issued", "credential": { "type": "card", "last4": "4242", "…": "…" } },
"verification": { "status": "awaiting_receipt", "receipt_url": "…/receipt" },
"poll_url": "https://railguardsecurity.com/api/public/transactions/7f3c…",
"timing": { "decision_ms": 38, "rules_ms": 1 }
}flagged
{
"transaction_id": "a91e…",
"status": "flagged",
"decision": "pending",
"reason": "$250.00 exceeds auto-approve threshold $100.00 — human approval required.",
"instruction": "Pause: waiting for human approval. Poll poll_url or wait for your webhook.",
"evaluations": [ { "rule": "Human approval threshold", "outcome": "review", "…": "…" } ],
"payment": null,
"poll_url": "…/api/public/transactions/a91e…"
}blocked
{
"transaction_id": "c04b…",
"status": "blocked",
"decision": "blocked",
"error_code": "POLICY_BLOCKED",
"reason": "Merchant \"CasinoX\" is on the blocklist.",
"instruction": "Do not complete this purchase. Stop or choose an alternative within policy.",
"evaluations": [ { "rule": "Merchant blocklist", "outcome": "block", "…": "…" } ]
}Reason codes
Top-level error_code: POLICY_BLOCKED (engine) or HUMAN_REJECTED (approver said no). Per-rule detail is in evaluations[].rule:
- Agent must be active · Per-transaction limit · daily/weekly/monthly spend cap · Policy spend cap
- Allowed merchant categories · Merchant blocklist · Merchant allowlist · Time-of-day restriction
- Human approval threshold (outcome
review)
Strictest wins
Every rule from the agent and every attached policy is evaluated. Then:
| Any block? | Any review? | Result |
|---|---|---|
| yes | — | blocked |
| no | yes | flagged |
| no | no | approved |
Example: $500/transaction cap + $2,000/week cap with $1,800 already spent. A $300 request passes the first, fails the second (only $200 left) → blocked, reason names the weekly cap.