Verifiable Intent
Treeship as one agent_attestation scheme inside Verifiable Intent credentials, shipped as treeship vi
Verifiable Intent is an open credential standard for agent commerce, maintained by Mastercard and co-developed with Google (draft v0.1, February 2026). It defines a three-layer credential chain that proves an agent was authorized to act on a user's behalf. Treeship implements the agent's side of that chain, treeship vi, and supplies one agent_attestation type for the Layer 3 credential: the signed evidence of what the agent actually did between receiving the mandate and handing the cart to checkout.
This is an independent implementation against the published draft and its reference SDK, tested against that SDK in both directions in CI. Treeship interoperates with Verifiable Intent; it is not endorsed by, and does not speak for, the standard's maintainers.
Shipped in 0.31. The command reference is treeship vi. Before 0.31 this page described a design; the April 2026 packages/vi types it referred to were written against a pre-v0.1 draft and never wired, and are retired.
The credential chain
L1: Issuer credential
The payment network or credential provider issues an SD-JWT that
identifies the user and binds their device key.
|
v
L2: User mandate
The user delegates bounded authority to a specific agent: checkout
constraints, payment constraints, a time window, and the agent's key
bound under `cnf`.
|
v
L3: Agent execution (autonomous mode)
The agent signs two key-bound SD-JWTs, L3a for the payment network and
L3b for the merchant, each bound to the L2 mandate. This is where the
`agent_attestation` claim lives, and where Treeship plugs in.treeship vi keygen mints the agent's key and prints the JWK the wallet binds at L2. treeship vi attest signs L3a and L3b, after checking the purchase against the mandate. treeship vi verify checks a pair the way the reference verifier does, then the attestation.
What Treeship puts in the claim
The v0.1 draft shapes the claim as { "type": "<scheme>", "value": <payload> } and requires verifiers to ignore types they do not recognize rather than reject the credential. Treeship did not invent the field; it registers the scheme treeship.receipt-chain.v1 and fills value with a signed statement, every field of which already exists in a Treeship session:
| Field | What it contains | Where it comes from |
|---|---|---|
session | The Treeship session id, which names the exported .treeship package a verifier receives | treeship session |
chain_head | The id of the last receipt in the session's chain at the moment the L3 pair was signed | The receipt chain |
checkpoint | The Merkle root over every receipt from the session root to that head, so a verifier can check inclusion of any single step | treeship merkle / session close |
approval_use | The digest of the approval-use record that spent the human approval the action ran under, when one exists | The Approval Use Journal |
mandate_digest | SHA-256 of the L2 base JWT, so the attestation names the mandate it was issued against | The L2 |
transaction_id | The checkout_hash both L3 halves carry | The checkout JWT |
The statement is signed with the ship's Ed25519 key as an ordinary action receipt (vi.l3.attested, DSSE envelope, parentId = chain_head inside the signature), stored on the chain, and value carries the envelope, its artifact id and the signing public key. Any Ed25519 library confirms the signature with no Treeship code. treeship verify <artifact-id> walks the chain it sits on. The L3 credential itself is signed with the agent's P-256 key as the spec requires; Treeship does not replace that signature, it adds evidence underneath it.
A verifier that does not know the scheme ignores the claim and checks the rest of the chain as usual. The reference SDK does exactly that, and the interop suite asserts it. A verifier that does know it takes the .treeship package, runs treeship package verify and treeship verify offline, and checks that the package's chain head and Merkle root equal the two digests in the claim. That confirms the credential was minted at the end of exactly this sequence of signed steps, and that the human approval it cites was spent once and never replayed.
What is deliberately not in the payload: zero-knowledge proofs. Nothing in the shipped Treeship stack produces such a proof, and the design does not claim one. Field-level privacy for the receipts themselves is a separate, shipped surface: treeship present.
What crosses the issuer boundary
An L3 credential travels to a payment network and, in a dispute, to an issuer's evidence process. That is a different audience from the merchant's operators, so the identifiers in the claim are chosen deliberately rather than inherited:
- The Treeship session id crosses. It is a random identifier that names the evidence package. It is not a bearer credential and unlocks nothing on its own; the verifier still has to be handed the package.
- The host's own session identifier does not cross. In the commerce-agents integration the reference host's session id is a request credential, and receipts carry only the short tag the host logs. The VI claim carries neither.
- No cart contents, prices, URLs, or order references cross in the claim. Those are already digests in the receipts, and the claim carries only the chain head and root over them. (The L3 halves themselves carry what the spec says they carry: the amount and payee to the network, the checkout JWT to the merchant.)
With Anthropic's commerce blueprint
Anthropic's commerce-agents reference stops at checkout hand-off: the shopping agent assembles a cart, and a hosted checkout owned by the merchant takes over. Verifiable Intent starts from the other end: the network wants a chain from the user's mandate to the transaction. Treeship's commerce package already signs the steps in between, so the mapping is direct:
| Verifiable Intent | Treeship commerce receipt | Note |
|---|---|---|
L2 mandate constraints (amount_range, allowed_payees, line_items) | commerce.checkout.handoff carries subtotal, currency, item_count, and a per-hand-off seller | treeship vi attest is run at hand-off with the cart's values; the chain the attestation names runs through the hand-off receipt, so the claim binds the cart that went to checkout to the credential |
L3b checkout_hash (SHA-256 of the merchant's checkout JWT) | cart_digest (SHA-256 over the canonical cart) | Different preimages by design: the spec hashes the merchant's token, Treeship hashes the cart the agent built. The claim's transaction_id is the former; the chain it names covers the latter |
| L3a payment leg | commerce.order.placed, on the chain after the hand-off, naming it | Treeship records that an order was placed and for how much, digesting the order reference. It does not touch the payment instrument; that stays on the network |
| Provenance-gate refusals | commerce.tool.* receipts with status blocked | Not part of VI at all, and the part an issuer is most likely to ask about: the planted cart add that the gate refused is in the same chain the credential cites |
Merchant-side approvals (the signed, single-use grants in the merchant vertical) are outside Verifiable Intent, which is the buyer's chain. They stay in the merchant's own session package.
Key management
Verifiable Intent requires ES256 (P-256) for every layer's signature, alongside Treeship's default Ed25519 receipt keys. treeship vi keygen generates the P-256 keypair, seals the private scalar at rest with the ship keystore's machine key (the same AES-256-GCM construction that protects the Ed25519 keys), and prints the public half as the JWK the L2 mandate binds under cnf. treeship vi keys import takes a private JWK a wallet or HSM issued instead.
Status
| Stage | Capability |
|---|---|
| spec (external) | agent_attestation claim on L3, { type, value }, unknown types ignored: defined by Verifiable Intent v0.1, not by Treeship |
| shipped · 0.31 | treeship vi keygen / keys / check / attest / verify; key-bound SD-JWT L3a/L3b with sd_hash, transaction_id / checkout_hash; the eight constraint types; the treeship.receipt-chain.v1 attestation |
| shipped · 0.31 | Two-way interop with the reference SDK, in CI |
| shipped | Every field of the attestation value: session ids, receipt chains, Merkle checkpoints, approval-use records, treeship verify over an exported package |
| shipped | The commerce receipts the claim binds: commerce.checkout.handoff and commerce.order.placed in treeship-commerce |
| not in scope | Multi-pair L2 mandates; network-side cumulative budget and occurrence counting; immediate mode (no L3 exists) |
Compatible with Lobster Cash
Verifiable Intent credentials and Lobster Cash payments work together. The flow is:
- L2 mandate delegates payment authority to the agent
- Treeship attests each step (intent, approval, execution)
- Lobster Cash executes the payment
- Treeship produces the
agent_attestationfor the L3 credential - The L3 credential, the Treeship receipt chain, and the Lobster Cash settlement form a complete proof
See the Lobster Cash integration for the payment-specific workflow.
Mastercard-specific integration details (network rules, merchant onboarding, credential exchange protocols) are separate from this technical implementation. This page covers the open Verifiable Intent standard only.