> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sumvin.com/llms.txt
> Use this file to discover all available pages before exploring further.

# The mandate language

> How a Stamped Mandate is written: scopes say what an agent may do, resources say what it is bound to, and parameters and conditions set the limits.

A Stamped Mandate is written in a small language of identifiers. Every part of a mandate that says what is allowed is one of these identifiers, so a mandate reads the same to you on the approval page, to your agent, and to whoever checks it.

<Info>
  The language is about to be open-sourced, so that others can propose and contribute new use cases. These pages are its public description.
</Info>

## The parts of a mandate

| Part | Written as | Says |
| - | - | - |
| **Scopes** | One or more scope identifiers | What the agent may do, each with its own limits. At least one is required. |
| **Resources** | Zero or more resource identifiers | What the mandate is bound to, such as one errand. |
| **Conditions** | Zero or more condition identifiers | Facts that must hold before a purchase goes ahead, such as a price. |
| **Audience** | A party identifier or a hostname | Who the mandate is addressed to. |
| **Expiry** | A time | When the mandate stops standing. |

A mandate grants only what its scopes grant, and only within their parameters, its resources, its conditions and its expiry. Anything not written in it is not permitted.

## Identifiers

Every identifier starts with the scheme `sr` and a region, separated by colons:

```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sr:{region}:{family}:...
```

The region is `us` for everything Sumvin issues today. The third segment names the family, and each family has its own shape:

