Docs
Get an API key

Understand Mandates

Start here: how consent becomes signed payment authority, who owns each step, and when to choose closed or open.

In short

1 callFor people and agents
  1. 1GET/v1/mandate/.well-known/jwks.jsonSigning keys

The same list heads this page's Markdown:/mandate/mandates-overview.md

Imagine a user tells a travel agent: “Book this itinerary, but only with Demo Travel and never above USD 1,800.”

The agent needs more than a remembered chat message. Settlement needs a permission it can verify at the moment of charge, the user needs the permission to stay inside the terms they approved, and an auditor needs to reconstruct what happened later. A mandate connects those needs.

A mandate is a signed, bounded authority to charge a payment instrument. It records who is paying, what instrument may be used, who may be paid, how much may be charged, how long the permission lasts, and any tighter constraints. It authorizes settlement; it does not move money itself.

The actors

Partner and settlement requests pass through the API gateway to the Mandate service, which records an append-only event history.

  • The partner defines the proposed authority, presents it to the user, records consent, and may verify an intended charge.
  • The user decides whether the proposed authority matches what they are willing to allow.
  • The gateway authenticates the caller, scopes access, and supplies the caller identity used for agent binding.
  • The Mandate service signs the authority, evaluates it, derives its current status, and records its history.
  • Settlement performs the actual payment operation. It exercises the mandate as part of committing the charge.

This separation is deliberate: the party proposing a payment can ask whether a charge appears valid, but the system that moves money makes the final state-changing exercise.

One authority, two phases

Issuing and confirming are separate operations.

  1. Issue creates a pending draft and a short confirmation window.
  2. Your application presents the exact terms to the user.
  3. Confirm records that consent and returns a signed ES256 JWT.

The split prevents a draft assembled by an agent from becoming payment authority before the user accepts it. The confirmation window limits how long an unapproved proposal can remain available; expires_in_seconds separately controls how long the confirmed authority is usable.

A mandate moves from pending to active, then follows a closed or open exercise path. Revocation and time can end the authority.

  • pending — issued, but not yet confirmed.
  • active — confirmed, unexpired, unrevoked, and still usable.
  • exercised — a closed mandate completed its one allowed settlement.
  • exhausted — an open mandate used its total budget. An open mandate that reaches payment.max_charges with budget left stays active, but every further charge fails.
  • revoked — the authority was withdrawn.
  • expired — the confirmation window or signed-token lifetime ended.

verify does not create a new status. It is a repeatable preflight check against the exact intended charge. exercise is the settlement commit: it writes exercised for a closed mandate or charged for an open mandate.

Status is derived from events and time rather than stored as a mutable field. Retrieve and list therefore report what the evidence says now, while the event history preserves how the mandate got there.

Choose closed or open

UsemodePayeepayment_amountSettlement
One purchase from one known merchantclosed (default)RequiredMaximum for that chargeOne successful exercise
Several purchases within one delegated budgetopenOptional; normally bounded by payment.allowed_payeesTotal budget across chargesRepeatable until exhausted, expired, or revoked

Use a closed mandate when the user is approving a particular purchase. Use an open mandate when the user is delegating a controlled budget, such as “book flights and hotels for this trip, up to USD 3,000.”

Open mandates return spent and remaining so callers can reason about the budget without rebuilding the ledger.

What is actually signed

Mandate IDs look like mdt_<32 lowercase hex>. Confirmation returns a JWT with an ES256 signature and claims such as:

{
  "iss": "https://mandates.oex.dev",
  "sub": "usr_demo_123",
  "jti": "mdt_0123456789abcdef0123456789abcdef",
  "vct": "mandate.payment.1",
  "mode": "closed",
  "payee": { "id": "merchant_demo", "name": "Demo Travel" },
  "payment_amount": { "currency": "USD", "amount": 180000 },
  "payment_instrument": { "id": "pi_demo_visa", "type": "card" },
  "constraints": [
    { "type": "payment.amount_range", "currency": "USD", "min": 100000, "max": 180000 }
  ],
  "agent_id": "agent_demo",
  "consent_method": "partner_attested",
  "iat": 1786842000,
  "exp": 1786845600
}

sub is the user ID and jti is the mandate ID. The service stamps consent_method; the caller cannot choose it. iss names the issuing environment, so pin the value your environment returns rather than the one shown here. The JWT header uses alg: ES256 and kid: oex-mandates-1. The current public key is available from GET /v1/mandate/.well-known/jwks.json.

Treat the token as an opaque signed value. Store or forward it exactly as returned; never edit, decode-and-reencode, or normalize it.

Rules every integration must keep

  • Amounts are integer minor units. 180000 USD means USD 1,800.00.
  • Issue-request currencies are exactly three uppercase letters.
  • A successful HTTP request is not necessarily authorization. Read confirmed, valid, or exercised and inspect the returned checks. Handle checks, refusals and errors has the full control flow.
  • Verify with the exact charge that settlement intends to make. Verification without a charge skips constraints and amount comparison.
  • Bind with agent_id when only one authenticated agent should use the mandate. The gateway supplies the caller identity for the check.
  • Keep consent evidence. It turns a signed permission into an explainable, auditable decision.

Relationship to AP2

Mandates use AP2 v0.2 payment-mandate naming and the mandate.payment.1 credential type as a compatibility anchor. The service is an OEX design with its own deployed contract, lifecycle, evidence model, and constraint evaluator. See Design choices and AP2 for the field-level relationship and the reasons behind those choices.

Continue

On this page

Endpoints on this page

GETgetMandateJwks