Ap2/v0.2 mandates#611
Open
mike-parkhill wants to merge 9 commits into
Open
Conversation
Implements the AP2 v0.2 mandate model: Open/Closed Checkout Mandate and Open/Closed Payment Mandate, as SD-JWTs with a delegate_payload envelope (RFC 9901 array-element disclosure wrapping the mandate content, not a flat payload). Mandates are self-signed (BYOK signer, same contract as signReceipt) rather than issued by a third party. Adds: - buildOpen/ClosedCheckoutMandate, buildOpen/ClosedPaymentMandate - signOpen/ClosedCheckoutMandate, signOpen/ClosedPaymentMandate - verifyClosedCheckoutMandate, verifyClosedPaymentMandate — brought in-house per this package now owning mandate verification, rather than requiring an external dependency - computeCheckoutHash / computeDisclosureDigest — the two distinct hash primitives mandates need (hash of checkout_jwt vs. per-disclosure digest), reusing existing crypto-utils SD-JWT primitives throughout Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Round-trips Open/Closed Checkout and Payment Mandates through real Secp256r1Keypair signing and verification, plus negative cases (tampered checkout_hash, wrong signing key). Also decodes the AP2 spec's own literal encoded token from the checkout_mandate page and asserts this package's digest computation matches it exactly — the only way to catch a subtly-wrong digest algorithm rather than one that's merely self-consistent. This caught two transcription typos while writing the test (independently confirmed via plain node:crypto that the spec page's human-readable JSON annotation has a one-character typo, not this code). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a Mandates section to the README (usage example, sd_hash caveat) and removes the now-outdated "mandate verification lives outside this package" line. Adds a changeset (minor bump) per this monorepo's changesets-based release process. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the 4 hand-authored mandate content schemas with the canonical versions published at schema.truvera.io last week (adding their $id/ $metadata), which are meaningfully more precise than what was written from just reading the spec's property tables: - payment_amount.amount is integer minor units (not a bare number) - Open Checkout Mandate constraints must contain at least one checkout.line_items entry (schema "contains", not just conventional) - Open Payment Mandate constraints must contain a payment.reference entry with conditional_transaction_id — also schema-required - Full constraint type coverage for Open Payment Mandate via proper $defs/oneOf: payment.agent_recurrence, allowed_payees, allowed_payment_instruments, allowed_pisps, amount_range, budget, execution_date, reference (previously only amount_range and allowed_payees were modeled at all) Updates redactPaymentConstraints to also treat payment.allowed_payment_instruments as array-element-disclosable, matching the "x-selectively-disclosable-array" annotation on the published schema (payment.allowed_pisps is not marked disclosable and is left unredacted, same as before). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The round-trip test's Open Payment Mandate constraints now include a payment.reference entry, and the two negative-path tests' Open Checkout Mandates now include a minimal checkout.line_items constraint — both now schema-required (see previous commit), where the tests previously used an empty/incomplete constraints array that only happened to pass under the old, looser hand-authored schema. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Points readers at the canonical schema.truvera.io documents (referenced in each schema file's $id) and calls out the two schema-required constraints and the full set of supported Open Payment Mandate constraint types. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates @docknetwork/ap2 to support AP2 v0.2’s mandate model (Open/Closed Checkout and Payment mandates) using SD-JWT delegate_payload envelopes, alongside the existing receipt tooling.
Changes:
- Added mandate build/sign/verify APIs (including selective disclosure handling and key-binding envelope verification).
- Vendored upstream AP2 v0.2 JSON Schemas and added a generator to produce self-contained mandate schemas for AJV validation.
- Added mandate-focused Jest coverage and updated package docs/changelog/version for the new public surface.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/ap2/upstream-ap2-schemas/types/receipt_status.json | Adds upstream Receipt Status type schema. |
| packages/ap2/upstream-ap2-schemas/types/pisp.json | Adds upstream PISP type schema. |
| packages/ap2/upstream-ap2-schemas/types/payment_instrument.json | Adds upstream Payment Instrument type schema. |
| packages/ap2/upstream-ap2-schemas/types/merchant.json | Adds upstream Merchant type schema. |
| packages/ap2/upstream-ap2-schemas/types/amount.json | Adds upstream Amount type schema. |
| packages/ap2/upstream-ap2-schemas/payment_receipt.json | Adds upstream Payment Receipt schema. |
| packages/ap2/upstream-ap2-schemas/payment_mandate.json | Adds upstream Closed Payment Mandate schema. |
| packages/ap2/upstream-ap2-schemas/open_payment_mandate.json | Adds upstream Open Payment Mandate schema. |
| packages/ap2/upstream-ap2-schemas/open_checkout_mandate.json | Adds upstream Open Checkout Mandate schema. |
| packages/ap2/upstream-ap2-schemas/checkout_receipt.json | Adds upstream Checkout Receipt schema. |
| packages/ap2/upstream-ap2-schemas/checkout_mandate.json | Adds upstream Closed Checkout Mandate schema. |
| packages/ap2/tests/mandates.test.js | Adds byte-level and round-trip mandate tests. |
| packages/ap2/src/utils.js | Adds mandate schema exports, mandate content validation, and mandate type constants. |
| packages/ap2/src/schemas/payment-mandate-open.json | Adds generated Open Payment Mandate AJV schema (inlined types). |
| packages/ap2/src/schemas/payment-mandate-closed.json | Adds generated Closed Payment Mandate AJV schema (inlined types). |
| packages/ap2/src/schemas/checkout-mandate-open.json | Adds generated Open Checkout Mandate AJV schema (inlined types). |
| packages/ap2/src/schemas/checkout-mandate-closed.json | Adds generated Closed Checkout Mandate AJV schema (inlined types). |
| packages/ap2/src/mandates.js | Implements mandate SD-JWT construction, redaction, signing, and verification. |
| packages/ap2/src/index.js | Exposes mandate APIs and schema exports from the package root. |
| packages/ap2/scripts/generate-schemas.mjs | Adds schema generator to inline upstream types/*.json references into self-contained schemas. |
| packages/ap2/README.md | Documents mandate support and updates examples accordingly. |
| packages/ap2/package.json | Bumps version and adds generate-schemas script. |
| packages/ap2/CHANGELOG.md | Documents the new 0.3.0 mandate feature set and schema generation approach. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "$id": "https://ap2-protocol.org/schemas/types/merchant.json", | ||
| "title": "Merchant", | ||
| "description": "Schema defining a Mechant object", |
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "$id": "https://ap2-protocol.org/schemas/types/amount.json", | ||
| "title": "Amount", | ||
| "description": "Schema defining an Amount and Current object", |
Comment on lines
+19
to
+22
| "constraints": { | ||
| "type": "array", | ||
| "description": "Array of constraints that the future checkout action must abide by.", | ||
| "items": { |
Comment on lines
+78
to
+81
| "risk_data": { | ||
| "type": "object", | ||
| "description": "An map of relevant risk signals collected by the trusted surface at time of mandate creation." | ||
| }, |
Comment on lines
+45
to
+48
| "risk_data": { | ||
| "type": "object", | ||
| "description": "An map of relevant risk signals collected by the trusted surface at time of mandate creation." | ||
| }, |
Comment on lines
+18
to
+21
| "constraints": { | ||
| "type": "array", | ||
| "description": "Array of constraints that the future checkout action must abide by.", | ||
| "items": { |
Comment on lines
+146
to
+149
| "risk_data": { | ||
| "type": "object", | ||
| "description": "An map of relevant risk signals collected by the trusted surface at time of mandate creation." | ||
| }, |
Comment on lines
+193
to
+198
| "required": [ | ||
| "id", | ||
| "name" | ||
| ], | ||
| "description": "Schema defining a Mechant object" | ||
| }, |
Comment on lines
+113
to
+116
| "risk_data": { | ||
| "type": "object", | ||
| "description": "An map of relevant risk signals collected by the trusted surface at time of mandate creation." | ||
| }, |
Comment on lines
+2
to
+4
| "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
| "$id": "https://ap2-protocol.org/schemas/receipt-status.json", | ||
| "title": "Receipt Status", |
Open Payment Mandates have no verify* counterpart today (only the Closed mandate verifiers exist), so no consumer can read back a mandate's own budget/allowed_payees/allowed_payment_instruments constraints without hand-rolling SD-JWT disclosure resolution. resolveOpenPaymentMandateContent parses and resolves an Open Payment Mandate presentation's content -- including per-array-element disclosures for payment.allowed_payees/payment.allowed_payment_instruments -- validates it against the Open Payment Mandate schema, and checks exp when present. It deliberately does not verify an issuer signature: Open Payment Mandates are signed by the User's key, which is generally a different key from the mandate's own cnf.jwk, so there is no single key this package can check the envelope against on its own -- a caller that independently knows the issuing key can verify it separately. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Brings
@docknetwork/ap2up to the current AP2 spec (v0.2), whichreplaced the old Cart/Intent/Payment Mandate model with two mandate
families — Checkout Mandate and Payment Mandate — each in an
Open and Closed state, secured as SD-JWTs with a
delegate_payloadenvelope rather than flat JSON-LD VCs.