Cross-merchant spending control for AI agents. Pick your role and copy the calls.
← Back to overviewhttps://verifier.goodmeta.co. Every call authenticates with your API key as a
bearer token: Authorization: Bearer gm_test_YOUR_KEY. Keys are issued by Good Meta during onboarding.
All money is in integer cents (e.g. 2500 = $25.00). IDs starting with pe_ are budgets;
ver_ are holds/reservations.
You fund an agent and set the rules: how much it can spend, where, on what, and for how long. You create a budget envelope once and hand its id to your agent.
Set the total, a per-transaction cap, the merchants it may spend at, and an expiry. With no
allowedMerchants list, only you (the key holder that created it) can spend it.
curl -X POST https://verifier.goodmeta.co/v1/budgets -H "Authorization: Bearer gm_test_YOUR_KEY" -H "Content-Type: application/json" -d '{
"agentId": "shopping-agent-01",
"budgetTotal": 50000,
"currency": "usd",
"validUntil": "2026-12-31T23:59:59Z",
"constraints": {
"maxAmount": "10000",
"allowedMerchants": ["merchant_abc", "merchant_xyz"],
"categories": ["software", "saas"]
}
}'
{
"id": "pe_3f9a2b8c1d0e4f567890",
"type": "budget",
"agentId": "shopping-agent-01",
"budgetTotal": "50000",
"budgetSpent": "0",
"remainingBudget": "50000",
"currency": "usd",
"validUntil": "2026-12-31T23:59:59Z"
}
software/saas. Anything outside the envelope is denied at verify time.Hand pe_3f9a2b8c1d0e4f567890 to the agent (env var, config, prompt). The agent never sees your
API key — it just references the budget id when it shops.
See remaining budget and the full cross-merchant transaction history. Only the budget's creator can read it.
curl https://verifier.goodmeta.co/v1/mandates/pe_3f9a2b8c1d0e4f567890 -H "Authorization: Bearer gm_test_YOUR_KEY"
An agent wants to pay you. Before you fulfill, check it's authorized and within budget — that places a hold. After the agent pays, settle the hold. If anything fails, release it.
One call: validates the budget, enforces every constraint, and reserves the amount so a parallel
purchase can't overspend. idempotency_key makes retries safe (your order id works well).
curl -X POST https://verifier.goodmeta.co/v1/check -H "Authorization: Bearer gm_test_MERCHANT_KEY" -H "Content-Type: application/json" -d '{
"budget_id": "pe_3f9a2b8c1d0e4f567890",
"amount_cents": 2500,
"vendor": "merchant_abc",
"idempotency_key": "order-1001"
}'
{ "approved": true, "hold_id": "ver_a1b2c3d4e5f6g7h8i9j0", "remaining_cents": 47500 }
{ "approved": false, "reason": "BUDGET_EXCEEDED" }
AMOUNT_EXCEEDED,
MERCHANT_NOT_ALLOWED, CATEGORY_BLOCKED, EXPIRED,
TX_LIMIT_REACHED, MANDATE_REVOKED.The verifier authorizes — it doesn't move money. Charge with whatever you already use (Stripe, x402, bank, card). The hold guarantees the budget is reserved while you do.
Settle confirms the spend and debits the budget permanently. Release returns the unspent hold if the payment didn't go through.
curl -X POST https://verifier.goodmeta.co/v1/settle -H "Authorization: Bearer gm_test_MERCHANT_KEY" -H "Content-Type: application/json" -d '{ "hold_id": "ver_a1b2c3d4e5f6g7h8i9j0", "success": true }'
curl -X POST https://verifier.goodmeta.co/v1/release -H "Authorization: Bearer gm_test_MERCHANT_KEY" -H "Content-Type: application/json" -d '{ "hold_id": "ver_a1b2c3d4e5f6g7h8i9j0" }'
Reverse a committed charge, fully or partially. Restores the budget. The idempotency_key
is required so a retry never double-refunds.
curl -X POST https://verifier.goodmeta.co/v1/refund -H "Authorization: Bearer gm_test_MERCHANT_KEY" -H "Content-Type: application/json" -d '{
"hold_id": "ver_a1b2c3d4e5f6g7h8i9j0",
"amount_cents": 2500,
"idempotency_key": "refund-1001"
}'
You're building the agent that spends. Wrap every payment in the same loop: check → pay → settle. The verifier is the guardrail that keeps your agent inside the budget its owner set.
The budget owner creates an envelope and gives your agent its id (e.g. pe_3f9a2b8c1d0e4f567890).
Store it; reference it on every purchase.
Same /v1/check the merchant uses. If approved, you hold the budget and get a
hold_id. If denied, stop — don't pay.
// pseudo-code around any purchase your agent makes
const res = await fetch("https://verifier.goodmeta.co/v1/check", {
method: "POST",
headers: { "Authorization": "Bearer gm_test_YOUR_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
budget_id: budgetId,
amount_cents: price,
vendor: merchantId,
idempotency_key: orderId,
}),
}).then(r => r.json());
if (!res.approved) throw new Error("over budget: " + res.reason);
const holdId = res.hold_id;
Run your payment, then confirm the hold. On any failure, release it so the budget isn't consumed.
try {
await payTheMerchant(price); // your rail
await fetch("https://verifier.goodmeta.co/v1/settle", {
method: "POST",
headers: { "Authorization": "Bearer gm_test_YOUR_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ hold_id: holdId, success: true }),
});
} catch (e) {
await fetch("https://verifier.goodmeta.co/v1/release", {
method: "POST",
headers: { "Authorization": "Bearer gm_test_YOUR_KEY", "Content-Type": "application/json" },
body: JSON.stringify({ hold_id: holdId }),
});
}
npm i @goodmeta/agent-verifier — see
github.com/goodmeta/agent-verifier
for the typed SDK over these same endpoints.Give an LLM (Claude, Cursor, your own agent) a spending guardrail it can drive in natural language. The verifier exposes the full budget lifecycle as MCP tools over a streamable HTTP endpoint.
Point your MCP client at https://verifier.goodmeta.co/mcp and pass your key as a bearer header.
{
"mcpServers": {
"agent-verifier": {
"url": "https://verifier.goodmeta.co/mcp",
"headers": { "Authorization": "Bearer gm_test_YOUR_KEY" }
}
}
}
https://verifier.goodmeta.co/mcp?VERIFIER_API_KEY=gm_test_YOUR_KEY. Prefer the header form — query strings can
end up in proxy logs.create_budget | Set a spending limit. Args: amount_dollars, currency, valid_hours. |
check_budget | Check a purchase is within budget & place a hold. Args: budget_id, amount_cents, vendor. |
settle | Confirm or cancel a hold after paying. Args: hold_id, success. |
release | Return a pre-commit hold to the budget. Args: hold_id. |
refund | Reverse a settled payment, full or partial. Args: hold_id, amount_cents, idempotency_key. |
get_budget | Remaining budget + recent history. Args: budget_id. |
query_reservation | State of a single hold. Args: hold_id. |
The model strings the tools together on its own:
You: "Set a $50 budget for today, then buy the $12 API plan from Acme."
Agent: create_budget(amount_dollars=50, valid_hours=24)
-> Budget pe_… created, $50.00
check_budget(budget_id=pe_…, amount_cents=1200, vendor="acme")
-> Approved. Hold ver_…, remaining $38.00
(pays Acme)
settle(hold_id=ver_…, success=true)
-> Hold confirmed.
check_budget returns
Denied with a reason and no hold is placed — the budget is the hard boundary, not the prompt.