> For the complete documentation index, see [llms.txt](https://docs.toolkit.equs.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.toolkit.equs.ai/docs/agentic/ap2/mandate-reference.md).

# Mandate Reference

Mandate types, constraints, validation rules and error codes shared by all three AP2 flows

All three flows take the same `mandates` array and validate it the same way. Every mandate is checked before anything reaches the User's wallet, and an invalid one is rejected with a specific error rather than put in front of them.

{% hint style="info" %}
**AP2 is at v0.2** and still moving. `vct` values and constraint shapes may change with the [specification](https://ap2-protocol.org/).
{% endhint %}

### Mandate types

A mandate's `vct` says what the User approves, and whether authority continues past them.

| Mandate             | vct                       | The User approves                                              | Agent key   |
| ------------------- | ------------------------- | -------------------------------------------------------------- | ----------- |
| **Open Checkout**   | `mandate.checkout.open.1` | Bounds on a future checkout: which items, from which merchants | Required    |
| **Open Payment**    | `mandate.payment.open.1`  | Bounds on a future payment: how much, to whom, by what means   | Required    |
| **Closed Checkout** | `mandate.checkout.1`      | One concrete checkout, signed by the merchant                  | Not allowed |
| **Closed Payment**  | `mandate.payment.1`       | One concrete payment                                           | Not allowed |

A request carries **1 to 10 mandates, all Open or all Closed**.

* **`exp`** - every mandate accepts an optional expiry, in Unix epoch seconds. Left out, it defaults to one hour after the mandate is issued.
* **Amounts** are always in the **minor units** of an ISO 4217 currency: `12999` in `USD` is $129.99. Currencies are three uppercase letters.

### Open Checkout constraints

An Open Checkout mandate needs **at least one `checkout.line_items` constraint**.

| Type                         | Payload                                                                                                                                                |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `checkout.line_items`        | `items[]` of `{ id, acceptable_items[], quantity }`, where `acceptable_items` lists the products that satisfy the line, such as `{ id, title, price }` |
| `checkout.allowed_merchants` | `allowed[]` of `{ id, name, website? }`                                                                                                                |

### Open Payment constraints

| Type                                  | Payload                                                                                                                                       |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `payment.amount_range`                | `{ currency, max, min? }` - per payment                                                                                                       |
| `payment.budget`                      | `{ currency, max }` - cumulative across payments                                                                                              |
| `payment.allowed_payees`              | `allowed[]` of `{ id, name, website? }`                                                                                                       |
| `payment.allowed_payment_instruments` | `allowed[]` of `{ id, type, description? }`                                                                                                   |
| `payment.allowed_pisps`               | `allowed[]` of `{ legal_name, brand_name, domain_name }`                                                                                      |
| `payment.agent_recurrence`            | `{ frequency, max_occurrences? }`, where `frequency` is one of `ON_DEMAND`, `DAILY`, `WEEKLY`, `BIWEEKLY`, `MONTHLY`, `QUARTERLY`, `ANNUALLY` |
| `payment.execution_date`              | `{ not_before?, not_after? }`                                                                                                                 |

`payment.reference` is part of AP2 but **not supported** - a request that uses it is rejected.

An Open Payment mandate may also carry `payee`, `payment_amount`, `payment_instrument`, `pisp`, `execution_date` and `risk_data` when they are already known at approval time.

### Closed mandates

| Mandate             | Fields                                                                                                                               |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **Closed Checkout** | `checkout_jwt` - the checkout as the merchant signed it; `checkout_hash` - its hash                                                  |
| **Closed Payment**  | `transaction_id`; `payee` `{ id, name }`; `payment_amount` `{ amount, currency }`; `payment_instrument` `{ id, type, description? }` |

**A checkout and its payment are linked.** When both are present, the payment's `transaction_id` must equal the checkout's `checkout_hash`.

```json
[
  { "vct": "mandate.checkout.1",
    "checkout_jwt": "eyJhbGciOiJFUzI1NiJ9…",
    "checkout_hash": "sha256-…" },
  { "vct": "mandate.payment.1",
    "transaction_id": "sha256-…",
    "payee": { "id": "merch_1", "name": "Demo Merchant" },
    "payment_amount": { "amount": 12999, "currency": "USD" },
    "payment_instrument": { "id": "card_1", "type": "card", "description": "Visa ending in 4444" } }
]
```

The same shapes serve two purposes: sent in a mandate request for a **Human-present** approval, where the User signs them; and, on Flows 2 and 3, sent to the close call, where the platform signs them for your agent over an existing grant.

### Validation rules

* All Open **or** all Closed - never both in one request.
* Open mandates need an agent key; Closed mandates must not have one. On Flow 1 that means `agentKey` is required for Open and rejected for Closed. On Flows 2 and 3 the platform supplies the key, and `kid` is accepted only on an Open request.
* An Open Checkout mandate needs a `checkout.line_items` constraint.
* `payment.reference` is rejected.
* A linked payment's `transaction_id` must equal the checkout's `checkout_hash`.
* The VP Schema must have exactly one credential input.
* When closing on Flows 2 and 3, supply Closed content for **every** mandate the grant carries, in one call.

### Errors

**Creating a request**, on every flow, fails with `400` and one of these codes:

| Error                                      | Meaning                                                                   |
| ------------------------------------------ | ------------------------------------------------------------------------- |
| `mixed_mandate_flows`                      | Open and Closed mandates in one request                                   |
| `agent_key_required`                       | An Open mandate without `agentKey`                                        |
| `agent_key_not_allowed`                    | `agentKey` on an all-Closed request                                       |
| `checkout_line_items_required`             | An Open Checkout mandate without a `checkout.line_items` constraint       |
| `payment_reference_unsupported`            | A `payment.reference` constraint                                          |
| `mandate_link_mismatch`                    | A payment's `transaction_id` doesn't match its checkout's `checkout_hash` |
| `multi_credential_vp_schema_not_supported` | The VP Schema has more than one credential input                          |

A Tenant, Verifier or VP Schema that doesn't exist, or doesn't belong with the others, returns `404` with no code.

**On Flows 2 and 3**, the Web Custodial Wallet API adds these. All are `400`, except `kid_not_found`, which is `404`:

| Error                                                | Meaning                                                                                                                |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `mandate_request_rejected`, `mandate_request_failed` | The mandate request was rejected, or couldn't be created                                                               |
| `kid_not_found`                                      | No such key in the agent's vault - often a `kid` generated with the other kind of token, the User's or the agent's own |
| `invalid_tx_code`                                    | The `txCode` is wrong, expired or already used                                                                         |
| `mandate_not_accepted`                               | The grant for this `txId` has already been imported                                                                    |
| `grant_expired`                                      | A mandate in the grant has passed its `exp`                                                                            |
| `close_rejected`                                     | The Closed content doesn't match the stored grant                                                                      |

**In the wallet** - `no_credentials_found` means the User holds no credential that satisfies your VP Schema, so there is nothing for the mandate to be signed over. It reaches your page through Embed UI's `onError`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.toolkit.equs.ai/docs/agentic/ap2/mandate-reference.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
