Concepts
The vocabulary. These are the actual field names, so nothing on this page has to be translated to use the API.
Terms
The irreducible fields. They are explicit on every instruction and on every receipt, and they are never silently defaulted, because these are the fields where an agent spending money actually loses it.
reversibility- Whether a settled payment can be reversed:
reversibleorirreversible. finality- When value becomes final:
instantordeferred. credential- Which authorisation model is being used, for example
eip3009,vc-mandateorhttp-sig. rail- How the money moves. See rails.
capitalSource- Who fronts the capital:
payer,facilitator,merchant_of_recordorsolver. presence- Whether a person was there at authorisation:
presentordelegated.
Intent
A signed request to move value. It never carries the means to settle: submitting one is asking, not doing.
{
idempotencyKey: string
payee: string
amount: { value: string, asset: string }
purpose: string
terms: Terms
envelope: Envelope
}Amounts are minor units carried as a string, with the asset as a currency code or a chain-scoped asset id. Money in a float is a rounding error waiting to happen, so the type does not allow one.
Envelope and Grant
The layered delegation wrapped around an instruction: who is calling, under which mandate, and the operator's counter-signature proving that authority was actually granted rather than claimed.
{
identity: string // the calling agent
mandateId: string
grant: { agentId, mandateId, expiresAt, signature }
signature: string
}Mandate
Operator-granted spend authority: scoped, capped, and expiring. This is the object your limits actually live in.
{
id: string
payees: string[] // who may be paid, and nobody else
perTxCap: Amount
perPeriodCap: Amount
period: string // ISO-8601 duration
expiresAt: string // ISO-8601 instant
irreversibleOutlay?: {
maximumAmount?: Amount // absolute ceiling, below perPeriodCap
maximumShareBps?: number // or a share of it; 1000 is 10%
}
constraints?: Record<string, unknown>
}The irreversible bound is nested rather than parallel: an irreversible payment counts in full against the period cap and against this one. A sub-cap with its own separate allowance would add authority instead of subtracting it. Where both forms are present, the tighter one binds, because operators genuinely think in both.
Decision
The verdict, and it is deny-first.
{
outcome: "allow" | "confirm" | "deny"
reasons: string[] // prose, for a person
mandateId: string
checks?: { id: string, passed: boolean }[] // the predicates evaluated, in order
}reasons is written for a human. checks is the machine version: stable ids you can compare across versions and switch on. An older decision may carry none, and an absent list does not mean everything passed.
Receipt
Durable proof that value moved, and under exactly which terms.
{
intentKey: string
rail: RailId
reference: string // the rail's own settlement reference
terms: Terms
settledAt: string
...enforcement hash, byte-identical between emitter and verifier
}The receipt repeats the terms rather than referring back to them, so a receipt read years later still says what kind of payment it was without needing anything else to be alive.