REST APIMandates & Authorize

A mandate is the on-record spending rulebook for one agent. Every payment is authorized against it before execution; an amount outside the rules is rejected and no money moves.

Create a mandate

Requires completed KYC (403 KYC_NOT_VERIFIED otherwise). agent_id must be the canonical agent_… identifier from registration — a record UUID gets an immediate 422 AGENT_ID_MALFORMED, an agent outside your organization a 404 AGENT_NOT_FOUND.

curl -X POST https://api.regentprotocol.org/v1/organizations/<org>/mandates \
  -H "Authorization: Bearer rgnt_..." -H "content-type: application/json" \
  -d '{
    "agent_id": "agent_688b10bc62aef…",
    "owner_id": "<responsible_party_id from registration>",
    "currency": "USD",
    "limits": {
      "per_tx_limit": "50",
      "daily_limit": "300",
      "monthly_limit": "5000"
    }
  }'

Limit fields

FieldMeaning
per_tx_limitMaximum for a single authorization
daily_limit / monthly_limitRolling usage ceilings (settle adjusts them)
entity_key + per_entity_limitPer-entity sub-budget (e.g. entity_key: "customer", at most N per customer/month) — each authorize must then carry entity_id
relational_capBound the action by a referenced anchor’s amount (e.g. a refund must not exceed the original charge) — authorize must then carry reference + reference_amount

Optional: expires_at, metadata. settlement_chain is solana (the only live anchor). The response includes the mandate id, status: active, and a terms_commitment in metadata — the on-chain anchor gets a commitment to the terms, never the ceilings themselves.

Authorize a payment

curl -X POST https://api.regentprotocol.org/v1/organizations/<org>/mandates/<mandate_id>/authorize \
  -H "Authorization: Bearer rgnt_..." -H "content-type: application/json" \
  -d '{"amount": "25", "currency": "USD"}'

Optional fields: idempotency_key, entity_id (per-entity budgets), reference + reference_amount (relational cap), caller_agent_id (when set, must equal the mandate’s agent — stops one agent spending against another’s mandate; the control gate always sends it).

Success returns the authorization with a short-lived JWT proof:

{
  "id": "de35ead1-…",
  "mandate_id": "…",
  "agent_id": "agent_688b…",
  "amount": "25.000000",
  "currency": "USD",
  "status": "authorized",
  "jwt_token": "…",
  "jti": "…",
  "guardian_score": 0.12,
  "authorized_at": "…"
}

A refusal is 402 with detail.code — the full ladder is in the error reference. The two you must handle: MANDATE_LIMIT_EXCEEDED (don’t retry the same amount) and MANDATE_SUSPENDED (the kill switch — stop).

Settle

After the real charge lands, reconcile the difference between approved and settled:

POST /v1/organizations/<org>/mandates/<mandate_id>/settle
{"delta": "-3.50"}     // settled − approved; negative = came in lower / refund

Returns updated daily_used / monthly_used.

Revoke a mandate

POST /v1/organizations/<org>/mandates/<mandate_id>/revoke

Independent of agent revocation: revoking the agent suspends all its mandates; revoking one mandate leaves the agent (and other mandates) alone.