Intent mandates
An intent mandate is the user’s cryptographically signed instruction: “Buy X under conditions Y, up to amount Z, valid until T.” Agents fulfill mandates; Lipafy validates against the signed terms.
Mandates exist because “the agent should know what I want” is a bad authorization model. Mandates make the user’s permission explicit, conditional, time-bound, and signed.
The shape
Two flavors:
- Single-shot (
max_fulfillments: 1) — “buy this one thing when the conditions match.” Equivalent to AP2’s “Closed” state once fulfilled. - Multi-shot — “I’ll let you fulfill this up to N times, total budget Z.” Useful for monitoring (price-drop alerts), recurring buys, or budget-pooled background purchases.
The two-phase signing flow
To prevent server↔client text-format disagreements, signing is a round-trip:
Phase 1 — challenge
The server responds with the exact canonical text to sign, plus a nonce:
Phase 2 — create
The user signs that text with their wallet (personal_sign). The client posts the same parameters plus the signature and nonce:
The server reconstructs the exact same text from the parameters + nonce, then recoverMessageAddress-es the signature. If the recovered address is linked to the account via wallet_addresses, the mandate is stored.
This shape means the signature commits to every parameter — change a single character of the intent or pattern and the signature won’t recover correctly.
Fulfilling
Anyone with the mandate id (including the agent itself via MCP) can call:
Lipafy validates every condition against the stored, signed mandate:
All pass → call dispatches through the gateway like any normal capability call. The mandate’s consumed budget atomically advances inside a transaction with SELECT FOR UPDATE, so concurrent fulfillments serialise.
Where this matches Google’s AP2
Lipafy adds:
- Concrete budget arithmetic (per-fulfillment cap, total budget) so the mandate is enforceable without AI judgment
- Multi-shot lifecycle (a single mandate can serve N fulfillments)
- Per-account wallet binding — the signature has to come from a wallet linked to the owning account, so even a leaked mandate id isn’t enough to act
Cancelling
The user can always DELETE /v1/intent-mandates/<id> while it’s open. Once cancelled, no further fulfillments are accepted (existing capability_requests don’t reverse — past spend is past spend, not undone by cancelling future authorization).