| Family | Shape | Used for |
| - | - | - |
| Scope | `sr:us:pint:{domain}:{action}[?{params}]` | What an agent may do. See [Scopes](/concepts/mandates/scopes). |
| Mandate | `sr:us:pint:{id}` | One specific mandate. |
| Errand | `sr:us:errand:{id}` | One specific errand. |
| Person | `sr:us:person:...` | A person's own account. |
| Condition | `sr:us:condition:{type}?{params}` | A fact that must hold. See [Resources and conditions](/concepts/mandates/resources#conditions). |

Scopes and mandates share a family. A scope has five segments, a domain and an action; a mandate identifier has four, ending in an opaque id. The two are never confused: a five-segment identifier is always a scope, never a thing a mandate is bound to.

<Info>
  **On the wire.** The third segment of a scope or mandate identifier is the literal word `pint`. A Stamped Mandate was previously called a PINT, and the identifiers keep that segment. `sr:us:pint:spend:visa_checkout` is a scope; `sr:us:pint:3f9c2a7e5b1d4c8e9a6f0b2d7e4c1a58` is a mandate.
</Info>

## Scope syntax

```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sr:us:pint:{domain}:{action}?{key}={value}&{key}={value}
```

| Piece | Rules |
| - | - |
| `domain` | The area the scope covers, such as `sigil`, `spend`, `errand` or `accounts`. |
| `action` | What may be done there, such as `read`, `manage`, `search` or `visa_checkout`. |
| Parameters | Optional, after a single `?`, as `key=value` pairs joined by `&`. |

The rules a scope must pass before anyone can sign it:

* **Exactly five segments** before any `?`: `sr`, a region, `pint`, a domain and an action. None may be empty.
* **Known name.** The domain and action must be a scope in the [catalogue](/concepts/mandates/scopes). An unknown name is refused, not ignored.
* **Declared parameters only.** Each scope declares the parameters it accepts. An undeclared key is refused.
* **Required parameters present.** Some scopes can't be signed without certain parameters. `spend:visa_checkout` needs both `max` and `currency`.
* **Each parameter once.** A scope that repeats a parameter, such as `max=1&asset=USDC&max=1000`, is refused as malformed (`PINT-400-005`). Sumvin never picks the first value or the last, because two readers could pick differently and read different limits from the same mandate.
* **No empty values.** `max=` is refused.
* **Values of the right type.** See the table below.

## Parameter types

| Type | Written as | Example |
| - | - | - |
| Amount | A plain decimal number in the display unit of the currency or asset the scope names: ASCII digits with at most one `.`. See [Numbers](#numbers). | `max=25.50` |
| Integer | ASCII digits only. See [Numbers](#numbers). | `time=604800` |
| Timestamp | Unix time in seconds, as an integer. | `from_date=1788220800` |
| Currency | An ISO 4217 code. | `currency=USD` |
| Provider | Lowercase letters, digits and `_`, from the scope's own list. | `provider=meld` |
| Text | Free text, or one of a fixed list where the scope declares one. | `doc_type=passport` |

Amounts are covered in full in [Limits and narrowing](/concepts/mandates/limits#spending-ceilings).

### Numbers

Every number in a scope or a condition is written in one exact form, so a number in a signed mandate reads the same to every person and every program.

* **Amounts** are ASCII digits with at most one `.`, and digits on both sides of it. `25`, `25.50` and `0.5` are amounts; `25.` and `.5` are not.
* **Integers** are ASCII digits only. `604800` is an integer; `604800.0` is not.
* **Nothing else is read as a number.** These are all refused: a `+` sign (`+5`), spaces (`1 000`), `_` separators (`1_000`), an exponent (`1e3`), `NaN`, `Infinity`, a trailing newline, and digits from another script.
* **A minus sign is refused wherever a value can't be negative.** Limits, search windows and chain ids can't be, so `max=-5` is refused, and so is `max=-0`.

Conditions use the same form. The `value` of a `price_target` and the `max` of a `budget_cap` are amounts, so `value=1e3` or `max=+5` in a condition is refused just as it would be in a scope. No condition value can be negative, so a minus sign is refused in every condition: `max=-5`, `max=-0` and `value=-180` are all refused.

## How the parts combine

* **Scopes add up.** A mandate with two scopes grants both, and each scope keeps its own parameters. `accounts:read` plus `transactions:read?from_date=…` lets an agent read your accounts, and your transactions only in that range. Two `transactions:read` scopes with different ranges add up too: a transaction is readable when it falls inside either. See [Limit reads to a date range](/concepts/mandates/scopes#limit-reads-to-a-date-range). Where several `spend:execute` scopes limit the same payment, their limits combine and the tightest one binds. See [Several spending scopes](/concepts/mandates/limits#several-spending-scopes-on-one-mandate).
* **Parameters narrow a scope.** A scope with no parameters grants its whole action. Each parameter you add can only take something away.
* **Resources and conditions narrow the whole mandate.** A mandate bound to one errand can be used for that errand only. A mandate with conditions can't complete a purchase until all of them hold.
* **One spending limit per drafted mandate.** When your agent drafts a spending mandate for you to sign, it carries exactly one scope that states a ceiling. A mandate that carries separate limits for different assets is a different shape, described in [Several spending scopes](/concepts/mandates/limits#several-spending-scopes-on-one-mandate).
* **What you sign is what is checked.** Scopes, resources and conditions are signed exactly as written: in the same order, with nothing removed, merged or reordered. When your agent drafts a spending mandate, its scopes are sorted and duplicates removed once, before you see the approval page, so the page shows the form you sign.
* **Additive to the service's own rules.** A mandate restricts what an agent may do. It never lifts a check the service already makes, such as requiring you to be verified.

## Older names

Some scopes were renamed. The older names are still accepted in mandates signed before the rename, and they mean exactly the same as the new ones. Use the new names.

<Accordion title="Older scope names and their replacements">
  | Older name | Current name |
  | - | - |
  | `sr:us:pint:perpetual:search` | `sr:us:pint:errand:search` |
  | `sr:us:pint:identity:kyc_status` | `sr:us:pint:sigil:kyc_status` |
  | `sr:us:pint:identity:kyc_read` | `sr:us:pint:sigil:kyc_read` |
  | `sr:us:pint:identity:proof_of_personhood` | `sr:us:pint:sigil:proof_of_personhood` |
  | `sr:us:pint:identity:age_over_18` | `sr:us:pint:sigil:age_over_18` |
</Accordion>

## Next

<Columns cols={2}>
  <Card title="Scopes" icon="list" href="/concepts/mandates/scopes">
    Every scope family and what it grants.
  </Card>

  <Card title="Resources and conditions" icon="link" href="/concepts/mandates/resources">
    What a mandate is bound to, and what must hold.
  </Card>

  <Card title="Limits and narrowing" icon="sliders-horizontal" href="/concepts/mandates/limits">
    Ceilings, units, expiry, and why a mandate only narrows.
  </Card>

  <Card title="What a verifier checks" icon="shield-check" href="/concepts/mandates/verification">
    The answer a counterparty gets.
  </Card>
</Columns>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.