@reactionary/acp 0.10.42 → 0.10.43

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.
@@ -0,0 +1,48 @@
1
+ /** An agent's order webhook receiver and the secret shared with it. */
2
+ export interface ACPWebhookEndpoint {
3
+ /** e.g. the agent's `.../agentic_checkout/webhooks/order_events` URL. */
4
+ url: string;
5
+ /** Shared secret for the `Merchant-Signature` HMAC. */
6
+ secret: string;
7
+ /**
8
+ * The authenticated agent (see `authenticate`) whose orders go to this
9
+ * endpoint. Endpoints without one receive orders of every agent that has
10
+ * no endpoint of its own.
11
+ */
12
+ agentId?: string;
13
+ }
14
+ export interface ACPWebhookOptions {
15
+ endpoints: ACPWebhookEndpoint[];
16
+ /**
17
+ * Delays before each retry of a failed delivery. Retries are held in
18
+ * memory, so they do not survive a restart. Defaults to 0.5s, 2s, 10s, 1m
19
+ * and 5m.
20
+ */
21
+ retryDelaysMs?: number[];
22
+ /** Accepts `http:` endpoint URLs; intended for test environments. */
23
+ allowInsecureUrls?: boolean;
24
+ /** Fetch implementation; defaults to the global fetch. */
25
+ fetch?: typeof fetch;
26
+ }
27
+ export type ACPOrderEventType = 'order_create' | 'order_update';
28
+ /**
29
+ * Delivers order lifecycle events to agents' webhook receivers (checkout
30
+ * RFC §2.3), signed with `Merchant-Signature: t=<unix>,v1=<hex>` over
31
+ * `timestamp + "." + body` (HMAC-SHA256). Failed deliveries are retried as
32
+ * the same event, with a fresh timestamp and signature, as in the UCP
33
+ * adapter.
34
+ */
35
+ export declare class ACPOrderWebhooks {
36
+ private readonly options;
37
+ private readonly retryDelaysMs;
38
+ private readonly fetchImpl;
39
+ constructor(options: ACPWebhookOptions);
40
+ /** The endpoint for an agent's orders, if any. */
41
+ getEndpoint(agentId: string | undefined): ACPWebhookEndpoint | undefined;
42
+ /** Sends an event without waiting for it; the order is the full current state. */
43
+ deliver(endpoint: ACPWebhookEndpoint, type: ACPOrderEventType, order: object): void;
44
+ private attempt;
45
+ private isAllowedUrl;
46
+ }
47
+ /** `t=<unix seconds>,v1=<hex HMAC-SHA256 of "t.body">`, as receivers verify. */
48
+ export declare function signWebhookPayload(body: string, secret: string, timestamp?: number): string;
@@ -1,36 +1,38 @@
1
- import { type Cache, type Cart, type Checkout, type Inventory, type LanguageContext, type PaymentMethod, type Price, type Product, type ProductSearchResult, type RequestContext, type Result, type SearchIdentifier, type ShippingMethod } from '@reactionary/core';
2
- import { type ReactionaryFeedInventoryOptions, type ReactionaryFeedProcessingOptions } from '@reactionary/feeds';
1
+ import { type Cache, type Cart, type Checkout, type Inventory, type Order, type MonetaryAmount, type PaymentMethod, type Product, type RequestContext, type Result, type ShippingMethod } from '@reactionary/core';
3
2
  import type { IncomingMessage, ServerResponse } from 'node:http';
