Every time your agent attempts a payment, Mandate’s policy engine runs automatically before any proof is issued. The engine evaluates the request against 9 checks in sequence. The first check to fail immediately halts evaluation and returns a denial with a specific reason code. Only a request that passes all 9 checks receives anDocumentation Index
Fetch the complete documentation index at: https://docs.usemandate.io/llms.txt
Use this file to discover all available pages before exploring further.
"approved" decision. You never need to call the policy engine directly — the Mandate SDK handles this for you — but understanding the check sequence helps you configure mandates correctly and debug denials quickly.
How to trigger an evaluation
"denied", the same structure is returned with a non-null reason_code and reason_detail. The HTTP status code is 200 for approved and 402 for denied.
The 9 checks
Check 1 — Agent exists
Check 1 — Agent exists
Mandate looks up the agent by
agent_id. If no agent record is found, evaluation stops immediately.Failure reason code: agent_revokedWhat to do: Confirm the agent_id is correct and belongs to your account. Agents are environment-scoped — a sandbox agent ID cannot be used with a production key.Check 2 — Agent status is active
Check 2 — Agent status is active
The agent record must have
status: "active". A revoked agent fails this check.Failure reason code: agent_revokedWhat to do: Revocation is permanent. Create a new agent and update your mandates to reference the new ID. See Agents.Check 3 — Mandate exists and belongs to the agent
Check 3 — Mandate exists and belongs to the agent
Mandate looks up the mandate by
mandate_id and confirms that its agent_id matches the agent in the request. A mandate belonging to a different agent will fail this check.Failure reason code: mandate_expiredWhat to do: Verify that mandate_id is correct and was created with the same agent_id you are passing in this request.Check 4 — Mandate status is active
Check 4 — Mandate status is active
The mandate must have
status: "active". Mandates with status revoked or exhausted fail this check.Failure reason code: mandate_expiredWhat to do: If the mandate is exhausted, create a new mandate with a fresh budget. If it has been revoked, create a replacement mandate.Check 5 — Mandate has not expired
Check 5 — Mandate has not expired
The mandate’s
expires_at timestamp must be in the future (i.e., expires_at > now). An expired mandate fails this check even if it still has remaining budget.Failure reason code: mandate_expiredWhat to do: Create a new mandate with an updated expires_at. There is currently no way to extend a mandate’s expiration in place.Check 6 — Merchant domain is in the allowlist
Check 6 — Merchant domain is in the allowlist
The
merchant_domain in the request must appear in the mandate’s allowed_sellers array, or the array must contain "*" (wildcard). An empty allowed_sellers array blocks all merchants — unlike allowed_categories, an empty seller list is not a wildcard.Failure reason code: merchant_not_allowedWhat to do: Add the merchant’s domain to allowed_sellers when creating the mandate, or use ["*"] if you want to allow any seller. Note that mandates are immutable after creation — you must create a new mandate to change the allowlist.Check 7 — Category is in the allowlist
Check 7 — Category is in the allowlist
If the request includes a
category, it must appear in the mandate’s allowed_categories array. If allowed_categories is an empty array [], the check is skipped and any category is permitted.Failure reason code: merchant_not_allowedWhat to do: Add the category to allowed_categories when creating the mandate. To allow all categories, leave allowed_categories as an empty array. See Mandates for details on the empty-array semantics.Check 8 — Amount is within the per-transaction limit
Check 8 — Amount is within the per-transaction limit
The
amount in the request must be less than or equal to the mandate’s max_spend_per_transaction.Failure reason code: amount_exceeds_per_transaction_limitWhat to do: Either use a mandate with a higher max_spend_per_transaction, or split the purchase into smaller transactions. Per-transaction limits are set at mandate creation and cannot be changed.Check 9 — Amount is within the remaining total budget
Check 9 — Amount is within the remaining total budget
The sum of
spent_total + amount must be less than or equal to max_spend_total. This check prevents the agent from exceeding the mandate’s lifetime budget cap.Failure reason code: total_budget_exceededWhat to do: Create a new mandate with a higher max_spend_total, or with a fresh budget for the same agent and purpose.Transaction records
Every call toPOST /v1/policy/evaluate creates a pending transaction record before the checks run. If the evaluation succeeds, the transaction is updated to approved. If any check fails, it is updated to denied. If the evaluation itself throws an error mid-way, the transaction is updated to failed. You can query all transaction records using GET /v1/transactions.
Pre-flight checks with POST /v1/verify-agent
POST /v1/verify-agent runs the same 9 policy checks as the policy engine but does not create a transaction record or charge the mandate. Use it to confirm that an agent and mandate are correctly configured before sending real payment requests — for example, during integration testing or in a pre-flight health check. It also returns identity details, remaining budget, and a risk placeholder in the response.
