@atlasauth/pca-ap2 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -60
- package/dist/chain.d.ts +217 -0
- package/dist/chain.js +366 -0
- package/dist/chain.js.map +1 -0
- package/dist/constraints.d.ts +61 -0
- package/dist/constraints.js +271 -0
- package/dist/constraints.js.map +1 -0
- package/dist/index.d.ts +14 -324
- package/dist/index.js +28 -354
- package/dist/index.js.map +1 -1
- package/dist/mandates.d.ts +140 -0
- package/dist/mandates.js +279 -0
- package/dist/mandates.js.map +1 -0
- package/dist/pca.d.ts +147 -0
- package/dist/pca.js +313 -0
- package/dist/pca.js.map +1 -0
- package/dist/sdjwt.d.ts +129 -0
- package/dist/sdjwt.js +394 -0
- package/dist/sdjwt.js.map +1 -0
- package/dist/settlement.d.ts +47 -0
- package/dist/settlement.js +91 -0
- package/dist/settlement.js.map +1 -0
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# @atlasauth/pca-ap2
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
AP2 (Agent Payments Protocol) mandates as real SD-JWT credentials, bound to a Proof-Carrying Authority (PCA) grant.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
AP2 models agentic payments as a chain of mandates: an open mandate signed by the user's trusted surface that delegates to an agent key and carries constraints, then a closed mandate signed by the agent that settles one concrete purchase. This package issues and verifies the checkout and payment mandates (`mandate.checkout.1`, `mandate.checkout.open.1`, `mandate.payment.1`, `mandate.payment.open.1`) in the SD-JWT format defined by the official AP2 JSON Schemas: integer minor-unit amounts, selective disclosure, ES256 (P-256) keys, and a key-binding JWT at each hop.
|
|
6
|
+
|
|
7
|
+
PCA governs: it decides who may spend, how much, until when, and when a human must co-sign. The AP2 mandates are the wire other parties verify, and each one carries PCA's proof of the grant (open mandate) or of the individual charge (closed payment mandate). Settlement rails (x402, Stripe Shared Payment Tokens) move the value.
|
|
6
8
|
|
|
7
9
|
## Install
|
|
8
10
|
|
|
@@ -10,73 +12,47 @@ PCA governs: it decides who may spend, how much, until when, and when a human mu
|
|
|
10
12
|
npm i @atlasauth/pca-ap2
|
|
11
13
|
```
|
|
12
14
|
|
|
13
|
-
Depends on `@atlasauth/pca` and `@atlasauth/pca-payments` (installed transitively; you will usually
|
|
14
|
-
|
|
15
|
-
##
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} from '@atlasauth/pca-ap2';
|
|
24
|
-
|
|
25
|
-
const principal = generateKeyPair(), merchantKey = generateKeyPair();
|
|
26
|
-
const payerKey = generateKeyPair(), agentKey = generateKeyPair();
|
|
27
|
-
const pub = (k: { publicKey: Uint8Array }) => encodeKey(k.publicKey);
|
|
28
|
-
|
|
29
|
-
// 1. A PCA payment mandate (the authority layer).
|
|
30
|
-
const mandate = buildPaymentMandate({
|
|
31
|
-
principalSecret: principal.secretKey, principalPublic: pub(principal), agentPublic: pub(agentKey),
|
|
32
|
-
merchants: ['acme'], currency: 'USD',
|
|
33
|
-
perTransactionCap: 500, autoApproveThreshold: 50, cumulativeCap: 1000,
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// 2. Map it down the AP2 chain; each step narrows, never widens.
|
|
37
|
-
const intent = toAP2IntentMandate(mandate, { issuerPublic: pub(principal), issuerSecret: principal.secretKey });
|
|
38
|
-
const cart = toAP2CartMandate(
|
|
39
|
-
intent,
|
|
40
|
-
{ merchant: 'acme', items: [{ sku: 'seat', name: 'Seat', quantity: 1, unit_price: { currency: 'USD', value: 120 } }] },
|
|
41
|
-
{ issuerPublic: pub(merchantKey), issuerSecret: merchantKey.secretKey },
|
|
42
|
-
);
|
|
43
|
-
const decision = authorizeCharge(mandate, { merchant: 'acme', amount: 120, currency: 'USD' }); // step-up, t = 3
|
|
44
|
-
const payment = toAP2PaymentMandate(cart, {
|
|
45
|
-
issuerPublic: pub(payerKey), issuerSecret: payerKey.secretKey,
|
|
46
|
-
paymentMethod: { type: 'card' }, pcaTier: decision.t, intent,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// 3. Verify the chain is a non-amplifying narrowing.
|
|
50
|
-
chainMandates(intent, cart, payment).verify(); // { ok: true, reasons: [] }
|
|
51
|
-
|
|
52
|
-
// 4. Parse back toward PCA terms.
|
|
53
|
-
fromAP2Mandate(intent); // { type: 'IntentMandate', merchants: ['acme'], perTransactionCap: 500, ... }
|
|
54
|
-
|
|
55
|
-
// 5. Build the rail's wire shape from the payment mandate (structural, no network).
|
|
56
|
-
x402Settlement.settle(payment, { resourceUrl: 'https://api.example.com/report', payTo: '0xabc', network: 'base' });
|
|
57
|
-
stripeSptSettlement.settle(payment, { payTo: 'acct_merchant' });
|
|
58
|
-
```
|
|
15
|
+
Depends on `@atlasauth/pca` and `@atlasauth/pca-payments` (installed transitively; you will usually build the PCA payment mandate with `buildPaymentMandate` from the latter).
|
|
16
|
+
|
|
17
|
+
## What it provides
|
|
18
|
+
|
|
19
|
+
- **Issue**: `issueOpenPaymentMandate`, `issueOpenCheckoutMandate`, `presentClosedCheckout`, `presentClosedPayment`; or from a PCA mandate directly, `openPaymentMandateFromPca` and `openCheckoutMandateFromPca`.
|
|
20
|
+
- **Verify**: `verifyCheckoutChain`, `verifyPaymentChain`, and `verifyPurchase` (checkout and payment verified together: the payment must reference the open checkout, settle the closed checkout's `checkout_hash`, and match the quoted payee, currency and total). A verifier must name its own audience and nonce.
|
|
21
|
+
- **Constraints**: `checkPaymentConstraints` and `checkCheckoutConstraints` evaluate amount ranges, allowed payees, budgets, recurrence, references and acceptable line items from the disclosed claims. A disclosure the agent withholds cannot widen an open mandate.
|
|
22
|
+
- **PCA binding**: `buildPcaPaymentBinding` and `verifyPcaBinding`.
|
|
23
|
+
- **Low level**: SD-JWT parsing and strict disclosure processing (`parseSdJwtHop`, `processDisclosures`, `splitChain`), schema-level validators (`paymentMandateProblems` and the three siblings), and `toMinorUnits` / `fromMinorUnits`.
|
|
24
|
+
- **Settlement shapes**: `x402Settlement`, `stripeSptSettlement` (the `SettlementBackend` interface).
|
|
59
25
|
|
|
60
|
-
|
|
26
|
+
## PCA binding
|
|
61
27
|
|
|
62
|
-
|
|
63
|
-
| --- | --- |
|
|
64
|
-
| tier 1: autonomous (within the auto-approve threshold and budget) | `false` |
|
|
65
|
-
| tier 3: human step-up or co-sign required | `true` |
|
|
28
|
+
The PCA proof travels inside the mandate as a namespaced `x_pca` claim, so it is covered by the issuer's or agent's signature and by the next hop's `sd_hash`:
|
|
66
29
|
|
|
67
|
-
|
|
30
|
+
| Mandate | `x_pca` | Meaning |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| open (checkout or payment) | `{ v, grant, terms }` | the principal-signed PCA grant and the terms it was minted from |
|
|
33
|
+
| closed payment | `{ v, charge, pcactn }` | the agent-signed PCA action proof that authorises exactly this charge |
|
|
68
34
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
35
|
+
The PCActn's signed nonce commits to the transaction id, payee, amount, instrument, the open mandate's `sd_hash` and the thumbprint of the agent's AP2 key, so replaying the proof under another mandate, charge or agent key fails. The official schemas do not forbid additional mandate claims and the reference SDK ignores unknown ones; both are tested, so `x_pca` does not affect schema validity or reference verification. Verifiers that do not know PCA simply ignore it. A charge above the auto-approve threshold carries a threshold co-signature in the PCActn.
|
|
36
|
+
|
|
37
|
+
`verifyPcaBinding` checks the grant signature and expected principal, that the `x_pca` terms agree with the grant envelope and with the AP2 constraints (AP2 constraints wider than the PCA terms are refused), the PCActn chain and signature, and the commitment above. When the charge's risk needs a threshold of t > 1, the `hooks.threshold` verifier must report that it enforced at least that `t` (build it with `createThresholdVerifier({ signerSet, t })`); a hook built for a smaller `t` is refused, as in the core verifier (breaking).
|
|
38
|
+
|
|
39
|
+
**The policy decision always runs on the verifier's own state (breaking).** `mandate` (the PCA mandate state you hold, with its live budget) is required, and `recentChargeTimes` (from your own records) is required when the mandate limits the charge count; otherwise `verifyPcaBinding` throws `PcaBindingError` (`mandate_required` / `charge_history_required`). The mandate must be bound to the verified grant (`authorizeCharge` refuses a different grant or terms), so the cumulative budget and the charge-count rate limit are always enforced.
|
|
72
40
|
|
|
73
41
|
## Status
|
|
74
42
|
|
|
75
|
-
Experimental
|
|
43
|
+
Experimental. Mandates are checked against the official AP2 JSON Schemas and documentation at github.com/google-agentic-commerce/AP2, commit `e1ea56db72a6385bce3e5c1112b3a56ce60acb43` (2026-04-29; still the head of `main` when this package was last updated). The schemas and example payloads are committed with source URLs and sha256.
|
|
44
|
+
|
|
45
|
+
What is verified, and how:
|
|
46
|
+
|
|
47
|
+
- Every mandate this package issues validates against the official schemas (Ajv, JSON Schema 2020-12).
|
|
48
|
+
- The six encoded SD-JWT examples in the AP2 documentation are parsed and re-serialised byte for byte; their disclosure digests, `sd_hash`, `checkout_hash`, `transaction_id` and payment reference recompute to the published values, and the closed hops' ES256 signatures (made by Google's reference code) verify under the open mandate's `cnf.jwk` with this verifier. The documentation never publishes the issuer key, so the documented open mandates' root signatures cannot be checked.
|
|
49
|
+
- Cross-implementation, in both directions: purchases issued here are accepted by Google's official AP2 Python SDK (`MandateClient`, payment and checkout chains) and by the independent `@sd-jwt/core` library; purchases issued by the official SDK are verified here with the real root signature.
|
|
50
|
+
- The documentation's decoded JSON blocks differ from its encoded tokens; the encoded tokens are treated as the source of truth.
|
|
51
|
+
- Adversarial tests: an exhaustive single-character mutation of a valid purchase is never accepted, structure fuzzing never throws or accepts, and withheld disclosures cannot widen an open mandate. Where this package is stricter than the reference SDK (for example acceptable-items, quantities and budgets) the tests say so.
|
|
76
52
|
|
|
77
|
-
|
|
53
|
+
Limits: only the P-256/ES256 and SHA-2 `_sd_alg` paths are implemented. Payment budgets are converted from major units the way the AP2 SDK does (a fixed x100), so they are refused for currencies whose exponent is not 2. Issuer key trust (`kid` / `x5c` resolution) is the caller's job. The cryptography is unaudited.
|
|
78
54
|
|
|
79
|
-
The settlement backends are structural only: they turn a payment mandate into an x402 HTTP-402 challenge or a Stripe Shared-Payment-Token charge shape
|
|
55
|
+
The settlement backends are structural only: they turn a payment mandate into an x402 HTTP-402 challenge or a Stripe Shared-Payment-Token charge shape and perform no network I/O. The x402 output is checked against the x402 v1 specification (field set, atomic-unit `maxAmountRequired`, `maxTimeoutSeconds`, standard-base64 `X-PAYMENT`); the `X-PAYMENT` payload is a placeholder envelope, not a signed authorization, and `asset` should be supplied as the token contract address. The Stripe shape has no official vector behind it. Settlement backends assume the mandate has already been verified.
|
|
80
56
|
|
|
81
57
|
## License
|
|
82
58
|
|
package/dist/chain.d.ts
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AP2 mandate issuance, presentation and verification.
|
|
3
|
+
*
|
|
4
|
+
* Wire format (AP2 `docs/ap2`, `ap2.sdk.sdjwt`): a mandate is the single object in an SD-JWT's
|
|
5
|
+
* `delegate_payload` array, itself an array-element disclosure. An *open* mandate is signed by the
|
|
6
|
+
* issuer (the user's trusted surface / agent provider) and names the agent's key in `cnf.jwk`. A
|
|
7
|
+
* *closed* mandate is a KB-SD-JWT hop (`typ: kb+sd-jwt`) signed by that agent key, carrying `iat`,
|
|
8
|
+
* `aud`, `nonce` and an `sd_hash` over the preceding hop. Hops are joined by `~~`. That hop is AP2's
|
|
9
|
+
* key-binding mechanism; no trailing RFC 9901 KB-JWT is used or accepted.
|
|
10
|
+
*/
|
|
11
|
+
import type { KeyObject } from 'node:crypto';
|
|
12
|
+
import { type JsonObject, type JwtHeader, type P256Jwk, type SdAlg, type SdJwtHop } from './sdjwt';
|
|
13
|
+
import { type CheckoutConstraint, type CheckoutMandateClaims, type Merchant, type OpenCheckoutMandateClaims, type OpenPaymentMandateClaims, type PaymentConstraint, type PaymentInstrument, type PaymentMandateClaims, type Pisp } from './mandates';
|
|
14
|
+
import { type MandateContext, type UcpCheckout } from './constraints';
|
|
15
|
+
/** The signer of an open mandate: the user's trusted surface or agent provider (an ES256 key). */
|
|
16
|
+
export interface MandateIssuer {
|
|
17
|
+
privateKey: KeyObject;
|
|
18
|
+
/** `kid` header; a verifier's key resolver maps it to the public key. */
|
|
19
|
+
kid?: string;
|
|
20
|
+
/** Optional `x5c` header (base64 DER certificates); chain validation is the resolver's job. */
|
|
21
|
+
x5c?: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface OpenMandateCommon {
|
|
24
|
+
issuer: MandateIssuer;
|
|
25
|
+
/** The agent's public key; becomes `cnf.jwk` and is the only key that can sign the closed mandate. */
|
|
26
|
+
agentJwk: P256Jwk;
|
|
27
|
+
/** Issued-at, epoch seconds. */
|
|
28
|
+
iat: number;
|
|
29
|
+
/** Expiry, epoch seconds (required: an open mandate must be bounded in time). */
|
|
30
|
+
exp: number;
|
|
31
|
+
/** `x_pca` claim (PCA's proof of the grant); see `pca.ts`. */
|
|
32
|
+
pca?: JsonObject;
|
|
33
|
+
sdAlg?: SdAlg;
|
|
34
|
+
/** Salt source (tests inject a deterministic one). */
|
|
35
|
+
salt?: () => string;
|
|
36
|
+
/** Root `typ` header; the reference SDK imposes none. */
|
|
37
|
+
typ?: string;
|
|
38
|
+
}
|
|
39
|
+
export interface OpenPaymentMandateInput extends OpenMandateCommon {
|
|
40
|
+
constraints: PaymentConstraint[];
|
|
41
|
+
payee?: Merchant;
|
|
42
|
+
paymentAmount?: {
|
|
43
|
+
amount: number;
|
|
44
|
+
currency: string;
|
|
45
|
+
};
|
|
46
|
+
paymentInstrument?: PaymentInstrument;
|
|
47
|
+
pisp?: Pisp;
|
|
48
|
+
executionDate?: string;
|
|
49
|
+
}
|
|
50
|
+
/** Issue an open Payment Mandate (`mandate.payment.open.1`) as a signed SD-JWT. */
|
|
51
|
+
export declare function issueOpenPaymentMandate(input: OpenPaymentMandateInput): string;
|
|
52
|
+
export interface OpenCheckoutMandateInput extends OpenMandateCommon {
|
|
53
|
+
constraints: CheckoutConstraint[];
|
|
54
|
+
}
|
|
55
|
+
/** Issue an open Checkout Mandate (`mandate.checkout.open.1`) as a signed SD-JWT. */
|
|
56
|
+
export declare function issueOpenCheckoutMandate(input: OpenCheckoutMandateInput): string;
|
|
57
|
+
export interface ClosedHopCommon {
|
|
58
|
+
/** The preceding token (an open mandate, or a chain ending in an intermediate hop). */
|
|
59
|
+
open: string;
|
|
60
|
+
/** The agent's key pair: its public key must be the open mandate's `cnf.jwk`. */
|
|
61
|
+
agentKey: {
|
|
62
|
+
privateKey: KeyObject;
|
|
63
|
+
publicJwk: P256Jwk;
|
|
64
|
+
};
|
|
65
|
+
/** Audience of this hop (the merchant for a checkout, the credential provider for a payment). */
|
|
66
|
+
aud: string;
|
|
67
|
+
/** Verifier-supplied nonce; the verifier checks it on receipt. */
|
|
68
|
+
nonce: string;
|
|
69
|
+
/** Issued-at, epoch seconds. */
|
|
70
|
+
iat: number;
|
|
71
|
+
/** Optional mandate-level expiry, epoch seconds. */
|
|
72
|
+
exp?: number;
|
|
73
|
+
pca?: JsonObject;
|
|
74
|
+
/** Binding claim: `sd_hash` (default; pins the preceding hop's disclosures) or `issuer_jwt_hash`. */
|
|
75
|
+
hashMode?: 'sd_hash' | 'issuer_jwt_hash';
|
|
76
|
+
salt?: () => string;
|
|
77
|
+
}
|
|
78
|
+
export interface ClosedPaymentInput extends ClosedHopCommon {
|
|
79
|
+
/** Hash of the closed checkout's `checkout_jwt` (= the closed checkout mandate's `checkout_hash`). */
|
|
80
|
+
transactionId: string;
|
|
81
|
+
payee: Merchant;
|
|
82
|
+
paymentAmount: {
|
|
83
|
+
amount: number;
|
|
84
|
+
currency: string;
|
|
85
|
+
};
|
|
86
|
+
paymentInstrument: PaymentInstrument;
|
|
87
|
+
pisp?: Pisp;
|
|
88
|
+
executionDate?: string;
|
|
89
|
+
riskData?: JsonObject;
|
|
90
|
+
}
|
|
91
|
+
/** Present a closed Payment Mandate (`mandate.payment.1`) on top of an open payment mandate. */
|
|
92
|
+
export declare function presentClosedPayment(input: ClosedPaymentInput): string;
|
|
93
|
+
export interface ClosedCheckoutInput extends ClosedHopCommon {
|
|
94
|
+
/** The merchant-signed checkout JWT (compact). */
|
|
95
|
+
checkoutJwt: string;
|
|
96
|
+
}
|
|
97
|
+
/** Present a closed Checkout Mandate (`mandate.checkout.1`) on top of an open checkout mandate. */
|
|
98
|
+
export declare function presentClosedCheckout(input: ClosedCheckoutInput): string;
|
|
99
|
+
export declare const TYP_TERMINAL: readonly string[];
|
|
100
|
+
export declare const TYP_INTERMEDIATE: readonly string[];
|
|
101
|
+
export interface VerifiedHop {
|
|
102
|
+
index: number;
|
|
103
|
+
kind: 'root' | 'intermediate' | 'terminal';
|
|
104
|
+
hop: SdJwtHop;
|
|
105
|
+
/** Hop-level claims after disclosure processing. */
|
|
106
|
+
claims: JsonObject;
|
|
107
|
+
/** The single mandate object disclosed in `delegate_payload`. */
|
|
108
|
+
mandate: JsonObject;
|
|
109
|
+
}
|
|
110
|
+
export interface VerifyChainOptions {
|
|
111
|
+
/** Resolve the root hop's public key from its header (`kid` / `x5c`); return undefined to refuse. */
|
|
112
|
+
resolveIssuerKey: (header: JwtHeader) => P256Jwk | undefined;
|
|
113
|
+
/** The terminal hop's `aud` must equal this. Required: a verifier that does not name itself cannot detect redirection. */
|
|
114
|
+
expectedAudience: string;
|
|
115
|
+
/** The terminal hop's `nonce` must equal this. Required: it is the replay defence. */
|
|
116
|
+
expectedNonce: string;
|
|
117
|
+
/** Verification time, epoch seconds (default: now). */
|
|
118
|
+
now?: number;
|
|
119
|
+
/** Tolerated clock skew in seconds (default 60). */
|
|
120
|
+
clockSkewSeconds?: number;
|
|
121
|
+
}
|
|
122
|
+
export type ChainResult = {
|
|
123
|
+
ok: true;
|
|
124
|
+
hops: VerifiedHop[];
|
|
125
|
+
} | {
|
|
126
|
+
ok: false;
|
|
127
|
+
reason: string;
|
|
128
|
+
};
|
|
129
|
+
/** Split a `~~`-joined chain into hops, each restored to `<jwt>~<d>...~`. */
|
|
130
|
+
export declare function splitChain(token: string): string[];
|
|
131
|
+
/** Verify one key-binding hop against its predecessor (signature, typ, binding hash, times, aud/nonce). */
|
|
132
|
+
export declare function verifyKbHop(hop: SdJwtHop, prev: {
|
|
133
|
+
hop: SdJwtHop;
|
|
134
|
+
mandate: JsonObject;
|
|
135
|
+
}, o: {
|
|
136
|
+
terminal: boolean;
|
|
137
|
+
expectedAudience?: string;
|
|
138
|
+
expectedNonce?: string;
|
|
139
|
+
now: number;
|
|
140
|
+
skew: number;
|
|
141
|
+
}, label: string): VerifiedHop;
|
|
142
|
+
/** Verify a whole chain: root signature, then every hop in order. Never throws; reports the reason. */
|
|
143
|
+
export declare function verifyDelegationChain(token: string, o: VerifyChainOptions): ChainResult;
|
|
144
|
+
export type CheckoutChainResult = {
|
|
145
|
+
ok: true;
|
|
146
|
+
open: OpenCheckoutMandateClaims;
|
|
147
|
+
closed: CheckoutMandateClaims;
|
|
148
|
+
checkoutJwt: string;
|
|
149
|
+
checkout: UcpCheckout;
|
|
150
|
+
/** `sd_hash` of the open checkout mandate token: the value an open payment mandate's `payment.reference` must hold. */
|
|
151
|
+
openHash: string;
|
|
152
|
+
hops: VerifiedHop[];
|
|
153
|
+
} | {
|
|
154
|
+
ok: false;
|
|
155
|
+
reason: string;
|
|
156
|
+
violations?: string[];
|
|
157
|
+
};
|
|
158
|
+
export interface VerifyCheckoutOptions extends VerifyChainOptions {
|
|
159
|
+
/** Resolve the merchant's key for the `checkout_jwt` signature; return undefined to refuse. */
|
|
160
|
+
resolveMerchantKey: (header: JwtHeader) => P256Jwk | undefined;
|
|
161
|
+
}
|
|
162
|
+
/** Verify an open+closed checkout chain, the merchant-signed checkout, its hash, and the open constraints. */
|
|
163
|
+
export declare function verifyCheckoutChain(token: string, o: VerifyCheckoutOptions): CheckoutChainResult;
|
|
164
|
+
export type PaymentChainResult = {
|
|
165
|
+
ok: true;
|
|
166
|
+
open: OpenPaymentMandateClaims;
|
|
167
|
+
closed: PaymentMandateClaims;
|
|
168
|
+
openHash: string;
|
|
169
|
+
hops: VerifiedHop[];
|
|
170
|
+
} | {
|
|
171
|
+
ok: false;
|
|
172
|
+
reason: string;
|
|
173
|
+
violations?: string[];
|
|
174
|
+
};
|
|
175
|
+
export interface VerifyPaymentOptions extends VerifyChainOptions {
|
|
176
|
+
/** `sd_hash` of the open checkout mandate (from `verifyCheckoutChain().openHash`); checked against `payment.reference`. */
|
|
177
|
+
openCheckoutHash: string;
|
|
178
|
+
/** Usage state under this open mandate (needed for `payment.budget` and recurrence). */
|
|
179
|
+
context?: MandateContext;
|
|
180
|
+
/** The `checkout_hash` this payment must settle (from the closed checkout mandate). */
|
|
181
|
+
expectedTransactionId?: string;
|
|
182
|
+
}
|
|
183
|
+
/** Verify an open+closed payment chain and every open payment constraint. */
|
|
184
|
+
export declare function verifyPaymentChain(token: string, o: VerifyPaymentOptions): PaymentChainResult;
|
|
185
|
+
export interface VerifyPurchaseOptions {
|
|
186
|
+
resolveIssuerKey: VerifyChainOptions['resolveIssuerKey'];
|
|
187
|
+
resolveMerchantKey: VerifyCheckoutOptions['resolveMerchantKey'];
|
|
188
|
+
checkout: {
|
|
189
|
+
expectedAudience: string;
|
|
190
|
+
expectedNonce: string;
|
|
191
|
+
};
|
|
192
|
+
payment: {
|
|
193
|
+
expectedAudience: string;
|
|
194
|
+
expectedNonce: string;
|
|
195
|
+
};
|
|
196
|
+
context?: MandateContext;
|
|
197
|
+
now?: number;
|
|
198
|
+
clockSkewSeconds?: number;
|
|
199
|
+
}
|
|
200
|
+
export type PurchaseResult = {
|
|
201
|
+
ok: true;
|
|
202
|
+
checkout: Extract<CheckoutChainResult, {
|
|
203
|
+
ok: true;
|
|
204
|
+
}>;
|
|
205
|
+
payment: Extract<PaymentChainResult, {
|
|
206
|
+
ok: true;
|
|
207
|
+
}>;
|
|
208
|
+
} | {
|
|
209
|
+
ok: false;
|
|
210
|
+
reason: string;
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* Verify a complete purchase: the checkout chain, then the payment chain bound to it (the payment's
|
|
214
|
+
* `payment.reference` is the open checkout hash; its `transaction_id` is the closed checkout's
|
|
215
|
+
* `checkout_hash`), and that the payment settles what the merchant quoted (payee, currency, total).
|
|
216
|
+
*/
|
|
217
|
+
export declare function verifyPurchase(checkoutToken: string, paymentToken: string, o: VerifyPurchaseOptions): PurchaseResult;
|