3
+ import { type ACPAffiliateAttribution, type ACPIntentTrace, type ACPAddress, type ACPAuthenticationMetadata, type ACPInterventionType, type ACPPaymentData } from './acp-schemas.js';
4
+ import { type ACPWebhookOptions } from './acp-webhooks.js';
5
+ import { type ACPPaymentHandler, type ACPPaymentHandlerOption } from './acp-payment-handlers.js';
4
6
  export interface ReactionaryACPClient {
5
7
  cart?: {
6
8
  createCart(payload: unknown): Promise<Result<Cart>>;
7
9
  add(payload: unknown): Promise<Result<Cart>>;
8
10
  getById(payload: unknown): Promise<Result<Cart>>;
9
11
  deleteCart?(payload: unknown): Promise<Result<void>>;
12
+ applyCouponCode?(payload: unknown): Promise<Result<Cart>>;
13
+ removeCouponCode?(payload: unknown): Promise<Result<Cart>>;
14
+ changeQuantity?(payload: unknown): Promise<Result<Cart>>;
15
+ remove?(payload: unknown): Promise<Result<Cart>>;
10
16
  };
11
17
  checkout?: {
12
18
  initiateCheckoutForCart(payload: unknown): Promise<Result<Checkout>>;
13
19
  getById(payload: unknown): Promise<Result<Checkout>>;
14
20
  setShippingAddress(payload: unknown): Promise<Result<Checkout>>;
15
21
  getAvailableShippingMethods(payload: unknown): Promise<Result<ShippingMethod[]>>;
16
- getAvailablePaymentMethods(payload: unknown): Promise<Result<PaymentMethod[]>>;
22
+ getAvailablePaymentMethods?(payload: unknown): Promise<Result<PaymentMethod[]>>;
17
23
  setShippingInstruction(payload: unknown): Promise<Result<Checkout>>;
18
24
  addPaymentInstruction(payload: unknown): Promise<Result<Checkout>>;
19
25
  finalizeCheckout(payload: unknown): Promise<Result<Checkout>>;
20
26
  };
21
- productSearch?: {
22
- queryByTerm(payload: unknown): Promise<Result<ProductSearchResult>>;
23
- };
24
27
  product?: {
25
28
  getBySKU(payload: unknown): Promise<Result<Product>>;
26
29
  };
27
- price?: {
28
- getListPrice(payload: unknown): Promise<Result<Price>>;
29
- getCustomerPrice(payload: unknown): Promise<Result<Price>>;
30
- };
31
30
  inventory?: {
32
31
  getBySKU(payload: unknown): Promise<Result<Inventory>>;
33
32
  };
33
+ order?: {
34
+ getById(payload: unknown): Promise<Result<Order>>;
35
+ };
34
36
  }
35
37
  export type ReactionaryACPClientFactory<TClient extends ReactionaryACPClient = ReactionaryACPClient> = (requestContext: RequestContext) => TClient;
36
38
  export interface ReactionaryACPServerOptions {
@@ -39,24 +41,219 @@ export interface ReactionaryACPServerOptions {
39
41
  basePath?: string;
40
42
  sessionCache?: Cache;
41
43
  sessionTtlSeconds?: number;
44
+ /**
45
+ * How long orders placed through ACP are remembered for order updates
46
+ * (`notifyOrderUpdated`). Defaults to 90 days.
47
+ */
48
+ orderTtlSeconds?: number;
49
+ /**
50
+ * How long Idempotency-Key responses are kept for replay. At least, and by
51
+ * default, 24 hours (checkout RFC §6.6).
52
+ */
53
+ idempotencyTtlSeconds?: number;
42
54
  checkoutSessionTtlSeconds?: number;
43
- paymentProvider?: ACPPaymentProvider;
55
+ /**
56
+ * Authenticates agents on checkout endpoints, e.g. by their
57
+ * `Authorization: Bearer` token (see `createBearerTokenAuthenticator`) or a
58
+ * request signature. Returning undefined answers 401. Checkout sessions are
59
+ * visible only to the agent that created them. Unset, checkout endpoints
60
+ * are open — the server logs a warning, as ACP requires authentication.
61
+ */
62
+ authenticate?: (request: Request) => ACPAgent | undefined | Promise<ACPAgent | undefined>;
63
+ /**
64
+ * The buyer-facing order page, as a URL template with an `{orderId}`
65
+ * placeholder, e.g. `https://shop.example/account/orders/{orderId}`. Orders
66
+ * MUST carry a permalink; without this option it is left out and a warning
67
+ * is logged.
68
+ */
69
+ orderPermalinkUrl?: string;
70
+ /**
71
+ * Asks for 3D Secure authentication: returning metadata makes completion
72
+ * answer `authentication_required` until the agent completes again with an
73
+ * `authentication_result`, which is passed to the backend's payment
74
+ * integration as protocol data `acp_authentication_result`. Advertise
75
+ * `3ds` in `interventions.supported` for agents to know.
76
+ */
77
+ authentication?: ACPAuthenticationOptions;
78
+ /**
79
+ * Receives an order's affiliate attribution (first touch from session
80
+ * creation, last touch from completion) once the order exists, for the
81
+ * affiliate network. Attribution is write-only: never returned to agents
82
+ * or sent in webhooks.
83
+ */
84
+ onOrderAttribution?: (attribution: {
85
+ orderId: string;
86
+ checkoutSessionId: string;
87
+ agentId?: string;
88
+ firstTouch?: ACPAffiliateAttribution;
89
+ lastTouch?: ACPAffiliateAttribution;
90
+ }) => void | Promise<void>;
91
+ /**
92
+ * Marketing consent (marketing consent RFC): channels offered to the
93
+ * buyer on every session, and where the buyer's decisions go once the
94
+ * order exists. Unset, no consent is offered.
95
+ */
96
+ marketingConsent?: ACPMarketingConsentOptions;
97
+ /**
98
+ * Receives the agent's reason for canceling a session (intent traces),
99
+ * e.g. for conversion analytics. Traces are also kept on the session state
100
+ * but never returned to agents.
101
+ */
102
+ onIntentTrace?: (trace: ACPIntentTrace, context: {
103
+ checkoutSessionId: string;
104
+ agentId?: string;
105
+ }) => void | Promise<void>;
106
+ /**
107
+ * Classifies backend shipping methods into ACP fulfillment types, e.g.
108
+ * click-and-collect methods as `pickup` with their location. Methods are
109
+ * `shipping` by default, as core shipping methods carry no type.
110
+ */
111
+ classifyFulfillmentOption?: (method: ShippingMethod) => ACPFulfillmentClassification | undefined;
112
+ /**
113
+ * The URL where the buyer can continue the checkout on the merchant's
114
+ * site, as a template with a `{checkoutSessionId}` placeholder.
115
+ */
116
+ continueUrl?: string;
117
+ /**
118
+ * Serves the ACP MCP transport binding at `{basePath}/mcp`: the checkout
119
+ * tools over JSON-RPC 2.0 (Streamable HTTP), dispatched to the REST
120
+ * handlers with the connection's Authorization. Discovery then lists the
121
+ * `mcp` transport.
122
+ */
123
+ mcp?: boolean;
124
+ /**
125
+ * Sends signed order events (`order_create` on placement, `order_update`
126
+ * via `notifyOrderUpdated`) to the agents' webhook receivers, as ACP
127
+ * requires. Needs the client's `order.getById`. Unset, no webhooks are
128
+ * sent and a warning is logged.
129
+ */
130
+ webhooks?: ACPWebhookOptions;
131
+ /**
132
+ * Payment handlers advertised in `capabilities.payment.handlers`, e.g.
133
+ * `createTokenizedCardHandler(...)`. Each maps to the backend payment
134
+ * method its payments are placed with.
135
+ */
136
+ paymentHandlers?: ACPPaymentHandlerOption[];
137
+ /**
138
+ * Accepts raw card credentials (anything carrying a card number or CVC)
139
+ * and forwards them to the backend's payment integration, which persists
140
+ * payment data — putting the deployment in PCI DSS scope. Off by default:
141
+ * such completions are rejected, as handlers are expected to submit
142
+ * delegated tokens.
143
+ */
144
+ acceptRawCardCredentials?: boolean;
44
145
  links?: ACPLink[];
45
- productFeed?: ACPProductFeedOptions;
46
146
  discovery?: ACPDiscoveryOptions;
47
147
  /**
48
148
  * Email used to price transient checkouts before the buyer has supplied
49
149
  * one. Never used for the real checkout created on completion.
50
150
  */
51
151
  placeholderEmail?: string;
152
+ /**
153
+ * The interventions (e.g. 3DS) this seller can handle, and which it
154
+ * requires. Sessions report the intersection with what the agent declared.
155
+ * Defaults to none supported and none required.
156
+ */
157
+ interventions?: ACPInterventionOptions;
158
+ /**
159
+ * Whether orders need a fulfillment option. When the backend offers none
160
+ * for an address, the session cannot become payable. Defaults to true;
161
+ * disable it for stores selling only goods that need no shipping.
162
+ */
163
+ requireFulfillment?: boolean;
164
+ /**
165
+ * Checks line items against these fulfillment centers' combined stock,
166
+ * reporting `out_of_stock` per line item. Unset, stock is left to the
167
+ * backend.
168
+ */
169
+ inventory?: ACPInventoryOptions;
52
170
  /**
53
171
  * How long checkout completion waits for the placed checkout to become
54
172
  * `readyForFinalization` (i.e. its payment authorized, e.g. by a PSP
55
- * webhook) before answering `in_progress`. Defaults to 10s timeout,
173
+ * webhook) before answering `complete_in_progress`. Defaults to 10s timeout,
56
174
  * polled every 1s; a timeout of 0 disables it.
57
175
  */
58
176
  paymentAuthorizationWait?: Partial<ACPPaymentAuthorizationWait>;
59
177
  }
178
+ export interface ACPInventoryOptions {
179
+ fulfillmentCenterKeys: string[];
180
+ }
181
+ export interface ACPAuthenticationOptions {
182
+ getMetadata(context: {
183
+ checkoutSessionId: string;
184
+ handler: ACPPaymentHandler;
185
+ instrument: ACPPaymentData['instrument'];
186
+ amount: MonetaryAmount;
187
+ }): ACPAuthenticationMetadata | undefined | Promise<ACPAuthenticationMetadata | undefined>;
188
+ }
189
+ export interface ACPMarketingConsentChannel {
190
+ /** e.g. `email`, `sms`, `whatsapp`. */
191
+ channel: string;
192
+ /** What the buyer consents to receive. */
193
+ display_text: string;
194
+ privacy_policy_url: string;
195
+ }
196
+ export interface ACPMarketingConsentOptions {
197
+ channels: ACPMarketingConsentChannel[];
198
+ /**
199
+ * Whether the contact is already subscribed on the channel, so agents
200
+ * pre-check the box. Defaults to not subscribed.
201
+ */
202
+ isSubscribed?(contact: string, channel: string): boolean | Promise<boolean>;
203
+ /**
204
+ * Receives the buyer's decisions for offered channels, with the contact
205
+ * they apply to. Channels the agent did not surface are left out, which
206
+ * preserves their current state.
207
+ */
208
+ onConsents(consents: Array<{
209
+ channel: string;
210
+ opted_in: boolean;
211
+ contact: string;
212
+ }>, context: {
213
+ orderId: string;
214
+ checkoutSessionId: string;
215
+ agentId?: string;
216
+ }): void | Promise<void>;
217
+ }
218
+ /** An ACP fulfillment option type with its type-specific details. */
219
+ export type ACPFulfillmentClassification = {
220
+ type: 'shipping';
221
+ } | {
222
+ type: 'digital';
223
+ } | {
224
+ type: 'pickup';
225
+ location: {
226
+ name: string;
227
+ address: ACPAddress;
228
+ phone?: string;
229
+ instructions?: string;
230
+ };
231
+ pickup_type?: 'in_store' | 'curbside' | 'locker';
232
+ ready_by?: string;
233
+ pickup_by?: string;
234
+ } | {
235
+ type: 'local_delivery';
236
+ delivery_window?: {
237
+ start: string;
238
+ end: string;
239
+ };
240
+ service_area?: Record<string, unknown>;
241
+ };
242
+ /** An authenticated agent (platform) calling the checkout API. */
243
+ export interface ACPAgent {
244
+ id: string;
245
+ }
246
+ /**
247
+ * Authenticates agents by `Authorization: Bearer <token>`, given each
248
+ * agent's token. Tokens are compared in constant time.
249
+ */
250
+ export declare function createBearerTokenAuthenticator(tokensByAgentId: Record<string, string>): (request: Request) => ACPAgent | undefined;
251
+ export interface ACPInterventionOptions {
252
+ supported: ACPInterventionType[];
253
+ required?: Array<'3ds' | 'biometric'>;
254
+ /** When required interventions apply. Defaults to `conditional`. */
255
+ enforcement?: 'always' | 'conditional' | 'optional';
256
+ }
60
257
  export declare const DEFAULT_ACP_PLACEHOLDER_EMAIL = "pending@checkout.invalid";
61
258
  export interface ACPPaymentAuthorizationWait {
62
259
  timeoutMs: number;
@@ -64,11 +261,14 @@ export interface ACPPaymentAuthorizationWait {
64
261
  }
65
262
  export declare const DEFAULT_ACP_PAYMENT_AUTHORIZATION_WAIT: ACPPaymentAuthorizationWait;
66
263
  export interface ACPDiscoveryOptions {
67
- apiVersion?: string;
68
- supportedVersions?: string[];
69
264
  apiBaseUrl?: string;
70
265
  documentationUrl?: string;
71
266
  supportedCurrencies?: string[];
267
+ /**
268
+ * BCP 47 locales the backend can localize for. Advertised in discovery,
269
+ * and checkout requests are localized to the best match of their
270
+ * Accept-Language.
271
+ */
72
272
  supportedLocales?: string[];
73
273
  }
74
274
  export interface ACPDiscoveryResponse {
@@ -79,34 +279,30 @@ export interface ACPDiscoveryResponse {
79
279
  documentation_url?: string;
80
280
  };
81
281
  api_base_url: string;
82
- transports: ['rest'];
282
+ transports: Array<'rest' | 'mcp'>;
83
283
  capabilities: {
84
- services: Array<'checkout' | 'feeds'>;
284
+ services: Array<'checkout' | 'orders' | 'delegate_payment' | 'carts'>;
285
+ extensions?: ACPDiscoveryExtension[];
286
+ intervention_types?: ACPInterventionType[];
85
287
  supported_currencies?: string[];
86
288
  supported_locales?: string[];
87
289
  };
88
290
  }
89
- export type ACPPaymentProcessor = 'stripe' | 'adyen' | 'braintree';
90
- export interface ACPPaymentProvider {
91
- provider: ACPPaymentProcessor;
92
- supported_payment_methods: ['card'];
291
+ /** An extension the seller supports, as listed in discovery. */
292
+ export interface ACPDiscoveryExtension {
293
+ name: string;
294
+ spec?: string;
295
+ schema?: string;
93
296
  }
297
+ /** The only ACP API version this adapter implements. */
298
+ export declare const ACP_API_VERSION = "2026-04-17";
299
+ /** A policy or support link shown with the checkout (2026-04-17 Link). */
94
300
  export interface ACPLink {
95
- type: 'terms_of_use' | 'privacy_policy' | 'seller_shop_policies';
301
+ type: 'terms_of_use' | 'privacy_policy' | 'return_policy' | 'shipping_policy' | 'contact_us' | 'about_us' | 'faq' | 'support';
302
+ /** Display text for the link. */
303
+ title?: string;
96
304
  url: string;
97
305
  }
98
- export interface ACPProductFeedOptions extends ReactionaryFeedInventoryOptions, ReactionaryFeedProcessingOptions {
99
- feeds: Record<string, ACPProductFeedDefinition>;
100
- }
101
- export interface ACPProductFeedDefinition {
102
- languageContext: LanguageContext;
103
- search: SearchIdentifier;
104
- pageSize?: number;
105
- maxPages?: number;
106
- productUrlBase?: string;
107
- fulfillmentCenterKeys?: string[];
108
- fulfillmentCenterKey?: string;
109
- }
110
306
  export interface ReactionaryACPHttpHandler {
111
307
  fetch(request: Request): Promise<Response>;
112
308
  close(): Promise<void>;
@@ -117,36 +313,81 @@ export declare class ReactionaryACPServer<TClient extends ReactionaryACPClient =
117
313
  private readonly options;
118
314
  private readonly sessionStore;
119
315
  private readonly checkoutSessionStore;
316
+ private readonly idempotency;
317
+ private readonly webhooks;
318
+ private readonly supportsDiscounts;
319
+ private readonly mcp;
120
320
  constructor(clientFactory: ReactionaryACPClientFactory<TClient>, options?: ReactionaryACPServerOptions);
121
321
  fetch(request: Request): Promise<Response>;
122
322
  private handleFetch;
323
+ /**
324
+ * Checkout endpoints require an authenticated agent (checkout RFC §3.1),
325
+ * and a checkout session is visible only to the agent that created it, so
326
+ * another agent's session is reported as missing. Discovery and the
327
+ * readiness document stay public.
328
+ */
329
+ private authenticate;
123
330
  /**
124
331
  * Requests addressing a checkout session resume the session that created
125
332
  * it: agents need not echo the ACP session header, but backends scope carts
126
333
  * to that session's (anonymous) identity.
127
334
  */
128
335
  private resolveSessionId;
336
+ /**
337
+ * The best supported locale for the request's Accept-Language: an exact
338
+ * tag, else one of the same language. Only locales advertised in
339
+ * `discovery.supportedLocales` are used, as backends may not localize
340
+ * others.
341
+ */
342
+ private resolveLocale;
343
+ /**
344
+ * The currency a checkout session is priced in: the one requested on its
345
+ * creation, which later requests for the session keep using.
346
+ */
347
+ private resolveCheckoutCurrency;
348
+ /**
349
+ * Sends an `order_update` event with the order's current state, e.g. when
350
+ * the OMS ships or cancels it. Returns false for orders not placed through
351
+ * an ACP checkout session, or when webhooks are not configured.
352
+ */
353
+ notifyOrderUpdated(orderId: string): Promise<boolean>;
129
354
  getHandler(): ReactionaryACPHttpHandler;
130
355
  toNodeHandler(): ReactionaryACPNodeRequestHandler;
131
356
  close(): Promise<void>;
132
357
  private createRequestContext;
133
358
  private handleRequest;
359
+ /**
360
+ * The cart capability (cart RFC): pre-checkout baskets over a backend
361
+ * cart. Carts have no status — they exist, or answer 404 once canceled or
362
+ * expired — and no payment or negotiation, which belong to checkout.
363
+ */
364
+ private handleCartRequest;
365
+ private getCartExpiry;
366
+ /** A cart's authoritative state; totals are estimates without an address. */
367
+ private toACPCart;
134
368
  private getDiscoveryDocument;
369
+ /** The extensions the server implements; extension PRs add theirs here. */
370
+ private getDiscoveryExtensions;
135
371
  private getReadinessDocument;
136
- private getProductFeed;
137
- private getRequestedProductFeed;
138
- private getProductFeedDefinition;
139
372
  private handlePost;
140
373
  private createCheckoutSession;
141
374
  private updateCheckoutSession;
142
375
  private getCheckoutSession;
143
376
  /**
144
377
  * Creates the real checkout from the session state and finalizes it. A
145
- * payment the PSP has not authorized yet leaves the session `in_progress`;
378
+ * payment the PSP has not authorized yet leaves the session
379
+ * `complete_in_progress`, without an order yet;
146
380
  * a repeated complete retries finalization.
147
381
  */
148
382
  private completeCheckoutSession;
149
383
  private cancelCheckoutSession;
384
+ /**
385
+ * Gives the session's cart exactly the requested items (line items are a
386
+ * full replacement), updating it in place where the backend supports it.
387
+ * Otherwise a new cart replaces it and the old one is deleted, if possible.
388
+ * Returns the cart key.
389
+ */
390
+ private replaceCartItems;
150
391
  private createCartForItems;
151
392
  private getRequiredCheckoutSessionState;
152
393
  private placeCheckout;
@@ -158,6 +399,69 @@ export declare class ReactionaryACPServer<TClient extends ReactionaryACPClient =
158
399
  */
159
400
  private priceSession;
160
401
  private toACPCheckoutSession;
402
+ private classifyFulfillmentOption;
403
+ /**
404
+ * Whether the discount extension is active for a session: the backend can
405
+ * apply coupons, and the agent declared the extension.
406
+ */
407
+ private isDiscountExtensionActive;
408
+ /** Applies submitted discount codes, when the extension is active. */
409
+ private applyRequestedDiscounts;
410
+ /**
411
+ * 3D Secure (checkout RFC §4.4): when the authentication hook asks for it,
412
+ * the first completion answers `authentication_required` with the
413
+ * metadata; completing such a session without `authentication_result` is
414
+ * a 4XX `requires_3ds`. Failed or refused authentications are not
415
+ * authorized. Returns a response when completion must stop here.
416
+ */
417
+ private checkAuthentication;
418
+ /**
419
+ * Records an order placed through a session once, and announces it to the
420
+ * creating agent's webhook receiver.
421
+ */
422
+ private recordOrder;
423
+ /**
424
+ * Reports the order's affiliate attribution once it exists: first touch
425
+ * from the session's creation, last touch from its completion. A failing
426
+ * hook never blocks the checkout.
427
+ */
428
+ private reportAttribution;
429
+ /**
430
+ * Passes the buyer's consent decisions on, once the order exists. Only
431
+ * offered channels with a resolvable contact count: email uses the buyer's
432
+ * email, falling back to the fulfillment email; sms and whatsapp the phone
433
+ * likewise (marketing consent RFC §3.5). Omitted channels are not consent.
434
+ */
435
+ private reportMarketingConsents;
436
+ /** The offered marketing channels, with the buyer's subscription state. */
437
+ private getMarketingConsentOptions;
438
+ private sendOrderEvent;
439
+ /** The full current order (webhooks carry the whole order, not deltas). */
440
+ private toACPOrder;
441
+ /**
442
+ * The advertised handler a completion pays with. Sellers MUST check the
443
+ * handler is one they declared (sellers guide, "Complete a checkout
444
+ * session"), and raw card numbers are refused unless explicitly accepted,
445
+ * so they never reach the backend's persisted payment data.
446
+ */
447
+ private resolvePaymentHandler;
448
+ /**
449
+ * The seller's capabilities for a session: interventions are the
450
+ * intersection of what the agent declared and what the seller supports,
451
+ * plus the seller's requirements (capability negotiation RFC §4.5.1).
452
+ */
453
+ private getNegotiatedCapabilities;
454
+ /**
455
+ * An out_of_stock error per line item requesting more than the configured
456
+ * fulfillment centers hold (as in the UCP adapter). Back-ordered and
457
+ * pre-ordered items are always purchasable; without configured centers,
458
+ * stock is left to the backend.
459
+ */
460
+ private getStockMessages;
461
+ /**
462
+ * Required interventions the agent cannot perform block the session when
463
+ * they always apply (checkout RFC §5, intervention_required).
464
+ */
465
+ private getInterventionMessages;
161
466
  private getPlacedView;
162
- private getPaymentProvider;
163
467
  }