@cmdoss/suipay-mcp 0.2.2-dev.9 → 0.3.0-dev.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.
@@ -0,0 +1,4786 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { Ed25519Keypair } from '@mysten/sui/keypairs/ed25519';
3
+
4
+ /**
5
+ * Resolve which grant policy target may pay a seller offer's targetHash (WS7.6).
6
+ *
7
+ * SINGLE SOURCE — consent validation and MCP pay MUST use this helper.
8
+ * Never inline "find policy by hash" in tools or consent UI.
9
+ *
10
+ * Seller offer carries targetHash only (no buyer policyId). Buyer authority
11
+ * is the OAuth grant snapshot of policies/targets at consent time.
12
+ */
13
+ type GrantLifecycleStatus = 'pending' | 'active' | 'paused' | 'revoked' | 'expired';
14
+ type PolicyLifecycleStatus = 'draft' | 'active' | 'paused' | 'revoked';
15
+ interface GrantTargetBinding {
16
+ /** 32-byte hex target hash. */
17
+ targetHash: string;
18
+ /** Optional per-target ceiling (atomic units). */
19
+ maxPerPayment?: string;
20
+ /**
21
+ * The address this target pays, when the authority source records one.
22
+ * Carried for callers that want to pin the payee before signing; target
23
+ * resolution itself matches on {@link targetHash} alone, because the offer's
24
+ * `payTo` is what the settlement actually pays.
25
+ */
26
+ recipient?: string;
27
+ }
28
+ interface GrantPolicyBinding {
29
+ /** Off-chain policy id (for audit). */
30
+ policyId: string;
31
+ /** On-chain policy id (u64) inside SpendAccount. */
32
+ onChainPolicyId: number | string;
33
+ status: PolicyLifecycleStatus;
34
+ targets: readonly GrantTargetBinding[];
35
+ }
36
+ /**
37
+ * Immutable snapshot of buyer authority for one OAuth grant.
38
+ * Pool/grant object ids come from finalized on-chain objects (or fake in WS6B).
39
+ */
40
+ interface GrantSnapshot {
41
+ grantId: string;
42
+ status: GrantLifecycleStatus;
43
+ grantObjectId: string | null;
44
+ poolObjectId: string;
45
+ coinType: string;
46
+ delegateAddress: string;
47
+ policies: readonly GrantPolicyBinding[];
48
+ /**
49
+ * `open` = open-recipient (no allowlist, caps required); `scoped` / omit = policy-bound.
50
+ */
51
+ accessMode?: 'scoped' | 'open';
52
+ /** Grant-level max per payment (atomic); used for open and as a grant ceiling. */
53
+ maxPerPayment?: string | null;
54
+ /** Grant-level session cap (atomic); open requires a positive value. */
55
+ sessionCap?: string | null;
56
+ }
57
+ type ResolveGrantTargetResult = {
58
+ ok: true;
59
+ policyId: string;
60
+ onChainPolicyId: number | string;
61
+ targetHash: string;
62
+ maxPerPayment?: string;
63
+ poolObjectId: string;
64
+ grantObjectId: string;
65
+ coinType: string;
66
+ delegateAddress: string;
67
+ } | {
68
+ ok: false;
69
+ reason: string;
70
+ };
71
+ /**
72
+ * Pick the policy target that matches offer.targetHash under an active grant.
73
+ * Pause/revoke of grant or policy fails closed without decrypting the delegate.
74
+ */
75
+ declare function resolveGrantTarget(snapshot: GrantSnapshot, offerTargetHash: string): ResolveGrantTargetResult;
76
+
77
+ /**
78
+ * Public authorization facts exposed to authenticated MCP clients.
79
+ *
80
+ * This shape is descriptive only. Payment authorization continues to use the
81
+ * immutable on-chain GrantSnapshot; callers must never derive spend authority
82
+ * from this object.
83
+ */
84
+ interface McpAccessProfile {
85
+ id: string;
86
+ name: string;
87
+ status: 'active' | 'disabled';
88
+ }
89
+ interface McpAccessTarget {
90
+ serviceId: string;
91
+ /** Friendly seller service name (live catalog), or serviceId if unresolved. */
92
+ name: string;
93
+ endpointId: string;
94
+ method: string;
95
+ path: string;
96
+ targetHash: string;
97
+ maxPerPayment: string;
98
+ }
99
+ interface McpAccessPolicy {
100
+ id: string;
101
+ name: string;
102
+ status: 'draft' | 'active' | 'paused' | 'revoked';
103
+ asset: string;
104
+ coinType: string;
105
+ totalCap: string;
106
+ spent: string;
107
+ maxPerPayment: string;
108
+ expiresAt: string | null;
109
+ targets: McpAccessTarget[];
110
+ }
111
+ interface McpAccessContext {
112
+ accessMode: 'scoped' | 'open';
113
+ grant: {
114
+ id: string;
115
+ status: 'pending' | 'active' | 'paused' | 'revoked' | 'expired';
116
+ sessionCap: string | null;
117
+ sessionSpent: string;
118
+ expiresAt: string | null;
119
+ };
120
+ profiles: McpAccessProfile[];
121
+ policies: McpAccessPolicy[];
122
+ }
123
+
124
+ /**
125
+ * Settlement rail identity + authority (WS7.1 / WS7.2 single source).
126
+ *
127
+ * Consumers MUST import `SettlementRail` / `SettlementRailAuthority` from here
128
+ * - do not redefine rail strings or package/module/function lookups inline.
129
+ *
130
+ * `dialectModes` is the rail CAPABILITY CEILING (what the rail can do per
131
+ * dialect). `supportedDialects` is DERIVED as `Object.keys(dialectModes)` -
132
+ * ONE SSOT, no parallel array to drift.
133
+ *
134
+ * Demo ships SpendAccount as MPP-only. WS12 dual-dialect (x402 on delegate)
135
+ * is STRETCH and must stay behind an explicit rollout flag, default off.
136
+ *
137
+ * Keep `spendAccountSponsorTargets()` SEPARATE - that is lifecycle sponsorship,
138
+ * not settlement authority.
139
+ */
140
+
141
+ /**
142
+ * Wire tokens for settlement rails. Three engines, three tokens: `direct`,
143
+ * `delegate`, and `recurring` (mandate rail; HTTP mint + Move `RAIL_TAG`).
144
+ * The Move *module* is still `subscription`; that name is not a wire rail.
145
+ * V1 `allowance` and `auth_capture` are not members: they do not decode.
146
+ */
147
+ declare const SETTLEMENT_RAILS: readonly ["direct", "delegate", "recurring"];
148
+ type SettlementRail = (typeof SETTLEMENT_RAILS)[number];
149
+ /**
150
+ * The delegation SCOPE discriminator: which `spend_account` pay surface a
151
+ * delegate draws on, and so which on-chain function settles the payment.
152
+ *
153
+ * - `'scoped'` — policy scope. The grant carries a policy allowlist; the
154
+ * payment resolves a target and settles via
155
+ * `settle_policy`.
156
+ * - `'open'` — any-recipient scope. No allowlist; the caps are the only
157
+ * limit; settles via `settle_any_recipient`.
158
+ *
159
+ * This is ONE of three orthogonal concepts that must never be conflated:
160
+ * - SCOPE — this type, `accessMode` (which pay function / recipient
161
+ * surface). Selects the on-chain entry point.
162
+ * - ELIGIBILITY — `SpendAccountGrantKind` (`'GrantCap' | 'SpendGrant'`), the
163
+ * x402 grant-object discriminator. A separate field.
164
+ * - CAP — the budget (`maxPerPayment` / total), a separate field.
165
+ *
166
+ * The string VALUES `'scoped'`/`'open'` are FROZEN: they persist in the
167
+ * `access_mode` DB column (legacy `profile_bound`/`catalog_open` already
168
+ * normalize onto them) and ride the non-signed `PreparedSettlement` 402-body
169
+ * field. They are NOT part of any signed/hashed payload — the scope selects a
170
+ * Move function via `spendAccountDebitFunction`; the string itself is never a
171
+ * serialized argument — so this type names the concept without touching the
172
+ * wire. Rename the VALUES only as a deliberate wire+DB migration, not here.
173
+ */
174
+ type DelegationScope = 'scoped' | 'open';
175
+
176
+ /**
177
+ * Shared vocabulary for both 402 dialects.
178
+ *
179
+ * The central claim of this PoC is that MPP and x402 are two encodings of one
180
+ * payment offer, not two payment systems. Everything below the dialect codecs
181
+ * therefore speaks in these types; only `mpp.ts` and `x402.ts` know about
182
+ * headers and JSON bodies.
183
+ */
184
+
185
+ /**
186
+ * Digest canonicalization version.
187
+ * v1 = legacy direct wire;
188
+ * v2 = two-layer SpendAccount fields;
189
+ * v3 = additive body binding (bodyHash, contentType) + subscription mandate
190
+ * (intent, periodMs, periodCount) fields (does not break v1/v2);
191
+ * v4 = additive cross-rail-exclusion binding: the normalized accepted-rail set
192
+ * plus the exclusion protocol version and canonical registry identity the
193
+ * offer commits to (does not break v1/v2/v3). Never the derived exclusion
194
+ * key — that is computed inside Move, never on the wire.
195
+ */
196
+ type OfferDigestVersion = 1 | 2 | 3 | 4;
197
+ /** Payment intent on a signed offer. Default / omitted = one-shot charge. */
198
+ type PaymentIntent = 'charge' | 'subscription';
199
+ /** What the provider is willing to be paid, for one specific request. */
200
+ interface Offer {
201
+ /** Single-use id. Both dialects carry this same value — the binding this PoC demonstrates. */
202
+ challengeId: string;
203
+ /** Absolute URL of the resource being sold. */
204
+ resource: string;
205
+ /** Human-readable description of the resource. */
206
+ description: string;
207
+ /** Content type the payer receives on success. */
208
+ mimeType: string;
209
+ /**
210
+ * Gross amount the buyer pays, in the asset's smallest unit, as a decimal
211
+ * string (no float rounding). Equals `netAmount + platformFee`.
212
+ */
213
+ amount: string;
214
+ /**
215
+ * Seller-declared net price (atomic units). Explicit even when equal to
216
+ * `amount` so fee semantics stay visible. Optional on legacy decoded offers
217
+ * that predate fee fields. Signed under digest v2.
218
+ */
219
+ netAmount?: string;
220
+ /**
221
+ * Facilitator-owned platform fee (atomic units). PoC is `"0"`; field is
222
+ * still present on freshly minted offers. Signed under digest v2.
223
+ */
224
+ platformFee?: string;
225
+ /** Fully-qualified Move coin type, e.g. `0x2::sui::SUI`. */
226
+ asset: string;
227
+ /** Decimal places of `asset`, for display only. */
228
+ decimals: number;
229
+ /** CAIP-2-style network id, e.g. `sui:testnet`. */
230
+ network: string;
231
+ /** Address that receives the funds. */
232
+ payTo: string;
233
+ /** Move package implementing the rail pay function. */
234
+ packageId: string;
235
+ /** Epoch ms. */
236
+ issuedAt: number;
237
+ /** Epoch ms. After this the offer is dead and must be re-fetched. */
238
+ expiresAt: number;
239
+ /**
240
+ * Canonicalization version for `digest`. Omitted / 1 = legacy fields only
241
+ * (existing wire format). 2 = includes settlementRail, service snapshot,
242
+ * method/path, and fee fields under the HMAC (WS7.3). 3 = adds the optional
243
+ * body-binding and subscription-mandate fields (additive; v1/v2 unchanged).
244
+ */
245
+ digestVersion?: OfferDigestVersion;
246
+ /** Settlement rail (signed in v2+). Never carries buyer policy/grant/pool. */
247
+ settlementRail?: SettlementRail;
248
+ /** Seller service id from one immutable registry snapshot (v2). */
249
+ serviceId?: string;
250
+ /** Active revision of that service snapshot (v2). */
251
+ serviceRevision?: number;
252
+ /** On-chain policy target hash hex (v2; delegate). */
253
+ targetHash?: string;
254
+ /** Authorization epoch bound into targetHash (v2; same snapshot). */
255
+ authorizationEpoch?: number;
256
+ /** HTTP method of the paid request (v2). */
257
+ method?: string;
258
+ /** Public path of the paid request (v2). */
259
+ path?: string;
260
+ /**
261
+ * Canonical hash of the paid request body (v3), base64url SHA-256 as produced
262
+ * by `hashRequestBody`. Present on body-bearing offers only; a GET offer omits
263
+ * it. Signing it is what stops a paid credential being replayed against
264
+ * different bytes.
265
+ */
266
+ bodyHash?: string;
267
+ /**
268
+ * Content type of the paid request body (v3), normalized. Signed alongside
269
+ * `bodyHash` so the seller executes the body under the type it was paid for.
270
+ */
271
+ contentType?: string;
272
+ /**
273
+ * Payment intent (v3). `charge` = one-shot; `subscription` = period mandate.
274
+ * Omitted on v1/v2 offers.
275
+ */
276
+ intent?: PaymentIntent;
277
+ /** Billing period length in ms (v3; required when intent=subscription). */
278
+ periodMs?: number;
279
+ /** Maximum billable periods (v3; required when intent=subscription). */
280
+ periodCount?: number;
281
+ /**
282
+ * Opt-in dispute-window vault settlement (ADR-0007).
283
+ * When true, settlement opens a RefundVault instead of paying the merchant.
284
+ * Omit / false keeps today's non-refundable path. Signed under v3 when present
285
+ * (omit-when-absent, same rule as subscription fields).
286
+ */
287
+ refundable?: boolean;
288
+ /**
289
+ * Refund window length in ms (v3). Deposit + this = release_at_ms.
290
+ * Required when refundable=true; omit-when-absent for non-refundable digests.
291
+ */
292
+ refundWindowMs?: number;
293
+ /**
294
+ * Delivery-decision window length in ms (v3). Deposit + this = decide_by_ms.
295
+ * Must be strictly less than refundWindowMs. Omit-when-absent.
296
+ */
297
+ decideWindowMs?: number;
298
+ /**
299
+ * Sui chain id (u64) for payment_key derivation. Required when refundable.
300
+ * Signed under v3 when present (omit-when-absent).
301
+ */
302
+ chainId?: number;
303
+ /**
304
+ * Per-payment salt for payment_key (utf8). Gateway mints; buyer echoes.
305
+ * Signed under v3 when present (omit-when-absent).
306
+ */
307
+ paymentSalt?: string;
308
+ /**
309
+ * Pinned refund destination expected on VaultOpened. When omitted on a
310
+ * refundable offer, facilitators default to the rail-derived beneficiary
311
+ * (pool owner / payer). Signed under v3 when present (omit-when-absent).
312
+ */
313
+ refundTo?: string;
314
+ /**
315
+ * Optional override for the rail-specific settlement_ref bytes in
316
+ * payment_key. When omitted, facilitators default to challengeId (direct)
317
+ * or the rail's on-chain identity (terms_hash for delegate).
318
+ * Signed under v3 when present (omit-when-absent).
319
+ */
320
+ settlementRef?: string;
321
+ /**
322
+ * Offer-pinned sponsor gas for delegate x402 (transaction mode).
323
+ * Omit-when-absent under digest v2+ so MPP-only offers keep byte-identical
324
+ * digests. When present, the agent must build TransactionData.gasData to
325
+ * match exactly, and the gateway precheck asserts equality.
326
+ */
327
+ sponsorGasOwner?: string;
328
+ /** Atomic units (decimal string), pinned gas budget. */
329
+ sponsorGasBudget?: string;
330
+ /** Atomic units (decimal string), pinned gas price. */
331
+ sponsorGasPrice?: string;
332
+ /**
333
+ * Compact reserved gas coin ref(s):
334
+ * `objectId@version@digest` joined by `,` (stable, HMAC-safe).
335
+ */
336
+ sponsorGasPayment?: string;
337
+ /**
338
+ * Cross-rail-exclusion accepted-rail set (v4). The normalized, ordered,
339
+ * deduped rails the offer is issued for. Unsigned before v4; signing it under
340
+ * v4 makes the multi-rail-with-delegate capability consensus-bound — a
341
+ * tampered set fails verification. Omit-when-absent under the v4 HMAC.
342
+ */
343
+ acceptedRails?: SettlementRail[];
344
+ /**
345
+ * Exclusion-protocol version the offer commits to (v4). The on-chain mutual
346
+ * exclusion the guarded settle path consumes is versioned; the offer pins
347
+ * which version it was minted against. Omit-when-absent under the v4 HMAC.
348
+ */
349
+ exclusionProtocolVersion?: number;
350
+ /**
351
+ * Canonical exclusion directory/registry identity the offer commits to (v4):
352
+ * the module-created directory and package the guarded settle resolves the
353
+ * recipient registry through, as one opaque canonical string (e.g.
354
+ * `packageId::directoryId`). Never the derived exclusion key. Omit-when-absent
355
+ * under the v4 HMAC.
356
+ */
357
+ registryIdentity?: string;
358
+ /** HMAC over the versioned canonical form. Detects tampering in transit. */
359
+ digest: string;
360
+ }
361
+ /** Proof of settlement, returned alongside the resource. */
362
+ interface Receipt {
363
+ challengeId: string;
364
+ /** On-chain transaction digest. */
365
+ txDigest: string;
366
+ network: string;
367
+ payer: string;
368
+ /** Gross amount settled (atomic units). */
369
+ amount: string;
370
+ asset: string;
371
+ status: 'settled';
372
+ /**
373
+ * Merchant address the native-transfer path paid. Absent on the event path,
374
+ * where PaymentMade.recipient is the evidence.
375
+ */
376
+ payTo?: string;
377
+ /**
378
+ * Canonical requestDigest this settlement paid for. Bound to `txDigest` so
379
+ * a receipt proves one specific HTTP request was settled on chain.
380
+ */
381
+ requestDigest?: string;
382
+ /** Seller net proceeds (atomic units). Explicit fee semantics; PoC equals amount. */
383
+ netAmount?: string;
384
+ /** Facilitator platform fee (atomic units). PoC is `"0"`. */
385
+ platformFee?: string;
386
+ /** Payment intent when settled via a non-charge flow (e.g. subscription). */
387
+ intent?: PaymentIntent;
388
+ /** Subscription mandate object id when intent=subscription. */
389
+ mandateId?: string;
390
+ /** Clock-derived period index that was charged (subscription). */
391
+ periodIndex?: string;
392
+ /**
393
+ * Canonical payment_key hex when settlement opened a RefundVault (refundable).
394
+ * Used as the durable delivery-success key and operator-refund identity.
395
+ */
396
+ paymentKey?: string;
397
+ /** Shared vault object id when refundable. */
398
+ vaultId?: string;
399
+ /** Pinned refund beneficiary from VaultOpened when refundable. */
400
+ refundTo?: string;
401
+ /**
402
+ * Canonical grant object id (on-chain Move type: `Grant<T>`) this settlement
403
+ * drew against (delegate rail only). `padObjectId` form — the SAME identity
404
+ * the session receipt ledger keys by (`sessionIdForGrant`), so the durable
405
+ * projection and the session ledger converge on one grant id. Absent for
406
+ * non-delegate rails and refundable-vault settlements, which carry no
407
+ * PaymentMade grant.
408
+ */
409
+ grantId?: string;
410
+ /**
411
+ * Canonical spend-account object id (`Account<T>`) the grant draws from
412
+ * (delegate rail only). Absent wherever `grantId` is.
413
+ */
414
+ poolId?: string;
415
+ }
416
+ /** Which encoding a message used. Recorded so the provider can answer in kind. */
417
+ type Dialect = 'mpp' | 'x402';
418
+
419
+ /**
420
+ * The settled-payment DTO.
421
+ *
422
+ * Shared vocabulary: the gateway produces it, `@cmdoss/suipay-mcp` consumes it.
423
+ * Only the shape lives here — the gateway's read-model mappers and row types
424
+ * stay in `apps/gateway/src/buyer/settlement-dto.ts`, which re-exports this.
425
+ */
426
+
427
+ interface SettlementDTO {
428
+ at: string;
429
+ resourceId?: string;
430
+ recipient: string;
431
+ dialect?: Dialect;
432
+ receipt: {
433
+ challengeId: string;
434
+ txDigest: string;
435
+ network: string;
436
+ payer: string;
437
+ amount: string;
438
+ asset: string;
439
+ status: 'settled';
440
+ };
441
+ /**
442
+ * Present only on the live in-memory feed. The read model dedups on
443
+ * (network, digest), so a durable row is never a replay — the field is
444
+ * omitted there rather than asserted false. Consumers must treat absent as
445
+ * not-replayed.
446
+ */
447
+ replayed?: boolean;
448
+ }
449
+
450
+ /**
451
+ * Authenticated MCP request context (remote Streamable HTTP).
452
+ * Bearer is required on /mcp; tools enforce scope from the resolved grant.
453
+ */
454
+
455
+ /**
456
+ * Read/prepare-only shared-pool context for an authenticated MCP bearer.
457
+ *
458
+ * Non-custodial: the gateway holds NO key that can spend. There is deliberately
459
+ * no `decryptDelegateSeed` and no forwarded `sponsorAuthorization` here — the
460
+ * `pay` tool only PREPARES an unsigned `spend_account::settle_policy` / `settle_any_recipient` transaction from the
461
+ * immutable grant snapshot (`prepareSpendAccountPayment`), and the client that
462
+ * holds the delegate key signs locally and submits. Only signatures ever reach
463
+ * the gateway. See docs/design/mcp-non-custodial-signing.md and ADR-0013 §3.
464
+ */
465
+ interface McpSpendAccountPayAuth {
466
+ snapshot: GrantSnapshot;
467
+ packageId: string;
468
+ /**
469
+ * Re-verify the paying authority against a FRESH graph + injected clock at
470
+ * prepare time. Throws on drift/expiry so the pay tool refuses to hand back a
471
+ * signing request for a grant that just went paused/revoked/expired. Optional:
472
+ * absent for legacy/local paths.
473
+ */
474
+ assertLive?: () => Promise<void>;
475
+ }
476
+ interface McpAuthContext {
477
+ grantId: string;
478
+ buyerAccountId: string;
479
+ /** Space-separated scopes from the access token. */
480
+ scope: string;
481
+ /** Public, descriptive policy context. Never used as payment authority. */
482
+ access?: McpAccessContext;
483
+ /**
484
+ * When present, `pay` prepares unsigned spend_account::settle_policy / settle_any_recipient bytes for the
485
+ * client-held delegate key to sign locally — no server-side decrypt or
486
+ * signing. Stdio local V1 profile path remains when absent.
487
+ */
488
+ spendAccountPay?: McpSpendAccountPayAuth;
489
+ /**
490
+ * Server-scoped receipts reader, built by the /mcp route from the verified
491
+ * bearer's connection. The `receipts` tool calls this instead of hitting the
492
+ * global settlement feed with a forwarded credential — the bearer never
493
+ * enters the tool surface, and scoping is enforced server-side. Absent for
494
+ * local stdio (no connection, no settlement source).
495
+ */
496
+ listReceipts?: (challengeId?: string) => Promise<SettlementDTO[]>;
497
+ }
498
+
499
+ type McpTarget = 'dev' | 'local';
500
+ /**
501
+ * Public suipay-dev origins (Railway). `local` is the laptop stack from
502
+ * `pnpm demo:testnet`. Explicit `SUIPAY_GATEWAY_URL` / `SUIPAY_CONSOLE_URL`
503
+ * still win over the preset.
504
+ */
505
+ declare const MCP_TARGET_PRESETS: Record<McpTarget, {
506
+ consoleUrl: string;
507
+ gatewayUrl: string;
508
+ }>;
509
+ interface McpConfig {
510
+ /** Preset used when console/gateway env is unset. Set by `loadMcpConfig`. */
511
+ target?: McpTarget;
512
+ consoleUrl: string;
513
+ gatewayUrl: string;
514
+ rpcUrl: string;
515
+ network: 'testnet' | 'mainnet' | 'devnet' | 'localnet';
516
+ packageId: string;
517
+ recipient: string;
518
+ coinType: string;
519
+ sponsorUrl: string;
520
+ minFunded: bigint;
521
+ minMaxPerPayment: bigint;
522
+ label: string;
523
+ /**
524
+ * Optional override of the gateway's published `ExclusionDirectory` id.
525
+ * When null, pay reads `GET /v1/delegate/deployment` and turns the resolver
526
+ * on only if that response names one. The id here does not choose the
527
+ * directory a settle uses — the offer's `registryIdentity` does.
528
+ */
529
+ exclusionDirectoryObjectId: string | null;
530
+ }
531
+ /**
532
+ * CLI flags: `--local` / `-local`, `--dev` / `-dev`. Unknown args are ignored
533
+ * so an MCP host can pass extra argv without breaking stdio.
534
+ */
535
+ declare function parseMcpTargetFlag(argv: readonly string[]): McpTarget | undefined;
536
+ declare function resolveMcpTarget(env?: NodeJS.ProcessEnv, argv?: readonly string[]): McpTarget;
537
+ /** Same public origin, or the same laptop loopback port (`localhost` ≡ `127.0.0.1`). */
538
+ declare function sameMcpGateway(a: string, b: string): boolean;
539
+ declare function loadMcpConfig(env?: NodeJS.ProcessEnv, argv?: readonly string[]): McpConfig;
540
+
541
+ /**
542
+ * Grant-scoped read DTOs a delegate may see. Split from `principal.ts` because
543
+ * `agent-sdk/reads.ts` (published) needs only these shapes, not the gateway-side
544
+ * projection functions that build them from a resolved authority record.
545
+ */
546
+ /**
547
+ * A delegate's grant-scoped balance view. The on-chain money facts for its OWN
548
+ * grant: the containment caps, the projected session spend, and the derived
549
+ * remaining headroom — never the owner tenant id or any operational context.
550
+ */
551
+ interface DelegateBalanceDTO {
552
+ grantObjectId: string;
553
+ poolObjectId: string;
554
+ asset: string;
555
+ coinType: string;
556
+ /** `open` (full access, caps) vs `scoped` (policy allowlist). */
557
+ grantType: 'open' | 'scoped';
558
+ /** Per-session ceiling in atomic units; null = unlimited. */
559
+ sessionCap: string | null;
560
+ /** Per-payment ceiling in atomic units; null = unlimited. */
561
+ maxPerPayment: string | null;
562
+ /** Projected session spend in atomic units; null = not wired / unknown. */
563
+ sessionSpent: string | null;
564
+ /**
565
+ * Remaining session headroom in atomic units when both a finite cap and a
566
+ * known spend exist, clamped at zero; null when the cap is unlimited or the
567
+ * spend is unknown (never guessed).
568
+ */
569
+ sessionRemaining: string | null;
570
+ }
571
+ /** One allowlisted target of one policy, as the delegate may see it. */
572
+ interface DelegatePolicyTargetDTO {
573
+ /** 32-byte hex target hash the offer's `targetHash` must equal. */
574
+ targetHash: string;
575
+ /**
576
+ * The only address this target may pay, when the authority source records
577
+ * one. Omitted rather than blank when it does not: an agent that pins an
578
+ * empty recipient would refuse every offer, and one that pins a fabricated
579
+ * value would refuse the right one.
580
+ */
581
+ recipient?: string;
582
+ /** Per-target ceiling in atomic units, when the target sets one. */
583
+ maxPerPayment?: string;
584
+ }
585
+ /** One policy backing this grant's on-chain spend authority. */
586
+ interface DelegatePolicyDTO {
587
+ /** Off-chain policy id (audit). */
588
+ policyId: string;
589
+ /** On-chain policy id (u64) the settlement call names. */
590
+ onChainPolicyId: number | string;
591
+ status: 'draft' | 'active' | 'paused' | 'revoked';
592
+ targets: DelegatePolicyTargetDTO[];
593
+ }
594
+ /**
595
+ * A delegate's grant-scoped policy view: the immutable policy snapshot the grant
596
+ * was created with — off-chain ids, on-chain ids, and each policy's allowlisted
597
+ * TARGETS — plus the grant surface. An open grant carries no allowlist (empty
598
+ * arrays). Never the owner tenant id, policy names, or catalog enrichment.
599
+ *
600
+ * The targets are here because without them a scoped grant cannot be paid at
601
+ * all. A payment names a policy id and a target hash, and the ids alone let a
602
+ * caller name neither: `resolveGrantTarget` matches the offer's `targetHash`
603
+ * against this allowlist, and nothing else publishes it to the key that holds
604
+ * the grant.
605
+ *
606
+ * Publishing them adds no authority. This is a signed, grant-scoped read: the
607
+ * caller proved possession of the delegate key and the signature binds the
608
+ * grant, so the response can only ever describe that one grant. It states the
609
+ * bound the chain already enforces on `spend_account::settle_policy`;
610
+ * it does not widen it. What an agent gains is the ability to check an offer
611
+ * BEFORE signing instead of discovering the bound as an on-chain abort.
612
+ */
613
+ interface DelegatePoliciesDTO {
614
+ grantObjectId: string;
615
+ grantType: 'open' | 'scoped';
616
+ offChainPolicyIds: string[];
617
+ onChainPolicyIds: number[];
618
+ /**
619
+ * The bound policies with their targets, in the order the authority source
620
+ * returns them. Empty for an open grant (no allowlist exists) and empty when
621
+ * no target source is configured — never a partial list, because a truncated
622
+ * allowlist reads as "this target is not authorized" for targets that are.
623
+ */
624
+ policies: DelegatePolicyDTO[];
625
+ }
626
+
627
+ /**
628
+ * Agent signing helper — emit the four `x-suipay-*` signed-request headers.
629
+ *
630
+ * A delegate agent proves identity on every private, grant-scoped request by
631
+ * signing the canonical `SignedRequestV1` payload with a Sui personal-message
632
+ * signature. This helper is the client-side counterpart to the gateway verifier:
633
+ * it canonicalizes the path/query and hashes the body EXACTLY as the verifier
634
+ * will (reusing the P0 codec's `canonicalizePath` / `canonicalizeQuery` /
635
+ * `hashBodyHex`), builds the payload, signs it through P0's `signSignedRequest`,
636
+ * and returns the four headers keyed by P0's `SIGNED_REQUEST_HEADERS`.
637
+ *
638
+ * It NEVER holds or transmits the private key: the caller injects a
639
+ * `signPersonalMessage` callback (a wallet, a keystore, or an `Ed25519Keypair`
640
+ * bound via {@link personalMessageSigner}). Money never moves on this signature;
641
+ * it authorizes only the grant-scoped reads the epic defines.
642
+ *
643
+ * Byte-for-byte parity with P0 is locked by the golden vector in
644
+ * `tests/agent-sdk-signed-headers.test.ts`, which reproduces the exact
645
+ * signature the cross-language vector (`tests/parity/signed-request-golden.test.ts`)
646
+ * pins.
647
+ */
648
+
649
+ /** Sui personal-message signer: returns the serialized signature (base64). */
650
+ type SignPersonalMessage = (message: Uint8Array) => Promise<string>;
651
+ /**
652
+ * The deployment + grant identity every signed request binds. `network` and
653
+ * `packageId` MUST equal the gateway's server-authoritative config; `delegate`
654
+ * MUST equal the grant's registered on-chain delegate (the signer's address).
655
+ */
656
+ interface SessionSignerContext {
657
+ /** e.g. `sui:testnet` — must equal the gateway config. */
658
+ network: string;
659
+ /** Deployed package id — must equal the gateway config. */
660
+ packageId: string;
661
+ /** On-chain grant object id — the authorization scope. */
662
+ grantObjectId: string;
663
+ /** Registered delegate Sui address (the signer). */
664
+ delegateAddress: string;
665
+ }
666
+ /** Deterministic overrides (tests / golden vectors) + injectable entropy/clock. */
667
+ interface SignRequestOptions {
668
+ /** Pin the signed timestamp (epoch ms). Defaults to `now()`. */
669
+ timestampMs?: number;
670
+ /** Pin the single-use nonce. Defaults to `generateNonce()`. */
671
+ nonce?: string;
672
+ /** Injectable clock; defaults to `Date.now`. */
673
+ now?: () => number;
674
+ /** Injectable nonce source; defaults to {@link generateSignedRequestNonce}. */
675
+ generateNonce?: () => string;
676
+ }
677
+
678
+ /**
679
+ * Grant-scoped read ergonomics for a delegate agent.
680
+ *
681
+ * Two kinds of read, mirroring the epic's public/private split:
682
+ *
683
+ * 1. Enriched-context reads ({@link createReader}) — the private,
684
+ * off-chain-enriched projections behind P2's signed routes
685
+ * (`GET /v1/delegate/{balance,policies,receipts}`). Each request is signed
686
+ * with the four `x-suipay-*` headers (via the P0-backed signing helper),
687
+ * so the gateway resolves the caller's grant and returns ONLY that grant's
688
+ * state. Non-2xx responses are classified, never swallowed.
689
+ *
690
+ * 2. Direct on-chain reads ({@link readPublicSessionState} /
691
+ * {@link readPublicSpendAccountState}) — the PUBLIC on-chain facts (delegate, caps,
692
+ * spend, policy ids, pause/revoke, pool balance) read straight from a
693
+ * `getObject` projection with no signature. Public data stays public.
694
+ *
695
+ * The read client never spends and never holds the private key: money still
696
+ * moves only through the delegate's own on-chain `spend_account::settle_policy`.
697
+ */
698
+
699
+ /** A delegate's own receipts, as P2's receipts route shapes them. */
700
+ interface PayerReceiptsDTO {
701
+ source: 'read-model' | 'memory';
702
+ receipts: unknown[];
703
+ }
704
+ /**
705
+ * A classified read outcome. `ok` is a 2xx with a parsed body; a failure carries
706
+ * the HTTP status, a coarse class, and the gateway's stable error code (never a
707
+ * raw internal string — the gateway already sanitizes `{ error }`).
708
+ */
709
+ type PayerReadResult<T> = {
710
+ ok: true;
711
+ status: number;
712
+ data: T;
713
+ } | {
714
+ ok: false;
715
+ status: number;
716
+ /**
717
+ * Coarse failure class: `rejected` = auth/authz refusal (4xx);
718
+ * `unavailable` = a 5xx or a transport failure; `malformed` = unparseable;
719
+ * `signing` = the local signature could not be produced (the request never
720
+ * left the client). Never a throw — every failure is a typed result.
721
+ */
722
+ error: 'rejected' | 'unavailable' | 'malformed' | 'signing';
723
+ /** Gateway's public failure code from `{ error }`, or a stable client code. */
724
+ code?: string;
725
+ body?: unknown;
726
+ };
727
+ interface PayerReadClientOptions {
728
+ /** Gateway origin, e.g. `https://gateway.suipay.dev` (no trailing slash needed). */
729
+ gatewayUrl: string;
730
+ /** Deployment + grant identity every signed read binds. */
731
+ context: SessionSignerContext;
732
+ /** Local personal-message signer; the key never leaves it. */
733
+ signPersonalMessage: SignPersonalMessage;
734
+ /** Injectable fetch (tests / custom transports). Defaults to global `fetch`. */
735
+ fetchImpl?: typeof fetch;
736
+ /** Injectable clock + nonce for deterministic signing in tests. */
737
+ signOptions?: Pick<SignRequestOptions, 'now' | 'generateNonce' | 'timestampMs' | 'nonce'>;
738
+ /** Route prefix; defaults to `/v1/delegate`. */
739
+ basePath?: string;
740
+ }
741
+ /** The read surface a delegate agent gets from its grant. */
742
+ interface PayerReadClient {
743
+ balance(): Promise<PayerReadResult<DelegateBalanceDTO>>;
744
+ policies(): Promise<PayerReadResult<DelegatePoliciesDTO>>;
745
+ receipts(): Promise<PayerReadResult<PayerReceiptsDTO>>;
746
+ /** Sign an arbitrary grant-scoped GET under the same context (escape hatch). */
747
+ signedGet<T = unknown>(pathSuffix: string): Promise<PayerReadResult<T>>;
748
+ }
749
+ /**
750
+ * A signed, grant-scoped read client. Every method signs a GET with the four
751
+ * `x-suipay-*` headers and returns a classified result. A signed GET carries no
752
+ * body, so the body hash is the empty-string hash — matching the verifier.
753
+ */
754
+ declare function createReader(options: PayerReadClientOptions): PayerReadClient;
755
+ /**
756
+ * Fetch the Move JSON contents of an object. Wire this to
757
+ * `client.core.getObject({ objectId, include: { json: true } })` and return its
758
+ * `object.json`. `null` for a missing object. Injected so the reader is pure and
759
+ * testable with fakes and depends on no Sui client at load time.
760
+ */
761
+ type GetObjectJson = (objectId: string) => Promise<Record<string, unknown> | null | undefined>;
762
+
763
+ type PaidHttpMethod = 'GET' | 'POST';
764
+ interface PaidHttpRequest {
765
+ url: string;
766
+ method: PaidHttpMethod;
767
+ /** Exact wire bytes. Empty for GET. */
768
+ body: Uint8Array;
769
+ /** Normalized media type, or null when no body is sent. */
770
+ contentType: string | null;
771
+ /** `hashRequestBody(body)` — the single canonical body hash. */
772
+ bodyHash: string;
773
+ }
774
+
775
+ /**
776
+ * Shapes of the one error model every SuiPay surface shares.
777
+ *
778
+ * The registry (`registry.ts`) is the only place a code is defined. Everything
779
+ * here describes an entry or a value derived from one; nothing here names a
780
+ * code.
781
+ */
782
+ /** Whether money moved for the request the error is about. */
783
+ type PaymentState = 'not_charged' | 'charged' | 'unknown';
784
+ /** The one thing a caller, agent or person should do next. */
785
+ type NextAction = 'retry' | 'retry_later' | 'fix_request' | 'sign_in' | 'approve_access' | 'add_funds' | 'reconcile' | 'contact_support' | 'none';
786
+ /** Where an error can originate. A builder accepts only codes tagged for it. */
787
+ type Surface = 'gateway' | 'seller' | 'console_server' | 'browser' | 'sdk' | 'mcp_local' | 'mcp_hosted' | 'indexer';
788
+
789
+ declare const ERRORS: {
790
+ readonly 'indexer.chain_unavailable': {
791
+ readonly surfaces: readonly ["indexer"];
792
+ readonly status: null;
793
+ readonly title: "Transient chain read failure; retrying with backoff";
794
+ readonly paymentState: "not_charged";
795
+ readonly retry: "after_delay";
796
+ readonly retryAfterSeconds: 5;
797
+ readonly nextAction: "retry_later";
798
+ readonly user: null;
799
+ readonly logOnly: true;
800
+ };
801
+ readonly 'indexer.checkpoint_gap': {
802
+ readonly surfaces: readonly ["indexer"];
803
+ readonly status: null;
804
+ readonly title: "Checkpoint gap cannot be closed; fullnode has pruned it";
805
+ readonly paymentState: "not_charged";
806
+ readonly retry: "never";
807
+ readonly nextAction: "contact_support";
808
+ readonly user: null;
809
+ readonly logOnly: true;
810
+ };
811
+ readonly 'indexer.checkpoint_malformed': {
812
+ readonly surfaces: readonly ["indexer"];
813
+ readonly status: null;
814
+ readonly title: "Checkpoint payload is malformed";
815
+ readonly paymentState: "not_charged";
816
+ readonly retry: "never";
817
+ readonly nextAction: "contact_support";
818
+ readonly user: null;
819
+ readonly logOnly: true;
820
+ };
821
+ readonly 'indexer.checkpoint_refetch_failed': {
822
+ readonly surfaces: readonly ["indexer"];
823
+ readonly status: null;
824
+ readonly title: "Checkpoint re-fetch returned nothing";
825
+ readonly paymentState: "not_charged";
826
+ readonly retry: "after_delay";
827
+ readonly retryAfterSeconds: 5;
828
+ readonly nextAction: "retry_later";
829
+ readonly user: null;
830
+ readonly logOnly: true;
831
+ };
832
+ readonly 'indexer.config_invalid': {
833
+ readonly surfaces: readonly ["indexer"];
834
+ readonly status: null;
835
+ readonly title: "Indexer configuration is invalid";
836
+ readonly paymentState: "not_charged";
837
+ readonly retry: "never";
838
+ readonly nextAction: "contact_support";
839
+ readonly user: null;
840
+ readonly logOnly: true;
841
+ };
842
+ readonly 'indexer.event_legacy_field': {
843
+ readonly surfaces: readonly ["indexer"];
844
+ readonly status: null;
845
+ readonly title: "Event used a deprecated field name; decoded anyway";
846
+ readonly paymentState: "not_charged";
847
+ readonly retry: "never";
848
+ readonly nextAction: "none";
849
+ readonly user: null;
850
+ readonly logOnly: true;
851
+ };
852
+ readonly 'indexer.event_undecodable': {
853
+ readonly surfaces: readonly ["indexer"];
854
+ readonly status: null;
855
+ readonly title: "Owned event body failed to decode";
856
+ readonly paymentState: "not_charged";
857
+ readonly retry: "after_delay";
858
+ readonly retryAfterSeconds: 5;
859
+ readonly nextAction: "retry_later";
860
+ readonly user: null;
861
+ readonly logOnly: true;
862
+ };
863
+ readonly 'indexer.event_unrecognized': {
864
+ readonly surfaces: readonly ["indexer"];
865
+ readonly status: null;
866
+ readonly title: "Package emitted an event type no pipeline claims";
867
+ readonly paymentState: "not_charged";
868
+ readonly retry: "never";
869
+ readonly nextAction: "contact_support";
870
+ readonly user: null;
871
+ readonly logOnly: true;
872
+ };
873
+ readonly 'indexer.retries_exhausted': {
874
+ readonly surfaces: readonly ["indexer"];
875
+ readonly status: null;
876
+ readonly title: "Retry budget exhausted for a checkpoint";
877
+ readonly paymentState: "not_charged";
878
+ readonly retry: "never";
879
+ readonly nextAction: "contact_support";
880
+ readonly user: null;
881
+ readonly logOnly: true;
882
+ };
883
+ readonly 'indexer.stopped': {
884
+ readonly surfaces: readonly ["indexer"];
885
+ readonly status: null;
886
+ readonly title: "Indexer loop exited";
887
+ readonly paymentState: "not_charged";
888
+ readonly retry: "never";
889
+ readonly nextAction: "contact_support";
890
+ readonly user: null;
891
+ readonly logOnly: true;
892
+ };
893
+ readonly 'indexer.store_failed': {
894
+ readonly surfaces: readonly ["indexer"];
895
+ readonly status: null;
896
+ readonly title: "Indexer database write failed";
897
+ readonly paymentState: "not_charged";
898
+ readonly retry: "never";
899
+ readonly nextAction: "contact_support";
900
+ readonly user: null;
901
+ readonly logOnly: true;
902
+ };
903
+ readonly 'client.agent_handoff_failed': {
904
+ readonly surfaces: readonly ["browser", "mcp_local"];
905
+ readonly status: null;
906
+ readonly title: "Key hand-off to the local agent failed";
907
+ readonly paymentState: "not_charged";
908
+ readonly retry: "safe";
909
+ readonly nextAction: "retry";
910
+ readonly user: {
911
+ readonly title: "Couldn't reach your agent";
912
+ readonly message: "We couldn't pass the key to your agent. Try again.";
913
+ };
914
+ };
915
+ readonly 'client.already_paid': {
916
+ readonly surfaces: readonly ["browser"];
917
+ readonly status: null;
918
+ readonly title: "Request was already paid in this tab";
919
+ readonly paymentState: "charged";
920
+ readonly retry: "never";
921
+ readonly nextAction: "none";
922
+ readonly user: {
923
+ readonly title: "Already paid";
924
+ readonly message: "You already paid for this request in this tab.";
925
+ };
926
+ };
927
+ readonly 'client.build_failed': {
928
+ readonly surfaces: readonly ["sdk", "mcp_local", "browser"];
929
+ readonly status: null;
930
+ readonly title: "Payment transaction could not be built";
931
+ readonly paymentState: "not_charged";
932
+ readonly retry: "never";
933
+ readonly nextAction: "contact_support";
934
+ readonly user: {
935
+ readonly title: "Couldn't prepare payment";
936
+ readonly message: "We couldn't prepare this payment. If it keeps happening, contact support.";
937
+ };
938
+ };
939
+ readonly 'client.config_invalid': {
940
+ readonly surfaces: readonly ["sdk", "mcp_local"];
941
+ readonly status: null;
942
+ readonly title: "Client configuration is missing or invalid";
943
+ readonly paymentState: "not_charged";
944
+ readonly retry: "never";
945
+ readonly nextAction: "fix_request";
946
+ readonly user: {
947
+ readonly title: "Setup incomplete";
948
+ readonly message: "Your app is missing required settings. Check its setup and try again.";
949
+ };
950
+ };
951
+ readonly 'client.delivery_file_not_saved': {
952
+ readonly surfaces: readonly ["mcp_local"];
953
+ readonly status: null;
954
+ readonly title: "Paid result could not be written to a file";
955
+ readonly paymentState: "charged";
956
+ readonly retry: "never";
957
+ readonly nextAction: "contact_support";
958
+ readonly user: {
959
+ readonly title: "Result not saved";
960
+ readonly message: "The result couldn't be saved to a file.";
961
+ };
962
+ };
963
+ readonly 'client.gateway_unreachable': {
964
+ readonly surfaces: readonly ["browser", "sdk", "mcp_local"];
965
+ readonly status: null;
966
+ readonly title: "Payment service could not be reached";
967
+ readonly paymentState: "emitter";
968
+ readonly retry: "after_delay";
969
+ readonly retryAfterSeconds: 5;
970
+ readonly nextAction: "retry_later";
971
+ readonly user: {
972
+ readonly title: "Service unreachable";
973
+ readonly message: "We couldn't reach the payment service.";
974
+ };
975
+ };
976
+ readonly 'client.input_invalid': {
977
+ readonly surfaces: readonly ["browser"];
978
+ readonly status: null;
979
+ readonly title: "Form input failed local validation";
980
+ readonly paymentState: "not_charged";
981
+ readonly retry: "never";
982
+ readonly nextAction: "fix_request";
983
+ readonly user: {
984
+ readonly title: "Check the form";
985
+ readonly message: "Some fields need fixing. Check the highlighted fields and try again.";
986
+ };
987
+ };
988
+ readonly 'client.key_already_active': {
989
+ readonly surfaces: readonly ["browser"];
990
+ readonly status: null;
991
+ readonly title: "Edit asked to change a key that is already active";
992
+ readonly paymentState: "not_charged";
993
+ readonly retry: "never";
994
+ readonly nextAction: "fix_request";
995
+ readonly user: {
996
+ readonly title: "Key already active";
997
+ readonly message: "Nothing changed. To change this key's limits, revoke it and set it up again.";
998
+ };
999
+ };
1000
+ readonly 'client.key_invalid': {
1001
+ readonly surfaces: readonly ["browser", "mcp_local"];
1002
+ readonly status: null;
1003
+ readonly title: "Pasted or supplied key is not a delegate key";
1004
+ readonly paymentState: "not_charged";
1005
+ readonly retry: "never";
1006
+ readonly nextAction: "fix_request";
1007
+ readonly user: {
1008
+ readonly title: "Key not recognized";
1009
+ readonly message: "That isn't a valid agent key. Paste the key you saved when you set up access.";
1010
+ };
1011
+ };
1012
+ readonly 'client.ledger_failed': {
1013
+ readonly surfaces: readonly ["sdk", "mcp_local"];
1014
+ readonly status: null;
1015
+ readonly title: "Local payment ledger read or write failed";
1016
+ readonly paymentState: "emitter";
1017
+ readonly retry: "safe";
1018
+ readonly nextAction: "retry";
1019
+ readonly user: {
1020
+ readonly title: "Payment record not saved";
1021
+ readonly message: "We couldn't save this payment's record on your device.";
1022
+ };
1023
+ };
1024
+ readonly 'client.local_credentials_invalid': {
1025
+ readonly surfaces: readonly ["sdk", "mcp_local"];
1026
+ readonly status: null;
1027
+ readonly title: "Stored or environment credentials are unreadable, malformed or mismatched";
1028
+ readonly paymentState: "not_charged";
1029
+ readonly retry: "never";
1030
+ readonly nextAction: "sign_in";
1031
+ readonly user: {
1032
+ readonly title: "Saved key not usable";
1033
+ readonly message: "Your saved agent key is damaged or doesn't match. Sign in again to replace it.";
1034
+ };
1035
+ };
1036
+ readonly 'client.manifest_invalid': {
1037
+ readonly surfaces: readonly ["sdk", "mcp_local", "browser"];
1038
+ readonly status: null;
1039
+ readonly title: "Agent manifest is malformed or missing a field";
1040
+ readonly paymentState: "not_charged";
1041
+ readonly retry: "never";
1042
+ readonly nextAction: "fix_request";
1043
+ readonly user: {
1044
+ readonly title: "Access details incomplete";
1045
+ readonly message: "Your agent's access details are missing something. Set up access again.";
1046
+ };
1047
+ };
1048
+ readonly 'client.offline': {
1049
+ readonly surfaces: readonly ["browser"];
1050
+ readonly status: null;
1051
+ readonly title: "Browser is offline or the network request failed";
1052
+ readonly paymentState: "emitter";
1053
+ readonly retry: "after_delay";
1054
+ readonly retryAfterSeconds: 5;
1055
+ readonly nextAction: "retry_later";
1056
+ readonly user: {
1057
+ readonly title: "You're offline";
1058
+ readonly message: "Check your internet connection.";
1059
+ };
1060
+ };
1061
+ readonly 'client.page_stale': {
1062
+ readonly surfaces: readonly ["browser"];
1063
+ readonly status: null;
1064
+ readonly title: "Page state is missing data a reload restores";
1065
+ readonly paymentState: "not_charged";
1066
+ readonly retry: "never";
1067
+ readonly nextAction: "fix_request";
1068
+ readonly user: {
1069
+ readonly title: "Page out of date";
1070
+ readonly message: "This page is out of date. Reload it and try again.";
1071
+ };
1072
+ };
1073
+ readonly 'client.payer_misconfigured': {
1074
+ readonly surfaces: readonly ["sdk", "mcp_local", "browser"];
1075
+ readonly status: null;
1076
+ readonly title: "Payer lacks a required dependency (signer, executor, ledger or secret)";
1077
+ readonly paymentState: "not_charged";
1078
+ readonly retry: "never";
1079
+ readonly nextAction: "fix_request";
1080
+ readonly user: {
1081
+ readonly title: "Payment setup incomplete";
1082
+ readonly message: "Your app isn't set up to make this payment. Check its settings.";
1083
+ };
1084
+ };
1085
+ readonly 'client.payment_unresolved': {
1086
+ readonly surfaces: readonly ["browser", "sdk"];
1087
+ readonly status: null;
1088
+ readonly title: "An earlier payment did not resolve";
1089
+ readonly paymentState: "unknown";
1090
+ readonly retry: "never";
1091
+ readonly nextAction: "reconcile";
1092
+ readonly user: {
1093
+ readonly title: "Payment didn't finish";
1094
+ readonly message: "A payment didn't finish. Check its status.";
1095
+ };
1096
+ };
1097
+ readonly 'client.sign_failed': {
1098
+ readonly surfaces: readonly ["sdk", "mcp_local", "browser"];
1099
+ readonly status: null;
1100
+ readonly title: "Local signer failed";
1101
+ readonly paymentState: "not_charged";
1102
+ readonly retry: "safe";
1103
+ readonly nextAction: "retry";
1104
+ readonly user: {
1105
+ readonly title: "Couldn't sign";
1106
+ readonly message: "Your key couldn't sign this request. Try again.";
1107
+ };
1108
+ };
1109
+ readonly 'client.tx_mismatch': {
1110
+ readonly surfaces: readonly ["sdk", "mcp_local", "browser"];
1111
+ readonly status: null;
1112
+ readonly title: "Prepared transaction does not match the offer";
1113
+ readonly paymentState: "not_charged";
1114
+ readonly retry: "never";
1115
+ readonly nextAction: "contact_support";
1116
+ readonly user: {
1117
+ readonly title: "Payment stopped for safety";
1118
+ readonly message: "The transaction didn't match the quote, so we stopped before signing.";
1119
+ };
1120
+ };
1121
+ readonly 'client.unexpected': {
1122
+ readonly surfaces: readonly ["sdk", "mcp_local", "browser"];
1123
+ readonly status: null;
1124
+ readonly title: "Unexpected client error";
1125
+ readonly paymentState: "emitter";
1126
+ readonly retry: "never";
1127
+ readonly nextAction: "contact_support";
1128
+ readonly user: {
1129
+ readonly title: "Something went wrong";
1130
+ readonly message: "If it keeps happening, contact support.";
1131
+ };
1132
+ };
1133
+ readonly 'client.wallet_not_connected': {
1134
+ readonly surfaces: readonly ["browser"];
1135
+ readonly status: null;
1136
+ readonly title: "Action needs a connected, signed-in owner wallet";
1137
+ readonly paymentState: "not_charged";
1138
+ readonly retry: "never";
1139
+ readonly nextAction: "sign_in";
1140
+ readonly user: {
1141
+ readonly title: "Connect your wallet";
1142
+ readonly message: "Connect your wallet and sign in to continue.";
1143
+ };
1144
+ };
1145
+ readonly 'client.wallet_rejected': {
1146
+ readonly surfaces: readonly ["browser", "sdk"];
1147
+ readonly status: null;
1148
+ readonly title: "Wallet request was rejected by the user";
1149
+ readonly paymentState: "not_charged";
1150
+ readonly retry: "safe";
1151
+ readonly nextAction: "retry";
1152
+ readonly user: {
1153
+ readonly title: "Signature declined";
1154
+ readonly message: "You declined the request in your wallet. Try again when ready.";
1155
+ };
1156
+ };
1157
+ readonly 'service.internal': {
1158
+ readonly surfaces: readonly ["gateway", "seller", "console_server", "mcp_hosted"];
1159
+ readonly status: 500;
1160
+ readonly title: "Internal error";
1161
+ readonly paymentState: "emitter";
1162
+ readonly retry: "never";
1163
+ readonly nextAction: "contact_support";
1164
+ readonly user: {
1165
+ readonly title: "Something went wrong";
1166
+ readonly message: "If it keeps happening, contact support with the code below.";
1167
+ };
1168
+ };
1169
+ readonly 'service.unavailable': {
1170
+ readonly surfaces: readonly ["gateway", "console_server", "mcp_hosted", "browser"];
1171
+ readonly status: 503;
1172
+ readonly title: "Service temporarily unavailable";
1173
+ readonly paymentState: "not_charged";
1174
+ readonly retry: "after_delay";
1175
+ readonly retryAfterSeconds: 5;
1176
+ readonly nextAction: "retry_later";
1177
+ readonly user: {
1178
+ readonly title: "Temporarily unavailable";
1179
+ readonly message: "This isn't available right now. Try again in a moment.";
1180
+ };
1181
+ };
1182
+ readonly 'service.not_ready': {
1183
+ readonly surfaces: readonly ["gateway", "seller", "console_server"];
1184
+ readonly status: 503;
1185
+ readonly title: "Service is not ready";
1186
+ readonly paymentState: "not_charged";
1187
+ readonly retry: "after_delay";
1188
+ readonly retryAfterSeconds: 5;
1189
+ readonly nextAction: "retry_later";
1190
+ readonly user: null;
1191
+ readonly logOnly: true;
1192
+ };
1193
+ readonly 'service.job_failed': {
1194
+ readonly surfaces: readonly ["gateway"];
1195
+ readonly status: null;
1196
+ readonly title: "Background job attempt failed";
1197
+ readonly paymentState: "not_charged";
1198
+ readonly retry: "never";
1199
+ readonly nextAction: "none";
1200
+ readonly user: null;
1201
+ readonly logOnly: true;
1202
+ };
1203
+ readonly 'service.config_degraded': {
1204
+ readonly surfaces: readonly ["gateway"];
1205
+ readonly status: null;
1206
+ readonly title: "Service started with degraded configuration";
1207
+ readonly paymentState: "not_charged";
1208
+ readonly retry: "never";
1209
+ readonly nextAction: "none";
1210
+ readonly user: null;
1211
+ readonly logOnly: true;
1212
+ };
1213
+ readonly 'service.bookkeeping_failed': {
1214
+ readonly surfaces: readonly ["gateway"];
1215
+ readonly status: null;
1216
+ readonly title: "Best-effort record write failed";
1217
+ readonly paymentState: "not_charged";
1218
+ readonly retry: "never";
1219
+ readonly nextAction: "none";
1220
+ readonly user: null;
1221
+ readonly logOnly: true;
1222
+ };
1223
+ readonly 'limit.concurrency_exceeded': {
1224
+ readonly surfaces: readonly ["gateway"];
1225
+ readonly status: 429;
1226
+ readonly title: "Too many concurrent streams";
1227
+ readonly paymentState: "not_charged";
1228
+ readonly retry: "after_delay";
1229
+ readonly retryAfterSeconds: 5;
1230
+ readonly nextAction: "retry_later";
1231
+ readonly user: {
1232
+ readonly title: "Too many open connections";
1233
+ readonly message: "You have too many open connections. Close some and try again.";
1234
+ };
1235
+ };
1236
+ readonly 'limit.gas_quota_exceeded': {
1237
+ readonly surfaces: readonly ["gateway"];
1238
+ readonly status: 429;
1239
+ readonly title: "Per-signer gas sponsorship quota exceeded";
1240
+ readonly paymentState: "not_charged";
1241
+ readonly retry: "after_delay";
1242
+ readonly retryAfterSeconds: 3600;
1243
+ readonly nextAction: "retry_later";
1244
+ readonly user: {
1245
+ readonly title: "Fee cover limit reached";
1246
+ readonly message: "You've used up your covered network fees for now. Try again later.";
1247
+ };
1248
+ };
1249
+ readonly 'limit.rate_limited': {
1250
+ readonly surfaces: readonly ["gateway", "console_server"];
1251
+ readonly status: 429;
1252
+ readonly title: "Rate limit exceeded";
1253
+ readonly paymentState: "not_charged";
1254
+ readonly retry: "after_delay";
1255
+ readonly retryAfterSeconds: 30;
1256
+ readonly nextAction: "retry_later";
1257
+ readonly user: {
1258
+ readonly title: "Too many requests";
1259
+ readonly message: "You're sending requests too fast. Wait a moment and try again.";
1260
+ };
1261
+ };
1262
+ readonly 'chain.tx_failed': {
1263
+ readonly surfaces: readonly ["gateway", "sdk", "browser"];
1264
+ readonly status: 502;
1265
+ readonly title: "Transaction failed on chain";
1266
+ readonly paymentState: "not_charged";
1267
+ readonly retry: "safe";
1268
+ readonly nextAction: "retry";
1269
+ readonly user: {
1270
+ readonly title: "Transaction failed";
1271
+ readonly message: "The network rejected your transaction. Check the details and try again.";
1272
+ };
1273
+ };
1274
+ readonly 'chain.tx_not_final': {
1275
+ readonly surfaces: readonly ["gateway"];
1276
+ readonly status: 409;
1277
+ readonly title: "Owner transaction is not final yet";
1278
+ readonly paymentState: "not_charged";
1279
+ readonly retry: "after_delay";
1280
+ readonly retryAfterSeconds: 3;
1281
+ readonly nextAction: "retry_later";
1282
+ readonly user: {
1283
+ readonly title: "Still confirming";
1284
+ readonly message: "Your transaction is still being confirmed. Try again in a few seconds.";
1285
+ };
1286
+ };
1287
+ readonly 'chain.tx_unconfirmed': {
1288
+ readonly surfaces: readonly ["sdk", "browser"];
1289
+ readonly status: null;
1290
+ readonly title: "Owner transaction was submitted but finality is not confirmed";
1291
+ readonly paymentState: "unknown";
1292
+ readonly retry: "never";
1293
+ readonly nextAction: "reconcile";
1294
+ readonly user: {
1295
+ readonly title: "Transaction still processing";
1296
+ readonly message: "Your transaction was sent but isn't confirmed yet. Check its status before doing anything else.";
1297
+ };
1298
+ };
1299
+ readonly 'chain.tx_unverified': {
1300
+ readonly surfaces: readonly ["gateway"];
1301
+ readonly status: 502;
1302
+ readonly title: "Transaction effects could not be verified";
1303
+ readonly paymentState: "unknown";
1304
+ readonly retry: "never";
1305
+ readonly nextAction: "reconcile";
1306
+ readonly user: {
1307
+ readonly title: "Couldn't verify transaction";
1308
+ readonly message: "We couldn't confirm your transaction's result. Check its status before doing anything else.";
1309
+ };
1310
+ };
1311
+ readonly 'chain.unavailable': {
1312
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
1313
+ readonly status: 503;
1314
+ readonly title: "Chain read failed or the network is unavailable";
1315
+ readonly paymentState: "emitter";
1316
+ readonly retry: "after_delay";
1317
+ readonly retryAfterSeconds: 5;
1318
+ readonly nextAction: "retry_later";
1319
+ readonly user: {
1320
+ readonly title: "Network busy";
1321
+ readonly message: "We couldn't reach the network.";
1322
+ };
1323
+ };
1324
+ readonly 'chain.event_legacy_field': {
1325
+ readonly surfaces: readonly ["gateway", "sdk"];
1326
+ readonly status: null;
1327
+ readonly title: "On-chain event carries a legacy field";
1328
+ readonly paymentState: "not_charged";
1329
+ readonly retry: "never";
1330
+ readonly nextAction: "none";
1331
+ readonly user: null;
1332
+ readonly logOnly: true;
1333
+ };
1334
+ readonly 'sponsor.challenge_invalid': {
1335
+ readonly surfaces: readonly ["gateway"];
1336
+ readonly status: 403;
1337
+ readonly title: "Sponsor challenge expired or its nonce was rejected";
1338
+ readonly paymentState: "not_charged";
1339
+ readonly retry: "safe";
1340
+ readonly nextAction: "retry";
1341
+ readonly user: {
1342
+ readonly title: "Fee cover expired";
1343
+ readonly message: "Your request for a covered network fee expired. Start again.";
1344
+ };
1345
+ };
1346
+ readonly 'sponsor.execute_auth_invalid': {
1347
+ readonly surfaces: readonly ["gateway"];
1348
+ readonly status: 403;
1349
+ readonly title: "Sponsored execute authorization is missing, invalid or expired";
1350
+ readonly paymentState: "not_charged";
1351
+ readonly retry: "safe";
1352
+ readonly nextAction: "retry";
1353
+ readonly user: {
1354
+ readonly title: "Fee cover not confirmed";
1355
+ readonly message: "Your approval for the covered fee is missing or expired. Start again.";
1356
+ };
1357
+ };
1358
+ readonly 'sponsor.execute_digest_mismatch': {
1359
+ readonly surfaces: readonly ["gateway"];
1360
+ readonly status: 502;
1361
+ readonly title: "Executed digest does not match the sponsored transaction";
1362
+ readonly paymentState: "unknown";
1363
+ readonly retry: "never";
1364
+ readonly nextAction: "reconcile";
1365
+ readonly user: {
1366
+ readonly title: "Transaction needs checking";
1367
+ readonly message: "We can't confirm what was sent. Check its status before doing anything else.";
1368
+ };
1369
+ };
1370
+ readonly 'sponsor.execute_failed': {
1371
+ readonly surfaces: readonly ["gateway"];
1372
+ readonly status: 502;
1373
+ readonly title: "Sponsored transaction executed and aborted on chain";
1374
+ readonly paymentState: "not_charged";
1375
+ readonly retry: "never";
1376
+ readonly nextAction: "fix_request";
1377
+ readonly user: {
1378
+ readonly title: "Transaction failed";
1379
+ readonly message: "The network rejected this transaction. Check the details and try again.";
1380
+ };
1381
+ };
1382
+ readonly 'sponsor.execute_not_pending': {
1383
+ readonly surfaces: readonly ["gateway"];
1384
+ readonly status: 409;
1385
+ readonly title: "Sponsored transaction is no longer pending";
1386
+ readonly paymentState: "unknown";
1387
+ readonly retry: "never";
1388
+ readonly nextAction: "reconcile";
1389
+ readonly user: {
1390
+ readonly title: "Already submitted";
1391
+ readonly message: "This transaction may already have been sent. Check its status before doing anything else.";
1392
+ };
1393
+ };
1394
+ readonly 'sponsor.execute_outcome_unknown': {
1395
+ readonly surfaces: readonly ["gateway"];
1396
+ readonly status: 503;
1397
+ readonly title: "Sponsored execute outcome is unknown";
1398
+ readonly paymentState: "unknown";
1399
+ readonly retry: "never";
1400
+ readonly retryAfterSeconds: 10;
1401
+ readonly nextAction: "reconcile";
1402
+ readonly user: {
1403
+ readonly title: "Transaction still processing";
1404
+ readonly message: "We can't confirm this transaction yet. Check its status before doing anything else.";
1405
+ };
1406
+ };
1407
+ readonly 'sponsor.gas_lease_invalid': {
1408
+ readonly surfaces: readonly ["gateway"];
1409
+ readonly status: 402;
1410
+ readonly title: "Gas lease is missing, expired or in the wrong state";
1411
+ readonly paymentState: "not_charged";
1412
+ readonly retry: "safe";
1413
+ readonly nextAction: "retry";
1414
+ readonly user: {
1415
+ readonly title: "Fee cover expired";
1416
+ readonly message: "The covered network fee for this quote expired. Get a new quote and try again.";
1417
+ };
1418
+ };
1419
+ readonly 'sponsor.gas_pin_invalid': {
1420
+ readonly surfaces: readonly ["gateway"];
1421
+ readonly status: 402;
1422
+ readonly title: "Transaction gas does not match the pinned sponsor gas";
1423
+ readonly paymentState: "not_charged";
1424
+ readonly retry: "never";
1425
+ readonly nextAction: "fix_request";
1426
+ readonly user: {
1427
+ readonly title: "Fee details not valid";
1428
+ readonly message: "The network fee in your payment doesn't match the quote. Update your app and try again.";
1429
+ };
1430
+ };
1431
+ readonly 'sponsor.kind_rejected': {
1432
+ readonly surfaces: readonly ["gateway"];
1433
+ readonly status: 403;
1434
+ readonly title: "Transaction kind is not sponsorable";
1435
+ readonly paymentState: "not_charged";
1436
+ readonly retry: "never";
1437
+ readonly nextAction: "fix_request";
1438
+ readonly user: {
1439
+ readonly title: "Fee can't be covered";
1440
+ readonly message: "We can't cover your network fee for this kind of transaction.";
1441
+ };
1442
+ };
1443
+ readonly 'sponsor.personal_message_invalid': {
1444
+ readonly surfaces: readonly ["gateway"];
1445
+ readonly status: 403;
1446
+ readonly title: "Sponsor personal-message approval is missing or invalid";
1447
+ readonly paymentState: "not_charged";
1448
+ readonly retry: "never";
1449
+ readonly nextAction: "fix_request";
1450
+ readonly user: {
1451
+ readonly title: "Approval not valid";
1452
+ readonly message: "Your approval signature didn't check out. Sign again with the right key.";
1453
+ };
1454
+ };
1455
+ readonly 'sponsor.sponsorship_not_found': {
1456
+ readonly surfaces: readonly ["gateway"];
1457
+ readonly status: 409;
1458
+ readonly title: "Sponsored digest has no known sponsorship";
1459
+ readonly paymentState: "not_charged";
1460
+ readonly retry: "safe";
1461
+ readonly nextAction: "retry";
1462
+ readonly user: {
1463
+ readonly title: "Fee cover not found";
1464
+ readonly message: "We couldn't find the fee cover for this transaction. Start again.";
1465
+ };
1466
+ };
1467
+ readonly 'sponsor.target_not_allowed': {
1468
+ readonly surfaces: readonly ["gateway"];
1469
+ readonly status: 400;
1470
+ readonly title: "Move call target is not sponsorable";
1471
+ readonly paymentState: "not_charged";
1472
+ readonly retry: "never";
1473
+ readonly nextAction: "fix_request";
1474
+ readonly user: {
1475
+ readonly title: "Action can't be covered";
1476
+ readonly message: "We can't cover your network fee for that action.";
1477
+ };
1478
+ };
1479
+ readonly 'sponsor.tx_mismatch': {
1480
+ readonly surfaces: readonly ["sdk", "mcp_local"];
1481
+ readonly status: null;
1482
+ readonly title: "Sponsored transaction bytes do not reconstruct the payment";
1483
+ readonly paymentState: "not_charged";
1484
+ readonly retry: "never";
1485
+ readonly nextAction: "contact_support";
1486
+ readonly user: {
1487
+ readonly title: "Payment stopped for safety";
1488
+ readonly message: "The prepared transaction didn't match your payment, so we stopped before signing.";
1489
+ };
1490
+ };
1491
+ readonly 'sponsor.unavailable': {
1492
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "browser"];
1493
+ readonly status: 503;
1494
+ readonly title: "Gas sponsorship is unavailable";
1495
+ readonly paymentState: "not_charged";
1496
+ readonly retry: "after_delay";
1497
+ readonly retryAfterSeconds: 10;
1498
+ readonly nextAction: "retry_later";
1499
+ readonly user: {
1500
+ readonly title: "Fee cover unavailable";
1501
+ readonly message: "Covered network fees are unavailable right now. Try again in a moment.";
1502
+ };
1503
+ };
1504
+ readonly 'sponsor.would_abort': {
1505
+ readonly surfaces: readonly ["gateway"];
1506
+ readonly status: 422;
1507
+ readonly title: "Sponsored dry run would abort";
1508
+ readonly paymentState: "not_charged";
1509
+ readonly retry: "never";
1510
+ readonly nextAction: "fix_request";
1511
+ readonly user: {
1512
+ readonly title: "Transaction would fail";
1513
+ readonly message: "A test run shows this transaction would fail. Check the details and try again.";
1514
+ };
1515
+ };
1516
+ readonly 'seller.config_locked': {
1517
+ readonly surfaces: readonly ["seller"];
1518
+ readonly status: 403;
1519
+ readonly title: "Seller configuration is locked";
1520
+ readonly paymentState: "emitter";
1521
+ readonly retry: "never";
1522
+ readonly nextAction: "fix_request";
1523
+ readonly user: {
1524
+ readonly title: "Settings locked";
1525
+ readonly message: "Settings are locked. Use the settings token to change them.";
1526
+ };
1527
+ };
1528
+ readonly 'seller.config_origin_rejected': {
1529
+ readonly surfaces: readonly ["seller"];
1530
+ readonly status: 403;
1531
+ readonly title: "Configuration request came from a foreign origin";
1532
+ readonly paymentState: "emitter";
1533
+ readonly retry: "never";
1534
+ readonly nextAction: "fix_request";
1535
+ readonly user: {
1536
+ readonly title: "Request blocked";
1537
+ readonly message: "You can only change settings from this server's own setup page.";
1538
+ };
1539
+ };
1540
+ readonly 'seller.config_pinned': {
1541
+ readonly surfaces: readonly ["seller"];
1542
+ readonly status: 400;
1543
+ readonly title: "Gateway binding is pinned by environment";
1544
+ readonly paymentState: "emitter";
1545
+ readonly retry: "never";
1546
+ readonly nextAction: "fix_request";
1547
+ readonly user: {
1548
+ readonly title: "Settings set by the server";
1549
+ readonly message: "These settings come from the server's environment, so you can't change them here.";
1550
+ };
1551
+ };
1552
+ readonly 'seller.content_too_large': {
1553
+ readonly surfaces: readonly ["seller", "gateway"];
1554
+ readonly status: 413;
1555
+ readonly title: "Content exceeds the seller's storage limit";
1556
+ readonly paymentState: "emitter";
1557
+ readonly retry: "never";
1558
+ readonly nextAction: "fix_request";
1559
+ readonly user: {
1560
+ readonly title: "Content too large";
1561
+ readonly message: "What you sent is too large to store.";
1562
+ };
1563
+ };
1564
+ readonly 'seller.delivery_proof_expired': {
1565
+ readonly surfaces: readonly ["seller"];
1566
+ readonly status: 401;
1567
+ readonly title: "Delivery proof has expired";
1568
+ readonly paymentState: "emitter";
1569
+ readonly retry: "never";
1570
+ readonly nextAction: "contact_support";
1571
+ readonly user: {
1572
+ readonly title: "Request not accepted";
1573
+ readonly message: "The service couldn't confirm this request in time. Contact support with the code below.";
1574
+ };
1575
+ };
1576
+ readonly 'seller.delivery_proof_malformed': {
1577
+ readonly surfaces: readonly ["seller"];
1578
+ readonly status: 403;
1579
+ readonly title: "Delivery proof claims are malformed";
1580
+ readonly paymentState: "emitter";
1581
+ readonly retry: "never";
1582
+ readonly nextAction: "contact_support";
1583
+ readonly user: {
1584
+ readonly title: "Request not accepted";
1585
+ readonly message: "The service couldn't read the confirmation for this request. Contact support with the code below.";
1586
+ };
1587
+ };
1588
+ readonly 'seller.delivery_proof_missing': {
1589
+ readonly surfaces: readonly ["seller"];
1590
+ readonly status: 401;
1591
+ readonly title: "Paid request arrived without a delivery proof";
1592
+ readonly paymentState: "emitter";
1593
+ readonly retry: "never";
1594
+ readonly nextAction: "contact_support";
1595
+ readonly user: {
1596
+ readonly title: "Request not accepted";
1597
+ readonly message: "The service didn't receive the confirmation for this request. Contact support with the code below.";
1598
+ };
1599
+ };
1600
+ readonly 'seller.delivery_proof_mismatch': {
1601
+ readonly surfaces: readonly ["seller"];
1602
+ readonly status: 403;
1603
+ readonly title: "Delivery proof does not match the request";
1604
+ readonly paymentState: "emitter";
1605
+ readonly retry: "never";
1606
+ readonly nextAction: "contact_support";
1607
+ readonly user: {
1608
+ readonly title: "Request not accepted";
1609
+ readonly message: "The confirmation didn't match this request. Contact support with the code below.";
1610
+ };
1611
+ };
1612
+ readonly 'seller.delivery_proof_replayed': {
1613
+ readonly surfaces: readonly ["seller"];
1614
+ readonly status: 403;
1615
+ readonly title: "Delivery proof was already used";
1616
+ readonly paymentState: "emitter";
1617
+ readonly retry: "never";
1618
+ readonly nextAction: "contact_support";
1619
+ readonly user: {
1620
+ readonly title: "Request not accepted";
1621
+ readonly message: "This request was already served once. Contact support with the code below.";
1622
+ };
1623
+ };
1624
+ readonly 'seller.delivery_proof_unknown_audience': {
1625
+ readonly surfaces: readonly ["seller"];
1626
+ readonly status: 403;
1627
+ readonly title: "Delivery proof is for a different audience";
1628
+ readonly paymentState: "emitter";
1629
+ readonly retry: "never";
1630
+ readonly nextAction: "contact_support";
1631
+ readonly user: {
1632
+ readonly title: "Request not accepted";
1633
+ readonly message: "This request was meant for a different service. Contact support with the code below.";
1634
+ };
1635
+ };
1636
+ readonly 'seller.delivery_proof_unknown_service': {
1637
+ readonly surfaces: readonly ["seller"];
1638
+ readonly status: 403;
1639
+ readonly title: "Delivery proof names an unknown service";
1640
+ readonly paymentState: "emitter";
1641
+ readonly retry: "never";
1642
+ readonly nextAction: "contact_support";
1643
+ readonly user: {
1644
+ readonly title: "Request not accepted";
1645
+ readonly message: "The service didn't recognize this request. Contact support with the code below.";
1646
+ };
1647
+ };
1648
+ readonly 'seller.delivery_proof_verify_failed': {
1649
+ readonly surfaces: readonly ["seller"];
1650
+ readonly status: 401;
1651
+ readonly title: "Delivery proof signature did not verify";
1652
+ readonly paymentState: "emitter";
1653
+ readonly retry: "never";
1654
+ readonly nextAction: "contact_support";
1655
+ readonly user: {
1656
+ readonly title: "Request not accepted";
1657
+ readonly message: "The service couldn't confirm this request came through us. Contact support with the code below.";
1658
+ };
1659
+ };
1660
+ readonly 'seller.execution_failed': {
1661
+ readonly surfaces: readonly ["seller", "gateway"];
1662
+ readonly status: 502;
1663
+ readonly title: "Buyer's code exited with an error";
1664
+ readonly paymentState: "emitter";
1665
+ readonly retry: "never";
1666
+ readonly nextAction: "fix_request";
1667
+ readonly user: {
1668
+ readonly title: "Your code failed";
1669
+ readonly message: "Your code stopped with an error.";
1670
+ };
1671
+ };
1672
+ readonly 'seller.gateway_invalid': {
1673
+ readonly surfaces: readonly ["seller"];
1674
+ readonly status: 400;
1675
+ readonly title: "Address is not a payment gateway or its issuer does not match";
1676
+ readonly paymentState: "emitter";
1677
+ readonly retry: "never";
1678
+ readonly nextAction: "fix_request";
1679
+ readonly user: {
1680
+ readonly title: "Not a payment gateway";
1681
+ readonly message: "That address doesn't look like a payment gateway. Check it.";
1682
+ };
1683
+ };
1684
+ readonly 'seller.gateway_unreachable': {
1685
+ readonly surfaces: readonly ["seller"];
1686
+ readonly status: 400;
1687
+ readonly title: "Gateway could not be reached while binding";
1688
+ readonly paymentState: "emitter";
1689
+ readonly retry: "safe";
1690
+ readonly nextAction: "retry";
1691
+ readonly user: {
1692
+ readonly title: "Couldn't reach the gateway";
1693
+ readonly message: "We couldn't reach that gateway. Check the address.";
1694
+ };
1695
+ };
1696
+ readonly 'seller.gateway_url_invalid': {
1697
+ readonly surfaces: readonly ["seller"];
1698
+ readonly status: 400;
1699
+ readonly title: "Gateway URL is missing, malformed or not allowed";
1700
+ readonly paymentState: "emitter";
1701
+ readonly retry: "never";
1702
+ readonly nextAction: "fix_request";
1703
+ readonly user: {
1704
+ readonly title: "Check the gateway address";
1705
+ readonly message: "Enter a public https address for the gateway, with no username or password.";
1706
+ };
1707
+ };
1708
+ readonly 'seller.invalid_input': {
1709
+ readonly surfaces: readonly ["seller", "gateway"];
1710
+ readonly status: 400;
1711
+ readonly title: "Seller rejected the request input";
1712
+ readonly paymentState: "emitter";
1713
+ readonly retry: "never";
1714
+ readonly nextAction: "fix_request";
1715
+ readonly user: {
1716
+ readonly title: "Check your request";
1717
+ readonly message: "The service couldn't use what you sent. Fix the request.";
1718
+ };
1719
+ };
1720
+ readonly 'seller.not_configured': {
1721
+ readonly surfaces: readonly ["seller", "gateway"];
1722
+ readonly status: 503;
1723
+ readonly title: "Seller product or gateway binding is not configured";
1724
+ readonly paymentState: "emitter";
1725
+ readonly retry: "never";
1726
+ readonly retryAfterSeconds: 60;
1727
+ readonly nextAction: "contact_support";
1728
+ readonly user: {
1729
+ readonly title: "Service not set up";
1730
+ readonly message: "This service isn't set up yet.";
1731
+ };
1732
+ };
1733
+ readonly 'seller.not_ready': {
1734
+ readonly surfaces: readonly ["seller", "gateway"];
1735
+ readonly status: 503;
1736
+ readonly title: "Seller failed its readiness check";
1737
+ readonly paymentState: "emitter";
1738
+ readonly retry: "after_delay";
1739
+ readonly retryAfterSeconds: 30;
1740
+ readonly nextAction: "retry_later";
1741
+ readonly user: {
1742
+ readonly title: "Service not ready";
1743
+ readonly message: "This service isn't ready right now.";
1744
+ };
1745
+ };
1746
+ readonly 'seller.canonical_price_unavailable': {
1747
+ readonly surfaces: readonly ["seller"];
1748
+ readonly status: 503;
1749
+ readonly title: "Seller could not read the canonical price";
1750
+ readonly paymentState: "emitter";
1751
+ readonly retry: "never";
1752
+ readonly retryAfterSeconds: 30;
1753
+ readonly nextAction: "contact_support";
1754
+ readonly user: {
1755
+ readonly title: "Service not ready";
1756
+ readonly message: "This service can't confirm its price right now.";
1757
+ };
1758
+ };
1759
+ readonly 'seller.price_mismatch': {
1760
+ readonly surfaces: readonly ["seller"];
1761
+ readonly status: 503;
1762
+ readonly title: "Seller price does not match the canonical price";
1763
+ readonly paymentState: "emitter";
1764
+ readonly retry: "never";
1765
+ readonly retryAfterSeconds: 60;
1766
+ readonly nextAction: "contact_support";
1767
+ readonly user: {
1768
+ readonly title: "Service not ready";
1769
+ readonly message: "This service's price is being updated.";
1770
+ };
1771
+ };
1772
+ readonly 'seller.quota_exhausted': {
1773
+ readonly surfaces: readonly ["seller", "gateway"];
1774
+ readonly status: 503;
1775
+ readonly title: "Seller's vendor quota or credits are exhausted";
1776
+ readonly paymentState: "emitter";
1777
+ readonly retry: "after_delay";
1778
+ readonly retryAfterSeconds: 300;
1779
+ readonly nextAction: "retry_later";
1780
+ readonly user: {
1781
+ readonly title: "Service at capacity";
1782
+ readonly message: "This service has used up its capacity for now.";
1783
+ };
1784
+ };
1785
+ readonly 'seller.rate_limited': {
1786
+ readonly surfaces: readonly ["seller", "gateway"];
1787
+ readonly status: 503;
1788
+ readonly title: "Seller's vendor is rate limiting or throttling";
1789
+ readonly paymentState: "emitter";
1790
+ readonly retry: "after_delay";
1791
+ readonly retryAfterSeconds: 30;
1792
+ readonly nextAction: "retry_later";
1793
+ readonly user: {
1794
+ readonly title: "Service busy";
1795
+ readonly message: "This service is busy.";
1796
+ };
1797
+ };
1798
+ readonly 'seller.registration_rejected': {
1799
+ readonly surfaces: readonly ["seller"];
1800
+ readonly status: null;
1801
+ readonly title: "Gateway rejected the seller registration";
1802
+ readonly paymentState: "emitter";
1803
+ readonly retry: "never";
1804
+ readonly nextAction: "contact_support";
1805
+ readonly user: null;
1806
+ readonly logOnly: true;
1807
+ };
1808
+ readonly 'seller.registration_unreachable': {
1809
+ readonly surfaces: readonly ["seller"];
1810
+ readonly status: null;
1811
+ readonly title: "Gateway was unreachable during seller registration";
1812
+ readonly paymentState: "emitter";
1813
+ readonly retry: "after_delay";
1814
+ readonly retryAfterSeconds: 30;
1815
+ readonly nextAction: "retry_later";
1816
+ readonly user: null;
1817
+ readonly logOnly: true;
1818
+ };
1819
+ readonly 'seller.storage_full': {
1820
+ readonly surfaces: readonly ["seller", "gateway"];
1821
+ readonly status: 503;
1822
+ readonly title: "Seller's storage has insufficient space";
1823
+ readonly paymentState: "emitter";
1824
+ readonly retry: "after_delay";
1825
+ readonly retryAfterSeconds: 300;
1826
+ readonly nextAction: "retry_later";
1827
+ readonly user: {
1828
+ readonly title: "Storage full";
1829
+ readonly message: "Storage is full right now.";
1830
+ };
1831
+ };
1832
+ readonly 'seller.storage_guarantee_failed': {
1833
+ readonly surfaces: readonly ["seller", "gateway"];
1834
+ readonly status: 502;
1835
+ readonly title: "Stored content does not meet the permanence or window guarantee";
1836
+ readonly paymentState: "emitter";
1837
+ readonly retry: "never";
1838
+ readonly nextAction: "contact_support";
1839
+ readonly user: {
1840
+ readonly title: "Couldn't confirm storage";
1841
+ readonly message: "We couldn't confirm your data will be kept as long as promised.";
1842
+ };
1843
+ };
1844
+ readonly 'seller.upstream_auth_failed': {
1845
+ readonly surfaces: readonly ["seller", "gateway"];
1846
+ readonly status: 502;
1847
+ readonly title: "Seller's vendor credentials were refused";
1848
+ readonly paymentState: "emitter";
1849
+ readonly retry: "never";
1850
+ readonly nextAction: "contact_support";
1851
+ readonly user: {
1852
+ readonly title: "Service not working";
1853
+ readonly message: "This service can't reach its provider right now.";
1854
+ };
1855
+ };
1856
+ readonly 'seller.upstream_failed': {
1857
+ readonly surfaces: readonly ["seller", "gateway"];
1858
+ readonly status: 502;
1859
+ readonly title: "Seller's vendor returned an error";
1860
+ readonly paymentState: "emitter";
1861
+ readonly retry: "after_delay";
1862
+ readonly retryAfterSeconds: 10;
1863
+ readonly nextAction: "retry_later";
1864
+ readonly user: {
1865
+ readonly title: "Service error";
1866
+ readonly message: "This service hit an error.";
1867
+ };
1868
+ };
1869
+ readonly 'seller.upstream_malformed': {
1870
+ readonly surfaces: readonly ["seller", "gateway"];
1871
+ readonly status: 502;
1872
+ readonly title: "Seller's vendor returned a malformed response";
1873
+ readonly paymentState: "emitter";
1874
+ readonly retry: "never";
1875
+ readonly nextAction: "contact_support";
1876
+ readonly user: {
1877
+ readonly title: "Service error";
1878
+ readonly message: "This service couldn't read its provider's answer. Contact support if it keeps happening.";
1879
+ };
1880
+ };
1881
+ readonly 'seller.upstream_response_too_large': {
1882
+ readonly surfaces: readonly ["seller", "gateway"];
1883
+ readonly status: 502;
1884
+ readonly title: "Seller's vendor response exceeded the size limit";
1885
+ readonly paymentState: "emitter";
1886
+ readonly retry: "never";
1887
+ readonly nextAction: "contact_support";
1888
+ readonly user: {
1889
+ readonly title: "Result too large";
1890
+ readonly message: "The result was too large for this service to return to you.";
1891
+ };
1892
+ };
1893
+ readonly 'seller.upstream_timeout': {
1894
+ readonly surfaces: readonly ["seller", "gateway"];
1895
+ readonly status: 504;
1896
+ readonly title: "Seller's vendor timed out";
1897
+ readonly paymentState: "emitter";
1898
+ readonly retry: "after_delay";
1899
+ readonly retryAfterSeconds: 10;
1900
+ readonly nextAction: "retry_later";
1901
+ readonly user: {
1902
+ readonly title: "Service too slow";
1903
+ readonly message: "This service took too long to answer.";
1904
+ };
1905
+ };
1906
+ readonly 'seller.upstream_unavailable': {
1907
+ readonly surfaces: readonly ["seller", "gateway"];
1908
+ readonly status: 503;
1909
+ readonly title: "Seller's vendor is unavailable";
1910
+ readonly paymentState: "emitter";
1911
+ readonly retry: "after_delay";
1912
+ readonly retryAfterSeconds: 30;
1913
+ readonly nextAction: "retry_later";
1914
+ readonly user: {
1915
+ readonly title: "Service unavailable";
1916
+ readonly message: "This service's provider is unavailable.";
1917
+ };
1918
+ };
1919
+ readonly 'delivery.seller_unreachable': {
1920
+ readonly surfaces: readonly ["gateway"];
1921
+ readonly status: 502;
1922
+ readonly title: "Seller did not respond after payment";
1923
+ readonly paymentState: "charged";
1924
+ readonly retry: "never";
1925
+ readonly nextAction: "contact_support";
1926
+ readonly user: {
1927
+ readonly title: "Something went wrong";
1928
+ readonly message: "No result came back from the service.";
1929
+ };
1930
+ };
1931
+ readonly 'delivery.seller_timeout': {
1932
+ readonly surfaces: readonly ["gateway"];
1933
+ readonly status: 504;
1934
+ readonly title: "Seller timed out after payment";
1935
+ readonly paymentState: "charged";
1936
+ readonly retry: "never";
1937
+ readonly nextAction: "contact_support";
1938
+ readonly user: {
1939
+ readonly title: "Something went wrong";
1940
+ readonly message: "The service took too long to answer.";
1941
+ };
1942
+ };
1943
+ readonly 'delivery.seller_rejected': {
1944
+ readonly surfaces: readonly ["gateway", "seller"];
1945
+ readonly status: 502;
1946
+ readonly title: "Seller rejected the paid request";
1947
+ readonly paymentState: "charged";
1948
+ readonly retry: "never";
1949
+ readonly nextAction: "contact_support";
1950
+ readonly user: {
1951
+ readonly title: "Request not completed";
1952
+ readonly message: "The service didn't accept this request.";
1953
+ };
1954
+ };
1955
+ readonly 'delivery.seller_failed': {
1956
+ readonly surfaces: readonly ["gateway", "seller"];
1957
+ readonly status: 502;
1958
+ readonly title: "Seller failed while serving the paid request";
1959
+ readonly paymentState: "charged";
1960
+ readonly retry: "never";
1961
+ readonly nextAction: "contact_support";
1962
+ readonly user: {
1963
+ readonly title: "Something went wrong";
1964
+ readonly message: "The service failed while handling this request.";
1965
+ };
1966
+ };
1967
+ readonly 'delivery.seller_redirect_refused': {
1968
+ readonly surfaces: readonly ["gateway"];
1969
+ readonly status: 502;
1970
+ readonly title: "Seller answered the paid request with a redirect";
1971
+ readonly paymentState: "charged";
1972
+ readonly retry: "never";
1973
+ readonly nextAction: "contact_support";
1974
+ readonly user: {
1975
+ readonly title: "Something went wrong";
1976
+ readonly message: "The service didn't return a result.";
1977
+ };
1978
+ };
1979
+ readonly 'delivery.response_too_large': {
1980
+ readonly surfaces: readonly ["gateway"];
1981
+ readonly status: 502;
1982
+ readonly title: "Seller response exceeded the size limit";
1983
+ readonly paymentState: "charged";
1984
+ readonly retry: "never";
1985
+ readonly nextAction: "contact_support";
1986
+ readonly user: {
1987
+ readonly title: "Result too large";
1988
+ readonly message: "The result was too large to deliver.";
1989
+ };
1990
+ };
1991
+ readonly 'delivery.proof_unavailable': {
1992
+ readonly surfaces: readonly ["gateway"];
1993
+ readonly status: 503;
1994
+ readonly title: "Delivery proof could not be produced after payment";
1995
+ readonly paymentState: "charged";
1996
+ readonly retry: "never";
1997
+ readonly retryAfterSeconds: 10;
1998
+ readonly nextAction: "reconcile";
1999
+ readonly user: {
2000
+ readonly title: "Result delayed";
2001
+ readonly message: "Your result is delayed. Check the payment status later.";
2002
+ };
2003
+ };
2004
+ readonly 'delivery.reconciliation_required': {
2005
+ readonly surfaces: readonly ["gateway"];
2006
+ readonly status: 409;
2007
+ readonly title: "Settled payment needs reconciliation before delivery";
2008
+ readonly paymentState: "charged";
2009
+ readonly retry: "never";
2010
+ readonly nextAction: "reconcile";
2011
+ readonly user: {
2012
+ readonly title: "Result delayed";
2013
+ readonly message: "Your result needs a status check before it can be delivered.";
2014
+ };
2015
+ };
2016
+ readonly 'delivery.proof_rejected': {
2017
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted"];
2018
+ readonly status: 502;
2019
+ readonly title: "Resource refused the paid proof after finality";
2020
+ readonly paymentState: "charged";
2021
+ readonly retry: "never";
2022
+ readonly nextAction: "contact_support";
2023
+ readonly user: {
2024
+ readonly title: "Something went wrong";
2025
+ readonly message: "The result couldn't be delivered.";
2026
+ };
2027
+ };
2028
+ readonly 'delivery.internal': {
2029
+ readonly surfaces: readonly ["gateway", "seller"];
2030
+ readonly status: 500;
2031
+ readonly title: "Internal error after payment";
2032
+ readonly paymentState: "charged";
2033
+ readonly retry: "never";
2034
+ readonly nextAction: "contact_support";
2035
+ readonly user: {
2036
+ readonly title: "Something went wrong";
2037
+ readonly message: "No result came back. Contact support with the code below.";
2038
+ };
2039
+ };
2040
+ readonly 'delivery.refund_failed': {
2041
+ readonly surfaces: readonly ["gateway"];
2042
+ readonly status: null;
2043
+ readonly title: "Operator refund after a failed delivery was not sent";
2044
+ readonly paymentState: "charged";
2045
+ readonly retry: "never";
2046
+ readonly nextAction: "none";
2047
+ readonly user: null;
2048
+ readonly logOnly: true;
2049
+ };
2050
+ readonly 'payment.required': {
2051
+ readonly surfaces: readonly ["gateway", "seller"];
2052
+ readonly status: 402;
2053
+ readonly title: "Payment required";
2054
+ readonly paymentState: "not_charged";
2055
+ readonly retry: "safe";
2056
+ readonly nextAction: "none";
2057
+ readonly user: {
2058
+ readonly title: "Payment needed";
2059
+ readonly message: "This service needs a payment before it can answer.";
2060
+ };
2061
+ readonly mppProblem: "payment-required";
2062
+ };
2063
+ readonly 'payment.credential_malformed': {
2064
+ readonly surfaces: readonly ["gateway", "seller"];
2065
+ readonly status: 402;
2066
+ readonly title: "Payment credential could not be read";
2067
+ readonly paymentState: "not_charged";
2068
+ readonly retry: "never";
2069
+ readonly nextAction: "fix_request";
2070
+ readonly user: {
2071
+ readonly title: "Payment not accepted";
2072
+ readonly message: "Your payment couldn't be read. Try paying again.";
2073
+ };
2074
+ readonly mppProblem: "malformed-credential";
2075
+ };
2076
+ readonly 'payment.proof_invalid': {
2077
+ readonly surfaces: readonly ["gateway", "seller"];
2078
+ readonly status: 402;
2079
+ readonly title: "Payment proof failed verification";
2080
+ readonly paymentState: "not_charged";
2081
+ readonly retry: "never";
2082
+ readonly nextAction: "fix_request";
2083
+ readonly user: {
2084
+ readonly title: "Payment not accepted";
2085
+ readonly message: "Your payment couldn't be verified. Try paying again.";
2086
+ };
2087
+ readonly mppProblem: "verification-failed";
2088
+ };
2089
+ readonly 'payment.amount_insufficient': {
2090
+ readonly surfaces: readonly ["gateway", "seller", "sdk"];
2091
+ readonly status: 402;
2092
+ readonly title: "Payment amount is below the price";
2093
+ readonly paymentState: "not_charged";
2094
+ readonly retry: "never";
2095
+ readonly nextAction: "fix_request";
2096
+ readonly user: {
2097
+ readonly title: "Payment too small";
2098
+ readonly message: "The amount offered is below the price. Pay the full amount.";
2099
+ };
2100
+ readonly mppProblem: "payment-insufficient";
2101
+ };
2102
+ readonly 'payment.method_unsupported': {
2103
+ readonly surfaces: readonly ["gateway", "seller", "sdk", "console_server", "browser"];
2104
+ readonly status: 400;
2105
+ readonly title: "Payment method is not supported";
2106
+ readonly paymentState: "not_charged";
2107
+ readonly retry: "never";
2108
+ readonly nextAction: "fix_request";
2109
+ readonly user: {
2110
+ readonly title: "Payment method not supported";
2111
+ readonly message: "This service doesn't accept that way of paying.";
2112
+ };
2113
+ readonly mppProblem: "method-unsupported";
2114
+ };
2115
+ readonly 'payment.version_unsupported': {
2116
+ readonly surfaces: readonly ["gateway", "seller", "sdk", "console_server", "browser"];
2117
+ readonly status: 400;
2118
+ readonly title: "Payment protocol version is not supported";
2119
+ readonly paymentState: "not_charged";
2120
+ readonly retry: "never";
2121
+ readonly nextAction: "fix_request";
2122
+ readonly user: {
2123
+ readonly title: "Update your client";
2124
+ readonly message: "This service can't read the payment format your client uses. Update your client and try again.";
2125
+ };
2126
+ };
2127
+ readonly 'payment.verify_failed': {
2128
+ readonly surfaces: readonly ["gateway", "sdk", "console_server", "browser"];
2129
+ readonly status: 503;
2130
+ readonly title: "Payment verification failed unexpectedly";
2131
+ readonly paymentState: "not_charged";
2132
+ readonly retry: "after_delay";
2133
+ readonly retryAfterSeconds: 5;
2134
+ readonly nextAction: "retry_later";
2135
+ readonly user: {
2136
+ readonly title: "Payment check unavailable";
2137
+ readonly message: "We couldn't check your payment just now. Wait a moment and try again.";
2138
+ };
2139
+ };
2140
+ readonly 'payment.settlement_rejected': {
2141
+ readonly surfaces: readonly ["gateway", "seller", "sdk", "mcp_local", "mcp_hosted"];
2142
+ readonly status: 402;
2143
+ readonly title: "Settlement was rejected";
2144
+ readonly paymentState: "not_charged";
2145
+ readonly retry: "never";
2146
+ readonly nextAction: "fix_request";
2147
+ readonly user: {
2148
+ readonly title: "Payment not accepted";
2149
+ readonly message: "The payment was refused. Check your access key and try again.";
2150
+ };
2151
+ readonly mppProblem: "verification-failed";
2152
+ };
2153
+ readonly 'payment.proof_not_accepted': {
2154
+ readonly surfaces: readonly ["gateway", "seller"];
2155
+ readonly status: 409;
2156
+ readonly title: "Payment proof refused before its finality was read";
2157
+ readonly paymentState: "unknown";
2158
+ readonly retry: "never";
2159
+ readonly nextAction: "reconcile";
2160
+ readonly user: {
2161
+ readonly title: "Payment needs a check";
2162
+ readonly message: "Your payment was sent but couldn't be matched to this request. Check its status before doing anything else.";
2163
+ };
2164
+ };
2165
+ readonly 'payment.attempt_in_flight': {
2166
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2167
+ readonly status: 409;
2168
+ readonly title: "Another payment for this request is in progress";
2169
+ readonly paymentState: "unknown";
2170
+ readonly retry: "never";
2171
+ readonly nextAction: "reconcile";
2172
+ readonly user: {
2173
+ readonly title: "Payment already in progress";
2174
+ readonly message: "A payment for this request is still being processed. Wait for it to finish before doing anything else.";
2175
+ };
2176
+ readonly mppProblem: "invalid-challenge";
2177
+ };
2178
+ readonly 'payment.challenge_spent': {
2179
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2180
+ readonly status: 409;
2181
+ readonly title: "Payment challenge was already settled";
2182
+ readonly paymentState: "unknown";
2183
+ readonly retry: "never";
2184
+ readonly nextAction: "reconcile";
2185
+ readonly user: {
2186
+ readonly title: "Payment may already have gone through";
2187
+ readonly message: "This payment may already have gone through. Check its status before doing anything else.";
2188
+ };
2189
+ readonly mppProblem: "invalid-challenge";
2190
+ };
2191
+ readonly 'payment.settlement_unknown': {
2192
+ readonly surfaces: readonly ["gateway", "seller", "sdk", "mcp_local", "mcp_hosted"];
2193
+ readonly status: 503;
2194
+ readonly title: "Settlement outcome is not yet known";
2195
+ readonly paymentState: "unknown";
2196
+ readonly retry: "never";
2197
+ readonly retryAfterSeconds: 10;
2198
+ readonly nextAction: "reconcile";
2199
+ readonly user: {
2200
+ readonly title: "Payment still processing";
2201
+ readonly message: "We can't confirm your payment yet. Check its status before doing anything else.";
2202
+ };
2203
+ };
2204
+ readonly 'payment.finality_unconfirmed': {
2205
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted"];
2206
+ readonly status: 503;
2207
+ readonly title: "Transaction was submitted but finality is not confirmed";
2208
+ readonly paymentState: "unknown";
2209
+ readonly retry: "never";
2210
+ readonly retryAfterSeconds: 10;
2211
+ readonly nextAction: "reconcile";
2212
+ readonly user: {
2213
+ readonly title: "Payment still processing";
2214
+ readonly message: "Your payment was sent but is not confirmed yet. Check its status before doing anything else.";
2215
+ };
2216
+ };
2217
+ readonly 'payment.settlement_mismatch': {
2218
+ readonly surfaces: readonly ["gateway", "seller"];
2219
+ readonly status: 502;
2220
+ readonly title: "Settlement effects do not match the offer";
2221
+ readonly paymentState: "charged";
2222
+ readonly retry: "never";
2223
+ readonly nextAction: "contact_support";
2224
+ readonly user: {
2225
+ readonly title: "Payment needs review";
2226
+ readonly message: "Your payment went through but didn't match the offer. Contact support with the code below.";
2227
+ };
2228
+ };
2229
+ readonly 'offer.expired': {
2230
+ readonly surfaces: readonly ["gateway", "seller", "sdk", "mcp_local", "mcp_hosted"];
2231
+ readonly status: 402;
2232
+ readonly title: "Offer expired";
2233
+ readonly paymentState: "not_charged";
2234
+ readonly retry: "safe";
2235
+ readonly nextAction: "retry";
2236
+ readonly user: {
2237
+ readonly title: "Offer expired";
2238
+ readonly message: "The price quote expired before you paid. Try again for a new quote.";
2239
+ };
2240
+ readonly mppProblem: "payment-expired";
2241
+ };
2242
+ readonly 'offer.challenge_invalid': {
2243
+ readonly surfaces: readonly ["gateway", "seller", "sdk"];
2244
+ readonly status: 402;
2245
+ readonly title: "Challenge is unknown or already used";
2246
+ readonly paymentState: "not_charged";
2247
+ readonly retry: "safe";
2248
+ readonly nextAction: "retry";
2249
+ readonly user: {
2250
+ readonly title: "Offer no longer valid";
2251
+ readonly message: "That price quote can't be used anymore. Try again for a new quote.";
2252
+ };
2253
+ readonly mppProblem: "invalid-challenge";
2254
+ };
2255
+ readonly 'offer.terms_changed': {
2256
+ readonly surfaces: readonly ["gateway", "sdk"];
2257
+ readonly status: 409;
2258
+ readonly title: "Registration terms changed since the offer was made";
2259
+ readonly paymentState: "not_charged";
2260
+ readonly retry: "safe";
2261
+ readonly nextAction: "retry";
2262
+ readonly user: {
2263
+ readonly title: "Price changed";
2264
+ readonly message: "The service changed its terms. Try again for a new quote.";
2265
+ };
2266
+ };
2267
+ readonly 'offer.invalid': {
2268
+ readonly surfaces: readonly ["console_server", "sdk", "mcp_local", "mcp_hosted", "browser"];
2269
+ readonly status: 422;
2270
+ readonly title: "Offer is unreadable or internally inconsistent";
2271
+ readonly paymentState: "not_charged";
2272
+ readonly retry: "never";
2273
+ readonly nextAction: "contact_support";
2274
+ readonly user: {
2275
+ readonly title: "Price quote can't be used";
2276
+ readonly message: "This service sent a price quote we can't use. Try another service or contact support.";
2277
+ };
2278
+ };
2279
+ readonly 'offer.not_offered': {
2280
+ readonly surfaces: readonly ["console_server", "sdk", "mcp_local", "mcp_hosted", "browser"];
2281
+ readonly status: 422;
2282
+ readonly title: "Resource answered without a payment challenge";
2283
+ readonly paymentState: "not_charged";
2284
+ readonly retry: "never";
2285
+ readonly nextAction: "fix_request";
2286
+ readonly user: {
2287
+ readonly title: "No price quote";
2288
+ readonly message: "This address didn't ask for a payment. Check that you're using the right address.";
2289
+ };
2290
+ };
2291
+ readonly 'offer.not_payable': {
2292
+ readonly surfaces: readonly ["gateway", "sdk"];
2293
+ readonly status: 409;
2294
+ readonly title: "Offer's recipient or rail setup cannot be paid here";
2295
+ readonly paymentState: "not_charged";
2296
+ readonly retry: "never";
2297
+ readonly nextAction: "contact_support";
2298
+ readonly user: {
2299
+ readonly title: "Can't pay this service";
2300
+ readonly message: "You can't pay this service this way right now.";
2301
+ };
2302
+ };
2303
+ readonly 'offer.request_mismatch': {
2304
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2305
+ readonly status: 409;
2306
+ readonly title: "Request does not match what the offer bound";
2307
+ readonly paymentState: "not_charged";
2308
+ readonly retry: "never";
2309
+ readonly nextAction: "fix_request";
2310
+ readonly user: {
2311
+ readonly title: "Request doesn't match quote";
2312
+ readonly message: "What you sent differs from what the price was quoted for. Get a new quote and try again.";
2313
+ };
2314
+ };
2315
+ readonly 'account.asset_unsupported': {
2316
+ readonly surfaces: readonly ["gateway", "sdk"];
2317
+ readonly status: 400;
2318
+ readonly title: "Asset is not supported for this account";
2319
+ readonly paymentState: "not_charged";
2320
+ readonly retry: "never";
2321
+ readonly nextAction: "fix_request";
2322
+ readonly user: {
2323
+ readonly title: "Currency not supported";
2324
+ readonly message: "This currency isn't supported here. Pick a supported one.";
2325
+ };
2326
+ };
2327
+ readonly 'account.authority_stale': {
2328
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted"];
2329
+ readonly status: 409;
2330
+ readonly title: "Grant authority changed since it was read";
2331
+ readonly paymentState: "not_charged";
2332
+ readonly retry: "never";
2333
+ readonly nextAction: "approve_access";
2334
+ readonly user: {
2335
+ readonly title: "Access needs renewing";
2336
+ readonly message: "Your agent's access changed since it was last checked. Approve access again.";
2337
+ };
2338
+ };
2339
+ readonly 'account.delegate_conflict': {
2340
+ readonly surfaces: readonly ["gateway"];
2341
+ readonly status: 409;
2342
+ readonly title: "Consent session is bound to a different delegate";
2343
+ readonly paymentState: "not_charged";
2344
+ readonly retry: "never";
2345
+ readonly nextAction: "fix_request";
2346
+ readonly user: {
2347
+ readonly title: "Different key already chosen";
2348
+ readonly message: "This setup is tied to another agent key. Use that key or start again.";
2349
+ };
2350
+ };
2351
+ readonly 'account.delegate_invalid': {
2352
+ readonly surfaces: readonly ["gateway"];
2353
+ readonly status: 400;
2354
+ readonly title: "Delegate address is missing or invalid";
2355
+ readonly paymentState: "not_charged";
2356
+ readonly retry: "never";
2357
+ readonly nextAction: "fix_request";
2358
+ readonly user: {
2359
+ readonly title: "Agent address not valid";
2360
+ readonly message: "Enter a valid agent address and try again.";
2361
+ };
2362
+ };
2363
+ readonly 'account.finalize_mismatch': {
2364
+ readonly surfaces: readonly ["gateway"];
2365
+ readonly status: 409;
2366
+ readonly title: "Submitted transaction does not match the prepared intent";
2367
+ readonly paymentState: "not_charged";
2368
+ readonly retry: "never";
2369
+ readonly nextAction: "fix_request";
2370
+ readonly user: {
2371
+ readonly title: "Transaction doesn't match";
2372
+ readonly message: "The transaction you sent doesn't match this request. Submit the right one.";
2373
+ };
2374
+ };
2375
+ readonly 'account.funds_in_address_balance': {
2376
+ readonly surfaces: readonly ["sdk", "browser"];
2377
+ readonly status: null;
2378
+ readonly title: "Funds are held as address balance, not coin objects";
2379
+ readonly paymentState: "not_charged";
2380
+ readonly retry: "never";
2381
+ readonly nextAction: "fix_request";
2382
+ readonly user: {
2383
+ readonly title: "Funds need moving";
2384
+ readonly message: "Your funds aren't in a form this payment can use yet. Move them into coins and try again.";
2385
+ };
2386
+ };
2387
+ readonly 'account.funds_insufficient': {
2388
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2389
+ readonly status: 402;
2390
+ readonly title: "Insufficient funds";
2391
+ readonly paymentState: "not_charged";
2392
+ readonly retry: "never";
2393
+ readonly nextAction: "add_funds";
2394
+ readonly user: {
2395
+ readonly title: "Not enough funds";
2396
+ readonly message: "You don't have enough funds for this. Add funds and try again.";
2397
+ };
2398
+ };
2399
+ readonly 'account.grant_ambiguous': {
2400
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2401
+ readonly status: 409;
2402
+ readonly title: "More than one live grant matches";
2403
+ readonly paymentState: "not_charged";
2404
+ readonly retry: "never";
2405
+ readonly nextAction: "fix_request";
2406
+ readonly user: {
2407
+ readonly title: "More than one access found";
2408
+ readonly message: "Your key has more than one active access. Choose one and try again.";
2409
+ };
2410
+ };
2411
+ readonly 'account.grant_denied': {
2412
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted"];
2413
+ readonly status: 403;
2414
+ readonly title: "Grant does not authorize this payment";
2415
+ readonly paymentState: "not_charged";
2416
+ readonly retry: "never";
2417
+ readonly nextAction: "approve_access";
2418
+ readonly user: {
2419
+ readonly title: "Access not allowed";
2420
+ readonly message: "Your agent's access doesn't cover this payment. Approve access for it.";
2421
+ };
2422
+ };
2423
+ readonly 'account.grant_expired': {
2424
+ readonly surfaces: readonly ["gateway", "sdk", "browser"];
2425
+ readonly status: 403;
2426
+ readonly title: "Grant has expired";
2427
+ readonly paymentState: "not_charged";
2428
+ readonly retry: "never";
2429
+ readonly nextAction: "approve_access";
2430
+ readonly user: {
2431
+ readonly title: "Access expired";
2432
+ readonly message: "Your agent's access has expired. Approve access again.";
2433
+ };
2434
+ };
2435
+ readonly 'account.grant_not_active': {
2436
+ readonly surfaces: readonly ["gateway"];
2437
+ readonly status: 403;
2438
+ readonly title: "Grant is not active or not finalized";
2439
+ readonly paymentState: "not_charged";
2440
+ readonly retry: "never";
2441
+ readonly nextAction: "approve_access";
2442
+ readonly user: {
2443
+ readonly title: "Access not ready";
2444
+ readonly message: "Your agent's access isn't active yet. Finish setting it up.";
2445
+ };
2446
+ };
2447
+ readonly 'account.grant_not_found': {
2448
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2449
+ readonly status: 404;
2450
+ readonly title: "No grant found for this delegate or asset";
2451
+ readonly paymentState: "not_charged";
2452
+ readonly retry: "never";
2453
+ readonly nextAction: "approve_access";
2454
+ readonly user: {
2455
+ readonly title: "No access set up";
2456
+ readonly message: "Your agent has no access for this yet. Set up access to continue.";
2457
+ };
2458
+ };
2459
+ readonly 'account.grant_not_verified': {
2460
+ readonly surfaces: readonly ["sdk", "mcp_local", "browser"];
2461
+ readonly status: null;
2462
+ readonly title: "Grant on chain does not belong to this delegate key";
2463
+ readonly paymentState: "not_charged";
2464
+ readonly retry: "never";
2465
+ readonly nextAction: "fix_request";
2466
+ readonly user: {
2467
+ readonly title: "Key doesn't match access";
2468
+ readonly message: "This key isn't the one your access was given to. Use the right key.";
2469
+ };
2470
+ };
2471
+ readonly 'account.grant_paused': {
2472
+ readonly surfaces: readonly ["gateway", "sdk"];
2473
+ readonly status: 403;
2474
+ readonly title: "Grant is paused";
2475
+ readonly paymentState: "not_charged";
2476
+ readonly retry: "never";
2477
+ readonly nextAction: "approve_access";
2478
+ readonly user: {
2479
+ readonly title: "Access paused";
2480
+ readonly message: "Your agent's access is paused. Resume it to continue.";
2481
+ };
2482
+ };
2483
+ readonly 'account.grant_retired': {
2484
+ readonly surfaces: readonly ["mcp_hosted"];
2485
+ readonly status: 403;
2486
+ readonly title: "Grant type is retired and cannot sign here";
2487
+ readonly paymentState: "not_charged";
2488
+ readonly retry: "never";
2489
+ readonly nextAction: "approve_access";
2490
+ readonly user: {
2491
+ readonly title: "Access type retired";
2492
+ readonly message: "This kind of access is no longer supported. Remove it and set up access again.";
2493
+ };
2494
+ };
2495
+ readonly 'account.grant_revoked': {
2496
+ readonly surfaces: readonly ["gateway", "sdk"];
2497
+ readonly status: 403;
2498
+ readonly title: "Grant was revoked";
2499
+ readonly paymentState: "not_charged";
2500
+ readonly retry: "never";
2501
+ readonly nextAction: "approve_access";
2502
+ readonly user: {
2503
+ readonly title: "Access removed";
2504
+ readonly message: "Your agent's access was removed. Approve access again to continue.";
2505
+ };
2506
+ };
2507
+ readonly 'account.grant_scope_unsupported': {
2508
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "browser"];
2509
+ readonly status: 400;
2510
+ readonly title: "Grant scope cannot pay with this method";
2511
+ readonly paymentState: "not_charged";
2512
+ readonly retry: "never";
2513
+ readonly nextAction: "fix_request";
2514
+ readonly user: {
2515
+ readonly title: "Access can't pay this way";
2516
+ readonly message: "This kind of access can't pay this way. Set up access for specific services.";
2517
+ };
2518
+ };
2519
+ readonly 'account.limit_exceeded': {
2520
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2521
+ readonly status: 403;
2522
+ readonly title: "Amount exceeds the grant or session spending cap";
2523
+ readonly paymentState: "not_charged";
2524
+ readonly retry: "never";
2525
+ readonly nextAction: "approve_access";
2526
+ readonly user: {
2527
+ readonly title: "Over your spending limit";
2528
+ readonly message: "This costs more than your agent is allowed to spend. Raise the limit to continue.";
2529
+ };
2530
+ };
2531
+ readonly 'account.mandate_inactive': {
2532
+ readonly surfaces: readonly ["gateway"];
2533
+ readonly status: 402;
2534
+ readonly title: "Subscription mandate is paused or cancelled";
2535
+ readonly paymentState: "not_charged";
2536
+ readonly retry: "never";
2537
+ readonly nextAction: "approve_access";
2538
+ readonly user: {
2539
+ readonly title: "Subscription not active";
2540
+ readonly message: "Your subscription is paused or cancelled. Renew it to continue.";
2541
+ };
2542
+ };
2543
+ readonly 'account.mandate_not_found': {
2544
+ readonly surfaces: readonly ["gateway"];
2545
+ readonly status: 402;
2546
+ readonly title: "Subscription mandate not found";
2547
+ readonly paymentState: "not_charged";
2548
+ readonly retry: "never";
2549
+ readonly nextAction: "approve_access";
2550
+ readonly user: {
2551
+ readonly title: "No subscription";
2552
+ readonly message: "You don't have a subscription for this. Subscribe to continue.";
2553
+ };
2554
+ };
2555
+ readonly 'account.mandate_period_invalid': {
2556
+ readonly surfaces: readonly ["gateway"];
2557
+ readonly status: 402;
2558
+ readonly title: "Requested period is outside the mandate";
2559
+ readonly paymentState: "not_charged";
2560
+ readonly retry: "never";
2561
+ readonly nextAction: "fix_request";
2562
+ readonly user: {
2563
+ readonly title: "Outside your subscription";
2564
+ readonly message: "This falls outside your subscription's dates.";
2565
+ };
2566
+ };
2567
+ readonly 'account.policy_conflict': {
2568
+ readonly surfaces: readonly ["gateway", "sdk"];
2569
+ readonly status: 409;
2570
+ readonly title: "More than one policy matches the payment";
2571
+ readonly paymentState: "not_charged";
2572
+ readonly retry: "never";
2573
+ readonly nextAction: "approve_access";
2574
+ readonly user: {
2575
+ readonly title: "Spending rules overlap";
2576
+ readonly message: "More than one of your spending rules matches this payment. Fix your rules to continue.";
2577
+ };
2578
+ };
2579
+ readonly 'account.policy_missing': {
2580
+ readonly surfaces: readonly ["gateway"];
2581
+ readonly status: 409;
2582
+ readonly title: "Account has no active policies or profiles";
2583
+ readonly paymentState: "not_charged";
2584
+ readonly retry: "never";
2585
+ readonly nextAction: "approve_access";
2586
+ readonly user: {
2587
+ readonly title: "No spending rules";
2588
+ readonly message: "Add a spending rule before you connect an agent.";
2589
+ };
2590
+ };
2591
+ readonly 'account.policy_rejected': {
2592
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted", "browser"];
2593
+ readonly status: 403;
2594
+ readonly title: "Payment is outside the allowed policy";
2595
+ readonly paymentState: "not_charged";
2596
+ readonly retry: "never";
2597
+ readonly nextAction: "fix_request";
2598
+ readonly user: {
2599
+ readonly title: "Not allowed by your rules";
2600
+ readonly message: "This payment is outside what your spending rules allow.";
2601
+ };
2602
+ };
2603
+ readonly 'account.spend_account_missing': {
2604
+ readonly surfaces: readonly ["gateway"];
2605
+ readonly status: 409;
2606
+ readonly title: "Owner has no spend account";
2607
+ readonly paymentState: "not_charged";
2608
+ readonly retry: "never";
2609
+ readonly nextAction: "add_funds";
2610
+ readonly user: {
2611
+ readonly title: "No spending account";
2612
+ readonly message: "Create and fund a spending account first.";
2613
+ };
2614
+ };
2615
+ readonly 'account.spend_account_not_deployed': {
2616
+ readonly surfaces: readonly ["gateway"];
2617
+ readonly status: 503;
2618
+ readonly title: "Spending account package is not deployed on this network";
2619
+ readonly paymentState: "not_charged";
2620
+ readonly retry: "never";
2621
+ readonly retryAfterSeconds: 60;
2622
+ readonly nextAction: "contact_support";
2623
+ readonly user: {
2624
+ readonly title: "Not available on this network";
2625
+ readonly message: "You can't use spending accounts on this network yet.";
2626
+ };
2627
+ };
2628
+ readonly 'account.spend_account_package_mismatch': {
2629
+ readonly surfaces: readonly ["gateway", "sdk"];
2630
+ readonly status: 409;
2631
+ readonly title: "Spend account was published under a different package";
2632
+ readonly paymentState: "not_charged";
2633
+ readonly retry: "never";
2634
+ readonly nextAction: "fix_request";
2635
+ readonly user: {
2636
+ readonly title: "Spending account out of date";
2637
+ readonly message: "Your spending account is from an older version. Set up a new one to continue.";
2638
+ };
2639
+ };
2640
+ readonly 'account.recipient_rejected': {
2641
+ readonly surfaces: readonly ["gateway"];
2642
+ readonly status: 400;
2643
+ readonly title: "Recipient is not allowed";
2644
+ readonly paymentState: "not_charged";
2645
+ readonly retry: "never";
2646
+ readonly nextAction: "fix_request";
2647
+ readonly user: {
2648
+ readonly title: "Recipient not allowed";
2649
+ readonly message: "You can't pay that recipient from here.";
2650
+ };
2651
+ };
2652
+ readonly 'account.session_expired': {
2653
+ readonly surfaces: readonly ["gateway"];
2654
+ readonly status: 403;
2655
+ readonly title: "Spending session has expired";
2656
+ readonly paymentState: "not_charged";
2657
+ readonly retry: "never";
2658
+ readonly nextAction: "approve_access";
2659
+ readonly user: {
2660
+ readonly title: "Session expired";
2661
+ readonly message: "Your spending session has expired. Start a new one to continue.";
2662
+ };
2663
+ };
2664
+ readonly 'account.session_inactive': {
2665
+ readonly surfaces: readonly ["gateway"];
2666
+ readonly status: 403;
2667
+ readonly title: "Spending session is not active";
2668
+ readonly paymentState: "not_charged";
2669
+ readonly retry: "never";
2670
+ readonly nextAction: "approve_access";
2671
+ readonly user: {
2672
+ readonly title: "Session not active";
2673
+ readonly message: "Your spending session isn't active. Start a new one to continue.";
2674
+ };
2675
+ };
2676
+ readonly 'account.session_invalid': {
2677
+ readonly surfaces: readonly ["gateway"];
2678
+ readonly status: 403;
2679
+ readonly title: "Session request does not match the session grant or amount rules";
2680
+ readonly paymentState: "not_charged";
2681
+ readonly retry: "never";
2682
+ readonly nextAction: "fix_request";
2683
+ readonly user: {
2684
+ readonly title: "Session can't be used";
2685
+ readonly message: "This request doesn't fit your spending session. Check the amount and try again.";
2686
+ };
2687
+ };
2688
+ readonly 'account.session_state_invalid': {
2689
+ readonly surfaces: readonly ["gateway"];
2690
+ readonly status: 403;
2691
+ readonly title: "Session state or accounting is inconsistent";
2692
+ readonly paymentState: "not_charged";
2693
+ readonly retry: "never";
2694
+ readonly nextAction: "contact_support";
2695
+ readonly user: {
2696
+ readonly title: "Session needs review";
2697
+ readonly message: "Your spending session is in a state we can't use. Contact support with the code below.";
2698
+ };
2699
+ };
2700
+ readonly 'account.too_many_coins': {
2701
+ readonly surfaces: readonly ["sdk", "browser"];
2702
+ readonly status: null;
2703
+ readonly title: "Payment would need too many coin objects";
2704
+ readonly paymentState: "not_charged";
2705
+ readonly retry: "never";
2706
+ readonly nextAction: "fix_request";
2707
+ readonly user: {
2708
+ readonly title: "Funds too split up";
2709
+ readonly message: "Your funds are split into too many pieces. Combine them and try again.";
2710
+ };
2711
+ };
2712
+ readonly 'auth.client_invalid': {
2713
+ readonly surfaces: readonly ["gateway"];
2714
+ readonly status: 401;
2715
+ readonly title: "OAuth client is unknown or failed authentication";
2716
+ readonly paymentState: "not_charged";
2717
+ readonly retry: "never";
2718
+ readonly nextAction: "fix_request";
2719
+ readonly user: {
2720
+ readonly title: "App not recognized";
2721
+ readonly message: "The app you're connecting isn't registered. Connect it again.";
2722
+ };
2723
+ };
2724
+ readonly 'auth.client_metadata_invalid': {
2725
+ readonly surfaces: readonly ["gateway"];
2726
+ readonly status: 400;
2727
+ readonly title: "OAuth client registration metadata is invalid";
2728
+ readonly paymentState: "not_charged";
2729
+ readonly retry: "never";
2730
+ readonly nextAction: "fix_request";
2731
+ readonly user: {
2732
+ readonly title: "App details not accepted";
2733
+ readonly message: "The app's registration details aren't valid. Fix them and try again.";
2734
+ };
2735
+ };
2736
+ readonly 'auth.clock_skew': {
2737
+ readonly surfaces: readonly ["gateway"];
2738
+ readonly status: 401;
2739
+ readonly title: "Signed request timestamp is outside the allowed skew";
2740
+ readonly paymentState: "not_charged";
2741
+ readonly retry: "never";
2742
+ readonly nextAction: "fix_request";
2743
+ readonly user: {
2744
+ readonly title: "Clock out of sync";
2745
+ readonly message: "Your device's clock is off. Fix the time and try again.";
2746
+ };
2747
+ };
2748
+ readonly 'auth.connection_binding_mismatch': {
2749
+ readonly surfaces: readonly ["gateway", "mcp_hosted"];
2750
+ readonly status: 401;
2751
+ readonly title: "Bearer connection is bound to a different principal";
2752
+ readonly paymentState: "not_charged";
2753
+ readonly retry: "never";
2754
+ readonly nextAction: "approve_access";
2755
+ readonly user: {
2756
+ readonly title: "Connection not valid";
2757
+ readonly message: "Your agent's connection doesn't match this account. Connect it again.";
2758
+ };
2759
+ };
2760
+ readonly 'auth.connection_denied': {
2761
+ readonly surfaces: readonly ["gateway", "mcp_hosted"];
2762
+ readonly status: 401;
2763
+ readonly title: "Agent connection was revoked or is missing";
2764
+ readonly paymentState: "not_charged";
2765
+ readonly retry: "never";
2766
+ readonly nextAction: "approve_access";
2767
+ readonly user: {
2768
+ readonly title: "Access removed";
2769
+ readonly message: "Your agent's access was removed. Approve access again to continue.";
2770
+ };
2771
+ };
2772
+ readonly 'auth.connection_expired': {
2773
+ readonly surfaces: readonly ["gateway", "mcp_hosted"];
2774
+ readonly status: 409;
2775
+ readonly title: "Agent connection has expired";
2776
+ readonly paymentState: "not_charged";
2777
+ readonly retry: "never";
2778
+ readonly nextAction: "approve_access";
2779
+ readonly user: {
2780
+ readonly title: "Access expired";
2781
+ readonly message: "Your agent's access has expired. Approve access again to continue.";
2782
+ };
2783
+ };
2784
+ readonly 'auth.connection_not_found': {
2785
+ readonly surfaces: readonly ["gateway", "mcp_hosted", "browser"];
2786
+ readonly status: 404;
2787
+ readonly title: "Agent connection not found";
2788
+ readonly paymentState: "not_charged";
2789
+ readonly retry: "never";
2790
+ readonly nextAction: "approve_access";
2791
+ readonly user: {
2792
+ readonly title: "Connection not found";
2793
+ readonly message: "We couldn't find your agent's connection. Connect it again.";
2794
+ };
2795
+ };
2796
+ readonly 'auth.connection_required': {
2797
+ readonly surfaces: readonly ["gateway", "mcp_hosted"];
2798
+ readonly status: 401;
2799
+ readonly title: "An agent connection is required";
2800
+ readonly paymentState: "not_charged";
2801
+ readonly retry: "never";
2802
+ readonly nextAction: "approve_access";
2803
+ readonly user: {
2804
+ readonly title: "Connect your agent";
2805
+ readonly message: "Connect your agent to your account to continue.";
2806
+ };
2807
+ };
2808
+ readonly 'auth.forbidden': {
2809
+ readonly surfaces: readonly ["gateway", "console_server", "sdk"];
2810
+ readonly status: 403;
2811
+ readonly title: "Caller is not allowed to perform this action";
2812
+ readonly paymentState: "not_charged";
2813
+ readonly retry: "never";
2814
+ readonly nextAction: "none";
2815
+ readonly user: {
2816
+ readonly title: "Not allowed";
2817
+ readonly message: "You don't have permission to do this.";
2818
+ };
2819
+ };
2820
+ readonly 'auth.grant_invalid': {
2821
+ readonly surfaces: readonly ["gateway"];
2822
+ readonly status: 400;
2823
+ readonly title: "Authorization code or refresh token is invalid";
2824
+ readonly paymentState: "not_charged";
2825
+ readonly retry: "never";
2826
+ readonly nextAction: "sign_in";
2827
+ readonly user: {
2828
+ readonly title: "Sign-in no longer valid";
2829
+ readonly message: "Your sign-in is no longer valid. Sign in again.";
2830
+ };
2831
+ };
2832
+ readonly 'auth.grant_type_unsupported': {
2833
+ readonly surfaces: readonly ["gateway"];
2834
+ readonly status: 400;
2835
+ readonly title: "OAuth grant type is not supported";
2836
+ readonly paymentState: "not_charged";
2837
+ readonly retry: "never";
2838
+ readonly nextAction: "fix_request";
2839
+ readonly user: {
2840
+ readonly title: "Sign-in method not supported";
2841
+ readonly message: "The app you're connecting asked to sign in a way we don't support.";
2842
+ };
2843
+ };
2844
+ readonly 'auth.login_required': {
2845
+ readonly surfaces: readonly ["mcp_local"];
2846
+ readonly status: null;
2847
+ readonly title: "Local agent has no usable credentials";
2848
+ readonly paymentState: "not_charged";
2849
+ readonly retry: "never";
2850
+ readonly nextAction: "sign_in";
2851
+ readonly user: {
2852
+ readonly title: "Sign in first";
2853
+ readonly message: "Your agent isn't signed in yet. Sign in from your agent to continue.";
2854
+ };
2855
+ };
2856
+ readonly 'auth.nonce_replayed': {
2857
+ readonly surfaces: readonly ["gateway"];
2858
+ readonly status: 401;
2859
+ readonly title: "Signed request nonce was already used";
2860
+ readonly paymentState: "not_charged";
2861
+ readonly retry: "safe";
2862
+ readonly nextAction: "retry";
2863
+ readonly user: {
2864
+ readonly title: "Request already used";
2865
+ readonly message: "This signed request was already used. Send a new one.";
2866
+ };
2867
+ };
2868
+ readonly 'auth.redirect_uri_invalid': {
2869
+ readonly surfaces: readonly ["gateway"];
2870
+ readonly status: 400;
2871
+ readonly title: "OAuth redirect URI is not registered or not allowed";
2872
+ readonly paymentState: "not_charged";
2873
+ readonly retry: "never";
2874
+ readonly nextAction: "fix_request";
2875
+ readonly user: {
2876
+ readonly title: "App address not allowed";
2877
+ readonly message: "The app's return address isn't allowed. Check the app's settings.";
2878
+ };
2879
+ };
2880
+ readonly 'auth.required': {
2881
+ readonly surfaces: readonly ["gateway", "console_server", "sdk", "mcp_hosted"];
2882
+ readonly status: 401;
2883
+ readonly title: "Authentication required";
2884
+ readonly paymentState: "not_charged";
2885
+ readonly retry: "never";
2886
+ readonly nextAction: "sign_in";
2887
+ readonly user: {
2888
+ readonly title: "Sign in required";
2889
+ readonly message: "You need to sign in to continue.";
2890
+ };
2891
+ };
2892
+ readonly 'auth.resource_invalid': {
2893
+ readonly surfaces: readonly ["gateway"];
2894
+ readonly status: 400;
2895
+ readonly title: "OAuth resource indicator does not match this server";
2896
+ readonly paymentState: "not_charged";
2897
+ readonly retry: "never";
2898
+ readonly nextAction: "fix_request";
2899
+ readonly user: {
2900
+ readonly title: "Wrong service address";
2901
+ readonly message: "The app asked for access to a different address. Connect it again.";
2902
+ };
2903
+ };
2904
+ readonly 'auth.response_type_unsupported': {
2905
+ readonly surfaces: readonly ["gateway"];
2906
+ readonly status: 400;
2907
+ readonly title: "OAuth response type is not supported";
2908
+ readonly paymentState: "not_charged";
2909
+ readonly retry: "never";
2910
+ readonly nextAction: "fix_request";
2911
+ readonly user: {
2912
+ readonly title: "Sign-in method not supported";
2913
+ readonly message: "The app you're connecting asked to sign in a way we don't support.";
2914
+ };
2915
+ };
2916
+ readonly 'auth.scope_insufficient': {
2917
+ readonly surfaces: readonly ["gateway", "mcp_hosted"];
2918
+ readonly status: 403;
2919
+ readonly title: "Token scope does not cover this action";
2920
+ readonly paymentState: "not_charged";
2921
+ readonly retry: "never";
2922
+ readonly nextAction: "approve_access";
2923
+ readonly user: {
2924
+ readonly title: "More access needed";
2925
+ readonly message: "Your agent needs more access for this. Approve the extra access to continue.";
2926
+ };
2927
+ };
2928
+ readonly 'auth.scope_invalid': {
2929
+ readonly surfaces: readonly ["gateway"];
2930
+ readonly status: 400;
2931
+ readonly title: "Requested OAuth scope is invalid";
2932
+ readonly paymentState: "not_charged";
2933
+ readonly retry: "never";
2934
+ readonly nextAction: "fix_request";
2935
+ readonly user: {
2936
+ readonly title: "Access request not valid";
2937
+ readonly message: "The app asked for access that doesn't exist. Check the app's settings.";
2938
+ };
2939
+ };
2940
+ readonly 'auth.sign_in_expired': {
2941
+ readonly surfaces: readonly ["console_server", "browser"];
2942
+ readonly status: 401;
2943
+ readonly title: "Wallet sign-in challenge expired or is unknown";
2944
+ readonly paymentState: "not_charged";
2945
+ readonly retry: "never";
2946
+ readonly nextAction: "sign_in";
2947
+ readonly user: {
2948
+ readonly title: "Sign-in expired";
2949
+ readonly message: "Your sign-in request expired. Sign in again.";
2950
+ };
2951
+ };
2952
+ readonly 'auth.sign_in_failed': {
2953
+ readonly surfaces: readonly ["console_server", "browser"];
2954
+ readonly status: 401;
2955
+ readonly title: "Wallet sign-in signature did not verify";
2956
+ readonly paymentState: "not_charged";
2957
+ readonly retry: "never";
2958
+ readonly nextAction: "sign_in";
2959
+ readonly user: {
2960
+ readonly title: "Couldn't sign you in";
2961
+ readonly message: "We couldn't verify your wallet signature. Try signing in again.";
2962
+ };
2963
+ };
2964
+ readonly 'auth.signature_invalid': {
2965
+ readonly surfaces: readonly ["gateway"];
2966
+ readonly status: 401;
2967
+ readonly title: "Request signature does not verify";
2968
+ readonly paymentState: "not_charged";
2969
+ readonly retry: "never";
2970
+ readonly nextAction: "fix_request";
2971
+ readonly user: {
2972
+ readonly title: "Signature not valid";
2973
+ readonly message: "Your request's signature didn't check out. Sign it again with the right key.";
2974
+ };
2975
+ };
2976
+ readonly 'auth.signed_request_expired': {
2977
+ readonly surfaces: readonly ["gateway"];
2978
+ readonly status: 401;
2979
+ readonly title: "Signed request timestamp has expired";
2980
+ readonly paymentState: "not_charged";
2981
+ readonly retry: "safe";
2982
+ readonly nextAction: "retry";
2983
+ readonly user: {
2984
+ readonly title: "Request expired";
2985
+ readonly message: "Your signed request is too old. Send a new one.";
2986
+ };
2987
+ };
2988
+ readonly 'auth.signed_request_malformed': {
2989
+ readonly surfaces: readonly ["gateway"];
2990
+ readonly status: 401;
2991
+ readonly title: "Signed request headers are missing or malformed";
2992
+ readonly paymentState: "not_charged";
2993
+ readonly retry: "never";
2994
+ readonly nextAction: "fix_request";
2995
+ readonly user: {
2996
+ readonly title: "Signed request incomplete";
2997
+ readonly message: "Your request is missing signing details. Update your app and try again.";
2998
+ };
2999
+ };
3000
+ readonly 'auth.signer_not_delegate': {
3001
+ readonly surfaces: readonly ["gateway"];
3002
+ readonly status: 401;
3003
+ readonly title: "Signer is not the grant's delegate";
3004
+ readonly paymentState: "not_charged";
3005
+ readonly retry: "never";
3006
+ readonly nextAction: "fix_request";
3007
+ readonly user: {
3008
+ readonly title: "Wrong key";
3009
+ readonly message: "This key isn't the one your access was given to. Use the right key.";
3010
+ };
3011
+ };
3012
+ readonly 'auth.token_invalid': {
3013
+ readonly surfaces: readonly ["gateway", "mcp_hosted"];
3014
+ readonly status: 401;
3015
+ readonly title: "Bearer token is invalid or expired";
3016
+ readonly paymentState: "not_charged";
3017
+ readonly retry: "never";
3018
+ readonly nextAction: "sign_in";
3019
+ readonly user: {
3020
+ readonly title: "Sign in again";
3021
+ readonly message: "Your sign-in is no longer valid. Sign in again to continue.";
3022
+ };
3023
+ };
3024
+ readonly 'request.body_invalid': {
3025
+ readonly surfaces: readonly ["gateway", "console_server", "sdk"];
3026
+ readonly status: 400;
3027
+ readonly title: "Request body does not match the service's schema";
3028
+ readonly paymentState: "not_charged";
3029
+ readonly retry: "never";
3030
+ readonly nextAction: "fix_request";
3031
+ readonly user: {
3032
+ readonly title: "Check your request";
3033
+ readonly message: "Some details you sent aren't what this service expects. Fix them and try again.";
3034
+ };
3035
+ };
3036
+ readonly 'request.body_too_large': {
3037
+ readonly surfaces: readonly ["gateway", "seller", "sdk", "mcp_local", "mcp_hosted"];
3038
+ readonly status: 413;
3039
+ readonly title: "Request body exceeds the size limit";
3040
+ readonly paymentState: "not_charged";
3041
+ readonly retry: "never";
3042
+ readonly nextAction: "fix_request";
3043
+ readonly user: {
3044
+ readonly title: "Request too large";
3045
+ readonly message: "What you sent is larger than this service accepts. Send less and try again.";
3046
+ };
3047
+ };
3048
+ readonly 'request.clock_not_controllable': {
3049
+ readonly surfaces: readonly ["gateway"];
3050
+ readonly status: 400;
3051
+ readonly title: "Clock is not controllable on this deployment";
3052
+ readonly paymentState: "not_charged";
3053
+ readonly retry: "never";
3054
+ readonly nextAction: "fix_request";
3055
+ readonly user: {
3056
+ readonly title: "Clock control not available";
3057
+ readonly message: "You can't change the clock in this environment.";
3058
+ };
3059
+ };
3060
+ readonly 'request.clock_not_monotonic': {
3061
+ readonly surfaces: readonly ["gateway"];
3062
+ readonly status: 400;
3063
+ readonly title: "Clock can only move forward";
3064
+ readonly paymentState: "not_charged";
3065
+ readonly retry: "never";
3066
+ readonly nextAction: "fix_request";
3067
+ readonly user: {
3068
+ readonly title: "Clock can only move forward";
3069
+ readonly message: "You can only move the clock forward. Pick a later time.";
3070
+ };
3071
+ };
3072
+ readonly 'request.conflict': {
3073
+ readonly surfaces: readonly ["gateway", "console_server"];
3074
+ readonly status: 409;
3075
+ readonly title: "Resource state conflicts with the request";
3076
+ readonly paymentState: "not_charged";
3077
+ readonly retry: "never";
3078
+ readonly nextAction: "fix_request";
3079
+ readonly user: {
3080
+ readonly title: "Already changed";
3081
+ readonly message: "This was changed somewhere else. Reload and try again.";
3082
+ };
3083
+ };
3084
+ readonly 'request.credential_ambiguous': {
3085
+ readonly surfaces: readonly ["gateway", "seller"];
3086
+ readonly status: 400;
3087
+ readonly title: "Request carries more than one payment credential";
3088
+ readonly paymentState: "not_charged";
3089
+ readonly retry: "never";
3090
+ readonly nextAction: "fix_request";
3091
+ readonly user: {
3092
+ readonly title: "Payment not accepted";
3093
+ readonly message: "You sent two kinds of payment at once. Send only one.";
3094
+ };
3095
+ };
3096
+ readonly 'request.expired': {
3097
+ readonly surfaces: readonly ["gateway"];
3098
+ readonly status: 410;
3099
+ readonly title: "Session or pending request expired";
3100
+ readonly paymentState: "not_charged";
3101
+ readonly retry: "safe";
3102
+ readonly nextAction: "retry";
3103
+ readonly user: {
3104
+ readonly title: "Request expired";
3105
+ readonly message: "This request has expired. Start again.";
3106
+ };
3107
+ };
3108
+ readonly 'request.feature_retired': {
3109
+ readonly surfaces: readonly ["console_server"];
3110
+ readonly status: 410;
3111
+ readonly title: "Feature has been retired";
3112
+ readonly paymentState: "not_charged";
3113
+ readonly retry: "never";
3114
+ readonly nextAction: "fix_request";
3115
+ readonly user: {
3116
+ readonly title: "No longer available";
3117
+ readonly message: "This option was retired. Use the current version of the app.";
3118
+ };
3119
+ };
3120
+ readonly 'request.file_args_invalid': {
3121
+ readonly surfaces: readonly ["mcp_local"];
3122
+ readonly status: null;
3123
+ readonly title: "File and field arguments are incomplete or conflicting";
3124
+ readonly paymentState: "not_charged";
3125
+ readonly retry: "never";
3126
+ readonly nextAction: "fix_request";
3127
+ readonly user: {
3128
+ readonly title: "File options incomplete";
3129
+ readonly message: "Give both the file and a new field name, and only on a POST request.";
3130
+ };
3131
+ };
3132
+ readonly 'request.file_empty': {
3133
+ readonly surfaces: readonly ["mcp_local"];
3134
+ readonly status: null;
3135
+ readonly title: "File is empty";
3136
+ readonly paymentState: "not_charged";
3137
+ readonly retry: "never";
3138
+ readonly nextAction: "fix_request";
3139
+ readonly user: {
3140
+ readonly title: "File is empty";
3141
+ readonly message: "The file you chose is empty. Pick a file with content.";
3142
+ };
3143
+ };
3144
+ readonly 'request.file_forbidden': {
3145
+ readonly surfaces: readonly ["mcp_local"];
3146
+ readonly status: null;
3147
+ readonly title: "File is in a protected folder";
3148
+ readonly paymentState: "not_charged";
3149
+ readonly retry: "never";
3150
+ readonly nextAction: "fix_request";
3151
+ readonly user: {
3152
+ readonly title: "File can't be used";
3153
+ readonly message: "That file is in a protected folder. Pick a file outside it.";
3154
+ };
3155
+ };
3156
+ readonly 'request.file_invalid': {
3157
+ readonly surfaces: readonly ["mcp_local"];
3158
+ readonly status: null;
3159
+ readonly title: "File path is not a readable regular file";
3160
+ readonly paymentState: "not_charged";
3161
+ readonly retry: "never";
3162
+ readonly nextAction: "fix_request";
3163
+ readonly user: {
3164
+ readonly title: "File can't be read";
3165
+ readonly message: "Give the full path to a regular file on this computer.";
3166
+ };
3167
+ };
3168
+ readonly 'request.file_not_found': {
3169
+ readonly surfaces: readonly ["mcp_local"];
3170
+ readonly status: null;
3171
+ readonly title: "File not found";
3172
+ readonly paymentState: "not_charged";
3173
+ readonly retry: "never";
3174
+ readonly nextAction: "fix_request";
3175
+ readonly user: {
3176
+ readonly title: "File not found";
3177
+ readonly message: "No file exists at that path. Check the path and try again.";
3178
+ };
3179
+ };
3180
+ readonly 'request.file_outside_root': {
3181
+ readonly surfaces: readonly ["mcp_local"];
3182
+ readonly status: null;
3183
+ readonly title: "File is outside the allowed folder";
3184
+ readonly paymentState: "not_charged";
3185
+ readonly retry: "never";
3186
+ readonly nextAction: "fix_request";
3187
+ readonly user: {
3188
+ readonly title: "File outside allowed folder";
3189
+ readonly message: "You can only send files from the folder set up for uploads.";
3190
+ };
3191
+ };
3192
+ readonly 'request.file_root_unset': {
3193
+ readonly surfaces: readonly ["mcp_local"];
3194
+ readonly status: null;
3195
+ readonly title: "Upload folder is not configured";
3196
+ readonly paymentState: "not_charged";
3197
+ readonly retry: "never";
3198
+ readonly nextAction: "fix_request";
3199
+ readonly user: {
3200
+ readonly title: "Upload folder not set";
3201
+ readonly message: "Set an upload folder for your agent before you send files.";
3202
+ };
3203
+ };
3204
+ readonly 'request.file_too_large': {
3205
+ readonly surfaces: readonly ["mcp_local"];
3206
+ readonly status: null;
3207
+ readonly title: "File exceeds the size limit";
3208
+ readonly paymentState: "not_charged";
3209
+ readonly retry: "never";
3210
+ readonly nextAction: "fix_request";
3211
+ readonly user: {
3212
+ readonly title: "File too large";
3213
+ readonly message: "That file is larger than the limit. Pick a smaller file.";
3214
+ };
3215
+ };
3216
+ readonly 'request.file_unreadable': {
3217
+ readonly surfaces: readonly ["mcp_local"];
3218
+ readonly status: null;
3219
+ readonly title: "File is not readable by the agent process";
3220
+ readonly paymentState: "not_charged";
3221
+ readonly retry: "never";
3222
+ readonly nextAction: "fix_request";
3223
+ readonly user: {
3224
+ readonly title: "File can't be opened";
3225
+ readonly message: "You don't have permission to read that file.";
3226
+ };
3227
+ };
3228
+ readonly 'request.invalid': {
3229
+ readonly surfaces: readonly ["gateway", "seller", "console_server", "sdk", "mcp_local", "mcp_hosted"];
3230
+ readonly status: 400;
3231
+ readonly title: "Request is invalid";
3232
+ readonly paymentState: "not_charged";
3233
+ readonly retry: "never";
3234
+ readonly nextAction: "fix_request";
3235
+ readonly user: {
3236
+ readonly title: "Check your request";
3237
+ readonly message: "Something in your request isn't valid. Fix it and try again.";
3238
+ };
3239
+ };
3240
+ readonly 'request.local_only': {
3241
+ readonly surfaces: readonly ["mcp_hosted"];
3242
+ readonly status: 400;
3243
+ readonly title: "Only available on the local agent server";
3244
+ readonly paymentState: "not_charged";
3245
+ readonly retry: "never";
3246
+ readonly nextAction: "fix_request";
3247
+ readonly user: {
3248
+ readonly title: "Only in the local agent tool";
3249
+ readonly message: "This works only when your agent runs on your own computer.";
3250
+ };
3251
+ };
3252
+ readonly 'request.method_not_allowed': {
3253
+ readonly surfaces: readonly ["gateway", "seller", "console_server"];
3254
+ readonly status: 405;
3255
+ readonly title: "Method not allowed on this path";
3256
+ readonly paymentState: "not_charged";
3257
+ readonly retry: "never";
3258
+ readonly nextAction: "fix_request";
3259
+ readonly user: {
3260
+ readonly title: "Method not allowed";
3261
+ readonly message: "You can't send that kind of request to this address.";
3262
+ };
3263
+ };
3264
+ readonly 'request.network_mismatch': {
3265
+ readonly surfaces: readonly ["gateway", "sdk", "mcp_local", "mcp_hosted"];
3266
+ readonly status: 400;
3267
+ readonly title: "Request targets a different network or deployment";
3268
+ readonly paymentState: "not_charged";
3269
+ readonly retry: "never";
3270
+ readonly nextAction: "fix_request";
3271
+ readonly user: {
3272
+ readonly title: "Wrong network";
3273
+ readonly message: "This is set up for a different network. Switch networks and try again.";
3274
+ };
3275
+ };
3276
+ readonly 'request.not_found': {
3277
+ readonly surfaces: readonly ["gateway", "seller", "console_server"];
3278
+ readonly status: 404;
3279
+ readonly title: "Not found";
3280
+ readonly paymentState: "not_charged";
3281
+ readonly retry: "never";
3282
+ readonly nextAction: "fix_request";
3283
+ readonly user: {
3284
+ readonly title: "Not found";
3285
+ readonly message: "We couldn't find what you asked for. Check the address and try again.";
3286
+ };
3287
+ };
3288
+ readonly 'request.origin_already_listed': {
3289
+ readonly surfaces: readonly ["console_server"];
3290
+ readonly status: 422;
3291
+ readonly title: "Origin is an already-listed managed product";
3292
+ readonly paymentState: "not_charged";
3293
+ readonly retry: "never";
3294
+ readonly nextAction: "fix_request";
3295
+ readonly user: {
3296
+ readonly title: "Already listed";
3297
+ readonly message: "That service is already in the catalog. Add your own seller address instead.";
3298
+ };
3299
+ };
3300
+ readonly 'request.origin_not_public': {
3301
+ readonly surfaces: readonly ["seller", "console_server"];
3302
+ readonly status: 422;
3303
+ readonly title: "Origin resolves to a private or reserved address";
3304
+ readonly paymentState: "not_charged";
3305
+ readonly retry: "never";
3306
+ readonly nextAction: "fix_request";
3307
+ readonly user: {
3308
+ readonly title: "Address not public";
3309
+ readonly message: "You can only use a public web address here.";
3310
+ };
3311
+ };
3312
+ readonly 'request.origin_not_seller': {
3313
+ readonly surfaces: readonly ["console_server"];
3314
+ readonly status: 422;
3315
+ readonly title: "Origin serves no valid seller setup document";
3316
+ readonly paymentState: "not_charged";
3317
+ readonly retry: "never";
3318
+ readonly nextAction: "fix_request";
3319
+ readonly user: {
3320
+ readonly title: "No seller found";
3321
+ readonly message: "We found no valid seller setup at that address. Check it and try again.";
3322
+ };
3323
+ };
3324
+ readonly 'request.origin_self_hosted': {
3325
+ readonly surfaces: readonly ["console_server"];
3326
+ readonly status: 422;
3327
+ readonly title: "Origin issues its own payment challenges";
3328
+ readonly paymentState: "not_charged";
3329
+ readonly retry: "never";
3330
+ readonly nextAction: "fix_request";
3331
+ readonly user: {
3332
+ readonly title: "Seller takes its own payments";
3333
+ readonly message: "That seller takes payments itself. Add a managed seller address instead.";
3334
+ };
3335
+ };
3336
+ readonly 'request.origin_unreachable': {
3337
+ readonly surfaces: readonly ["console_server"];
3338
+ readonly status: 422;
3339
+ readonly title: "Origin could not be reached";
3340
+ readonly paymentState: "not_charged";
3341
+ readonly retry: "safe";
3342
+ readonly nextAction: "retry";
3343
+ readonly user: {
3344
+ readonly title: "Couldn't reach that address";
3345
+ readonly message: "We couldn't reach that address. Check it and try again.";
3346
+ };
3347
+ };
3348
+ readonly 'request.origin_unresolved': {
3349
+ readonly surfaces: readonly ["console_server"];
3350
+ readonly status: 422;
3351
+ readonly title: "Origin hostname did not resolve";
3352
+ readonly paymentState: "not_charged";
3353
+ readonly retry: "never";
3354
+ readonly nextAction: "fix_request";
3355
+ readonly user: {
3356
+ readonly title: "Address not found";
3357
+ readonly message: "That web address doesn't exist. Check the spelling and try again.";
3358
+ };
3359
+ };
3360
+ readonly 'request.redirect_refused': {
3361
+ readonly surfaces: readonly ["console_server", "sdk"];
3362
+ readonly status: 422;
3363
+ readonly title: "Target redirected and the redirect was refused";
3364
+ readonly paymentState: "not_charged";
3365
+ readonly retry: "never";
3366
+ readonly nextAction: "fix_request";
3367
+ readonly user: {
3368
+ readonly title: "Address redirects elsewhere";
3369
+ readonly message: "That address sends you somewhere else. Use the final address instead.";
3370
+ };
3371
+ };
3372
+ readonly 'request.route_conflict': {
3373
+ readonly surfaces: readonly ["gateway"];
3374
+ readonly status: 409;
3375
+ readonly title: "Route is already used by another service";
3376
+ readonly paymentState: "not_charged";
3377
+ readonly retry: "never";
3378
+ readonly nextAction: "fix_request";
3379
+ readonly user: {
3380
+ readonly title: "Path already in use";
3381
+ readonly message: "Another service already uses that path. Pick a different one.";
3382
+ };
3383
+ };
3384
+ readonly 'request.secret_refused': {
3385
+ readonly surfaces: readonly ["console_server", "browser", "sdk"];
3386
+ readonly status: 400;
3387
+ readonly title: "Request contained a private key";
3388
+ readonly paymentState: "not_charged";
3389
+ readonly retry: "never";
3390
+ readonly nextAction: "fix_request";
3391
+ readonly user: {
3392
+ readonly title: "Private key not accepted";
3393
+ readonly message: "Never send a private key. Your key stays on your device.";
3394
+ };
3395
+ };
3396
+ readonly 'request.service_definition_invalid': {
3397
+ readonly surfaces: readonly ["gateway"];
3398
+ readonly status: 400;
3399
+ readonly title: "Service registration has a missing or invalid field";
3400
+ readonly paymentState: "not_charged";
3401
+ readonly retry: "never";
3402
+ readonly nextAction: "fix_request";
3403
+ readonly user: {
3404
+ readonly title: "Check your service details";
3405
+ readonly message: "Some service details are missing or not valid. Fix them and publish again.";
3406
+ };
3407
+ };
3408
+ readonly 'request.service_id_taken': {
3409
+ readonly surfaces: readonly ["gateway"];
3410
+ readonly status: 409;
3411
+ readonly title: "Service id is already registered";
3412
+ readonly paymentState: "not_charged";
3413
+ readonly retry: "never";
3414
+ readonly nextAction: "fix_request";
3415
+ readonly user: {
3416
+ readonly title: "ID already taken";
3417
+ readonly message: "Another service already uses that ID. Pick a different one.";
3418
+ };
3419
+ };
3420
+ readonly 'request.service_inactive': {
3421
+ readonly surfaces: readonly ["gateway"];
3422
+ readonly status: 403;
3423
+ readonly title: "Service is paused, revoked or not listed";
3424
+ readonly paymentState: "not_charged";
3425
+ readonly retry: "never";
3426
+ readonly nextAction: "none";
3427
+ readonly user: {
3428
+ readonly title: "Service not available";
3429
+ readonly message: "You can't use this service right now because it isn't taking requests.";
3430
+ };
3431
+ };
3432
+ readonly 'request.service_logo_invalid': {
3433
+ readonly surfaces: readonly ["gateway"];
3434
+ readonly status: 400;
3435
+ readonly title: "Service logo is not accepted";
3436
+ readonly paymentState: "not_charged";
3437
+ readonly retry: "never";
3438
+ readonly nextAction: "fix_request";
3439
+ readonly user: {
3440
+ readonly title: "Logo not accepted";
3441
+ readonly message: "Use a smaller image in a supported format for your logo.";
3442
+ };
3443
+ };
3444
+ readonly 'request.service_terminal': {
3445
+ readonly surfaces: readonly ["gateway"];
3446
+ readonly status: 409;
3447
+ readonly title: "Service is in a terminal state";
3448
+ readonly paymentState: "not_charged";
3449
+ readonly retry: "never";
3450
+ readonly nextAction: "none";
3451
+ readonly user: {
3452
+ readonly title: "Service retired";
3453
+ readonly message: "This service was retired, so you can't change it.";
3454
+ };
3455
+ };
3456
+ readonly 'request.transition_invalid': {
3457
+ readonly surfaces: readonly ["gateway"];
3458
+ readonly status: 409;
3459
+ readonly title: "Status change is not allowed from the current state";
3460
+ readonly paymentState: "not_charged";
3461
+ readonly retry: "never";
3462
+ readonly nextAction: "fix_request";
3463
+ readonly user: {
3464
+ readonly title: "Can't make that change";
3465
+ readonly message: "You can't make that change while the service is in its current state.";
3466
+ };
3467
+ };
3468
+ readonly 'request.url_invalid': {
3469
+ readonly surfaces: readonly ["seller", "console_server", "sdk", "mcp_local", "mcp_hosted"];
3470
+ readonly status: 400;
3471
+ readonly title: "URL is missing, malformed or on the wrong origin";
3472
+ readonly paymentState: "not_charged";
3473
+ readonly retry: "never";
3474
+ readonly nextAction: "fix_request";
3475
+ readonly user: {
3476
+ readonly title: "Check the address";
3477
+ readonly message: "Enter a complete web address that starts with https and try again.";
3478
+ };
3479
+ };
3480
+ };
3481
+ type Registry = typeof ERRORS;
3482
+ /** Every registered code. */
3483
+ type ErrorCode = keyof Registry & string;
3484
+ /** The codes a given surface may originate. Builders are typed with this. */
3485
+ type CodeFor<S extends Surface> = {
3486
+ [K in ErrorCode]: S extends Registry[K]['surfaces'][number] ? K : never;
3487
+ }[ErrorCode];
3488
+
3489
+ /**
3490
+ * Non-MCP SDK/REST delegated-signer payer (Phase C1).
3491
+ *
3492
+ * MPP pay-then-prove over `spend_account::settle_policy` with a bring-your-own
3493
+ * delegated key. Mirrors packages/mcp/src/spend-account-pay.ts but:
3494
+ * - gas: agent-provided coins (default when configured) OR sponsored gas
3495
+ * gated by sponsor personal-message challenge (Phase C2 / ADR-0008)
3496
+ * - x402 (`dialect: 'x402'`) signs the pay with the offer's pinned sponsor
3497
+ * gas and presents it as PAYMENT-SIGNATURE; the gateway co-signs and
3498
+ * submits (docs/decisions/ADR-0045-delegate-x402-from-the-spend-account.md)
3499
+ *
3500
+ * Order is load-bearing on the money path (no step may run before the prior):
3501
+ * 1. Bound the offer FIRST — the gateway secret's HMAC over it, the agent's
3502
+ * own SpendIntent, or both; at least one is required. Nothing else
3503
+ * (ledger, capability, hashing) runs before this.
3504
+ * 2. Request-binding + offer-expiry checks.
3505
+ * 3. ATOMIC reserve on the REQUIRED payment-attempt ledger (payment_id).
3506
+ * - reserved -> this attempt owns the id; may proceed to build/sign
3507
+ * - done -> return validated prior ok/ambiguous (no re-sign)
3508
+ * - in_flight -> another attempt is mid-flight; return ambiguous (no sign)
3509
+ * Reserve failure fails closed: never sign without a durable claim.
3510
+ * 4. Execution-capability check (submitter present). After reserve so a
3511
+ * prior done result is never lost when capability is unavailable.
3512
+ * 5. Derive payment_id_hash / terms_hash.
3513
+ * 6. Build the full executable pay transaction (real shared-object versions).
3514
+ * 7. Validate-before-sign (built tx encodes exactly the intended pay; gas may differ).
3515
+ * 8. Sign, 9. execute, 10. complete(ledger) with terminal ok/ambiguous, settle.
3516
+ * x402 refuses before 3 when its offer, gas pins or epoch are missing, skips
3517
+ * 4, builds 6 with the offer-pinned sponsor gas, and in place of 9-10
3518
+ * presents the signed credential (the gateway co-signs and submits).
3519
+ *
3520
+ * Exactly-once for concurrent pay() on the same payment_id is the ledger
3521
+ * reserve CAS (memory: sync check-and-insert; Postgres: INSERT ON CONFLICT).
3522
+ * Settlement single-use on chain is the pool-scoped payment_id_hash replay
3523
+ * marker inside pay. The durable ChallengeStore is a delivery/proof CAS
3524
+ * (prevents a second proof/delivery for the same challenge), not the money
3525
+ * CAS (see ADR-0002).
3526
+ */
3527
+
3528
+ type DelegatedPayStatus = 'ok' | 'failed' | 'ambiguous';
3529
+ /**
3530
+ * Classification of a resource's non-402 response. Distinguishes a resource
3531
+ * served without payment (`unpaid_ok`, a 2xx) from a client-side refusal
3532
+ * (`rejected`, a non-2xx below 500) and a transient outage (`unavailable`, a
3533
+ * 5xx) — so a caller never mistakes a 503 for "already paid / ok". Absent on a
3534
+ * 402-driven pay outcome, which the `status`/`code`/`paid` fields describe.
3535
+ */
3536
+ type DelegatedPayResponseClass = 'unpaid_ok' | 'rejected' | 'unavailable';
3537
+ /**
3538
+ * The settled effects of a finality-confirmed pay, so a caller need not do a
3539
+ * separate on-chain read to learn what moved. `spend_account::settle_policy` debits exactly
3540
+ * `amount` of `coinType` to `recipient` from the grant's pool, and a `success`
3541
+ * finality confirms that transfer executed — so these are the settled effects,
3542
+ * not merely the intended ones. Present only on a settled (`paid`) result.
3543
+ */
3544
+ interface DelegatedPaySettlement {
3545
+ /** Finality-confirmed settlement status (only `success` reaches a paid result). */
3546
+ status: 'success';
3547
+ /** The settling transaction digest. */
3548
+ txDigest: string;
3549
+ /** Atomic units debited to the recipient (the offer amount the pay enforced). */
3550
+ amount: string;
3551
+ /** The paid recipient (the offer/target payTo the pay debited to). */
3552
+ recipient: string;
3553
+ /** Coin type settled. */
3554
+ coinType: string;
3555
+ /** Off-chain asset id of the offer. */
3556
+ asset: string;
3557
+ /** Grant object that authorized the draw. */
3558
+ grantObjectId: string;
3559
+ /** Pool object the draw debited. */
3560
+ poolObjectId: string;
3561
+ }
3562
+ interface DelegatedPayResult {
3563
+ /**
3564
+ * How resolved the outcome is: `ok` = settled AND delivered; `ambiguous` =
3565
+ * something after the signature is unresolved, so reconcile rather than retry;
3566
+ * `failed` = nothing was signed, or the chain rejected the settlement.
3567
+ */
3568
+ status: DelegatedPayStatus;
3569
+ /**
3570
+ * Did money leave the grant?
3571
+ *
3572
+ * - `true` — settlement was finality-confirmed `success`. {@link settlement}
3573
+ * carries the confirmed effects.
3574
+ * - `false` — nothing was signed, or the chain rejected the settlement. The
3575
+ * money is still in the pool.
3576
+ * - `'unknown'` — a signature left this process and execute/finality did not
3577
+ * resolve. The money may have moved. A caller that treats this as `false`
3578
+ * and retries will pay twice. `if (!result.paid)` is false for `'unknown'`.
3579
+ */
3580
+ paid: boolean | 'unknown';
3581
+ /**
3582
+ * Whether money moved, in the registry's words. Always agrees with `paid`:
3583
+ * `charged` ↔ `true`, `not_charged` ↔ `false`, `unknown` ↔ `'unknown'`. On a
3584
+ * result that is not `ok`, `failed` ⇔ `not_charged`.
3585
+ */
3586
+ paymentState: PaymentState;
3587
+ body?: unknown;
3588
+ receipt?: Receipt | null;
3589
+ /**
3590
+ * The registry code of a failed or ambiguous result. A gateway problem
3591
+ * document's code is kept as received, including one this SDK's registry
3592
+ * does not know yet (a newer gateway); a legacy gateway string never is.
3593
+ * Branch on this.
3594
+ */
3595
+ code?: ErrorCode | (string & {});
3596
+ /** True only when retrying cannot charge twice; derived, never guessed. */
3597
+ retryable?: boolean;
3598
+ /** What the caller should do next; derived from the code and the money state. */
3599
+ nextAction?: NextAction;
3600
+ /** The offer's challenge id (the same value as `paymentId`), when known. */
3601
+ challengeId?: string;
3602
+ /** Resource HTTP status for a non-402 outcome (preserved, not swallowed). */
3603
+ httpStatus?: number;
3604
+ /** Classification of a non-402 outcome; see {@link DelegatedPayResponseClass}. */
3605
+ responseClass?: DelegatedPayResponseClass;
3606
+ /** Caller-safe detail only; never raw RPC/gateway exception text. */
3607
+ detail?: string;
3608
+ /**
3609
+ * On-chain digest when known. For digestless ambiguity after a possible
3610
+ * broadcast, set to {@link BROADCAST_UNKNOWN}.
3611
+ */
3612
+ txDigest?: string;
3613
+ /** payment_id = offer.challengeId; reconcile key on ambiguous outcomes. */
3614
+ paymentId?: string;
3615
+ /**
3616
+ * Settled effects (amount/recipient/status) of a finality-confirmed pay.
3617
+ * Present on every `paid` result, including a settled pay whose delivery then
3618
+ * failed — that is exactly the case where a caller cannot afford to guess.
3619
+ */
3620
+ settlement?: DelegatedPaySettlement;
3621
+ }
3622
+ /**
3623
+ * Non-secret connection manifest produced at authorize-agent success.
3624
+ * Enough for the agent to resolve grant/policy/target without owner SIWS.
3625
+ */
3626
+ interface DelegatedSignerConnectionManifest {
3627
+ network: string;
3628
+ packageId: string;
3629
+ poolObjectId: string;
3630
+ grantObjectId: string;
3631
+ coinType: string;
3632
+ delegateAddress: string;
3633
+ /** Off-chain grant id for audit; optional. */
3634
+ grantId?: string;
3635
+ status?: GrantSnapshot['status'];
3636
+ policies: GrantSnapshot['policies'];
3637
+ /** Delegation-grant ceiling (on-chain Move type: `GrantCap.max_per_payment`). */
3638
+ maxPerPayment?: string;
3639
+ /** Grant-level session cap. Required positive for open surface. */
3640
+ sessionCap?: string;
3641
+ /** `open` = full access (no allowlist); omit/scoped = policy-bound. */
3642
+ accessMode?: 'scoped' | 'open';
3643
+ }
3644
+ /** Signer callback: address + sign over full transaction bytes (base64). */
3645
+ interface DelegatedKeySigner {
3646
+ address: string;
3647
+ signTransaction(txBytes: string): Promise<string>;
3648
+ /**
3649
+ * Personal-message signature (Sui IntentScope.PersonalMessage). Required
3650
+ * for the sponsored-gas personal-message path; not used when the agent supplies gas.
3651
+ */
3652
+ signPersonalMessage?(message: Uint8Array): Promise<string>;
3653
+ }
3654
+ /**
3655
+ * Platform gas sponsorship client for BYO personal-message (ADR-0008). The payer obtains
3656
+ * a single-use nonce, signs the domain-separated personal-message over the pre-sponsor
3657
+ * kind hash, then create+execute the sponsored pay. The x402 dialect does not
3658
+ * use it: there the gateway co-signs the offer-pinned gas (ADR-0045).
3659
+ */
3660
+ interface SponsoredGasClient {
3661
+ /** Gateway origin hosting /api/sponsor (no trailing slash). */
3662
+ sponsorUrl: string;
3663
+ fetchImpl?: typeof fetch;
3664
+ }
3665
+ type DelegatedSignerInput = DelegatedKeySigner | Ed25519Keypair | (() => Promise<DelegatedKeySigner> | DelegatedKeySigner);
3666
+ /**
3667
+ * Authority for one payment. Prefer an in-process snapshot/manifest; a
3668
+ * read-only fetch callback may load the same shape from a connection
3669
+ * manifest or a read endpoint the agent is allowed to call.
3670
+ */
3671
+ type GrantResolutionSource = GrantSnapshot | DelegatedSignerConnectionManifest | (() => Promise<GrantSnapshot | DelegatedSignerConnectionManifest>);
3672
+ interface DelegatedPayerSession {
3673
+ /** Package id of the published spend_account module (must match offer). */
3674
+ packageId: string;
3675
+ /** Network as offer.network expects, e.g. `sui:testnet`. */
3676
+ network: string;
3677
+ /** Grant + pool + policies for resolveGrantTarget. */
3678
+ authority: GrantResolutionSource;
3679
+ /** BYO delegated key (keypair or sign callback). Never platform-custodied. */
3680
+ signer: DelegatedSignerInput;
3681
+ /**
3682
+ * Optional re-check immediately before sign (pause/revoke race). Throw to
3683
+ * abort. When absent, request-time snapshot is the only pre-sign gate.
3684
+ */
3685
+ assertLive?: () => Promise<void>;
3686
+ }
3687
+ /** Gas coin ref for a complete executable transaction. */
3688
+ interface GasPaymentRef {
3689
+ objectId: string;
3690
+ version: string | number | bigint;
3691
+ digest: string;
3692
+ }
3693
+ interface AgentGasInput {
3694
+ budget?: string | number | bigint;
3695
+ price?: string | number | bigint;
3696
+ payment: GasPaymentRef[];
3697
+ /** Defaults to the delegate (sender). */
3698
+ owner?: string;
3699
+ }
3700
+ /**
3701
+ * Inputs for building a complete executable spend_account::settle_policy transaction
3702
+ * (sender + gas + move call). Not kind-only bytes.
3703
+ *
3704
+ * Pool and grant must carry real initial shared versions from chain (not a
3705
+ * hard-coded "1"). Mirror SpendAccountChain.buildPayKind / MCP production path
3706
+ * which resolve via getObject / tx.object + client.
3707
+ */
3708
+ interface BuildPayTxInput {
3709
+ packageId: string;
3710
+ delegate: string;
3711
+ coinType: string;
3712
+ poolObjectId: string;
3713
+ grantObjectId: string;
3714
+ /** Real initial shared version of the pool object (from chain). */
3715
+ poolInitialSharedVersion: string;
3716
+ /** Real initial shared version of the grant object (from chain). */
3717
+ grantInitialSharedVersion: string;
3718
+ /**
3719
+ * Initial shared version of the system Clock (0x6). Defaults to genesis
3720
+ * version "1" when omitted.
3721
+ */
3722
+ clockInitialSharedVersion?: string;
3723
+ policyId: number | string;
3724
+ targetHash: string;
3725
+ amount: string;
3726
+ paymentIdHash: Uint8Array;
3727
+ termsHash: Uint8Array;
3728
+ gas: AgentGasInput;
3729
+ /**
3730
+ * Guarded settle inputs. Present for a guarded delegate offer; when set the
3731
+ * builder emits `settle_policy` threading the exclusion directory +
3732
+ * per-recipient registry (each as a shared object ref built from its initial
3733
+ * shared version) + signed expiry. Required on the fresh lineage even for a
3734
+ * single-rail settle (there is no unguarded twin).
3735
+ */
3736
+ exclusionDirectoryId?: string;
3737
+ recipientRegistryId?: string;
3738
+ exclusionDirectoryInitialSharedVersion?: string;
3739
+ recipientRegistryInitialSharedVersion?: string;
3740
+ expiresAtMs?: string | number;
3741
+ }
3742
+ /**
3743
+ * Result of an atomic payment-id reserve (exactly-once attempt claim).
3744
+ *
3745
+ * - reserved: this caller owns the attempt; only then may build/sign/execute
3746
+ * - in_flight: another attempt is mid-flight (or complete never landed); do not sign
3747
+ * - done: a terminal ok/ambiguous is recorded; return validated prior
3748
+ */
3749
+ type PaymentAttemptReserveResult = {
3750
+ state: 'reserved';
3751
+ } | {
3752
+ state: 'in_flight';
3753
+ prior?: DelegatedPayResult;
3754
+ } | {
3755
+ state: 'done';
3756
+ prior: DelegatedPayResult;
3757
+ };
3758
+ /**
3759
+ * Durable ledger of payment attempts keyed by payment_id (offer.challengeId).
3760
+ * REQUIRED on the pay path. Exactly-once is reserve-before-sign:
3761
+ * reserve (atomic) -> build/validate/sign/execute only if reserved -> complete
3762
+ * Persistence failure fails closed (never sign without a durable claim).
3763
+ */
3764
+ interface PaymentAttemptLedger {
3765
+ /**
3766
+ * Atomically claim paymentId for this attempt, or report prior/in-flight.
3767
+ * Must not interleave another reserve for the same id between check and claim
3768
+ * (memory: sync Map check-and-insert; Postgres: INSERT ON CONFLICT DO NOTHING).
3769
+ */
3770
+ reserve(paymentId: string, fingerprint: string): Promise<PaymentAttemptReserveResult>;
3771
+ /**
3772
+ * Write the terminal ok/ambiguous result for a reserved payment_id.
3773
+ * After complete, further reserve() calls return state:'done' with prior.
3774
+ * Throws on persistence failure (caller must not swallow).
3775
+ */
3776
+ complete(paymentId: string, result: DelegatedPayResult): Promise<void>;
3777
+ /**
3778
+ * Drop an in-flight reservation when no sign/execute happened (clean abort).
3779
+ * No-op when the row is already terminal. Optional; missing release leaves
3780
+ * in_flight so retries stay fail-closed (ambiguous, no re-sign).
3781
+ */
3782
+ release?(paymentId: string): Promise<void>;
3783
+ }
3784
+ /**
3785
+ * Resolve real initial shared versions for pool + grant from chain.
3786
+ * Production should call getObject (or SpendAccountChain-equivalent resolution).
3787
+ */
3788
+ type ResolveSharedObjectVersions = (ids: {
3789
+ poolObjectId: string;
3790
+ grantObjectId: string;
3791
+ clockObjectId?: string;
3792
+ }) => Promise<{
3793
+ poolInitialSharedVersion: string;
3794
+ grantInitialSharedVersion: string;
3795
+ clockInitialSharedVersion?: string;
3796
+ }>;
3797
+ /**
3798
+ * One step of an x402 payment, reported as it happens so a caller can show it
3799
+ * (the console playground's timeline). `presented` and `answered` repeat once
3800
+ * per presentation while the gateway answers 503.
3801
+ */
3802
+ type X402PayProgress = {
3803
+ stage: 'built';
3804
+ txBytes: string;
3805
+ } | {
3806
+ stage: 'signed';
3807
+ signature: string;
3808
+ } | {
3809
+ stage: 'presented';
3810
+ header: string;
3811
+ attempt: number;
3812
+ } | {
3813
+ stage: 'answered';
3814
+ status: number;
3815
+ paymentResponse: string | null;
3816
+ attempt: number;
3817
+ };
3818
+ interface DelegatedPayerDeps {
3819
+ fetchImpl?: typeof fetch;
3820
+ now?: () => number;
3821
+ /**
3822
+ * The gateway's HMAC secret, when the caller legitimately holds one — an
3823
+ * operator running its own gateway, or a test. Present: offer digests are
3824
+ * verified client-side before any ledger, capability, hash, build, or sign.
3825
+ *
3826
+ * Optional, because an external agent must never be given it: it is the
3827
+ * secret that authenticates the gateway to itself, and handing it out makes
3828
+ * every holder able to forge offers for every other. An agent without it
3829
+ * supplies a {@link SpendIntent} instead. One of the two is REQUIRED — with
3830
+ * neither, nothing bounds what the offer may charge, and payment is refused
3831
+ * before any ledger, hash, build, or sign.
3832
+ */
3833
+ offerSecret?: string;
3834
+ /**
3835
+ * REQUIRED payment-attempt ledger. Absent ledger refuses to pay (config
3836
+ * error) rather than run an unprotected re-sign/rebroadcast path.
3837
+ */
3838
+ paymentLedger: PaymentAttemptLedger;
3839
+ /**
3840
+ * Build a COMPLETE executable pay transaction (delegate sender, gas,
3841
+ * real move call). Default uses {@link buildSpendAccountPayTx} with
3842
+ * {@link gas}. Must never return kind-only non-executable bytes.
3843
+ */
3844
+ buildPayTx?: (input: BuildPayTxInput) => Promise<{
3845
+ txBytes: string;
3846
+ }>;
3847
+ /**
3848
+ * Agent-owned gas payment objects for the default full-tx builder.
3849
+ * Required when buildPayTx is not injected and sponsor is not set.
3850
+ * When both `gas` and `sponsor` are set, `gasMode` selects the path
3851
+ * (default: agent gas when `gas` is present, else sponsored).
3852
+ */
3853
+ gas?: AgentGasInput;
3854
+ /**
3855
+ * Sponsored-gas path gated by sponsor personal-message challenge (Phase C2).
3856
+ * Alternative to agent-provided gas. Keep agent gas as the other option.
3857
+ */
3858
+ sponsor?: SponsoredGasClient;
3859
+ /**
3860
+ * Force gas path when both agent gas and sponsor are configured.
3861
+ * Default: `'agent'` when `gas` has payment objects, else `'sponsored'`.
3862
+ */
3863
+ gasMode?: 'agent' | 'sponsored';
3864
+ /**
3865
+ * Resolve real initial shared versions for pool/grant. Required for the
3866
+ * default full-tx builder when {@link sharedObjectVersions} is not set.
3867
+ * Mirror SpendAccountChain.buildPayKind (getObject Shared owner / tx.object).
3868
+ */
3869
+ resolveSharedObjectVersions?: ResolveSharedObjectVersions;
3870
+ /**
3871
+ * Pre-resolved pool/grant initial shared versions (tests / offline inject).
3872
+ * When set, skips {@link resolveSharedObjectVersions}.
3873
+ */
3874
+ sharedObjectVersions?: {
3875
+ poolInitialSharedVersion: string;
3876
+ grantInitialSharedVersion: string;
3877
+ clockInitialSharedVersion?: string;
3878
+ };
3879
+ /**
3880
+ * Resolve the per-recipient `RecipientRegistry` object id + directory/registry
3881
+ * shared versions for a guarded delegate offer. REQUIRED for a
3882
+ * guarded offer: without it such an offer FAILS CLOSED (BUILD_FAILED) —
3883
+ * it never builds an unguarded settle, which the self-settled verifier would
3884
+ * reject anyway. An unguarded offer never calls it. In production this binds
3885
+ * the shared `resolveExclusionRegistry`
3886
+ * (`buyer-control/exclusion-registry`) to a live chain
3887
+ * reader — which supplies the shared versions at runtime; tests stub it.
3888
+ */
3889
+ resolveExclusionRegistry?: (input: {
3890
+ directoryId: string;
3891
+ packageId: string;
3892
+ recipient: string;
3893
+ }) => Promise<{
3894
+ recipientRegistryId: string;
3895
+ directoryInitialSharedVersion?: string;
3896
+ registryInitialSharedVersion?: string;
3897
+ }>;
3898
+ /** Submit signed full transaction bytes; returns the broadcast digest. */
3899
+ executeTx?: (txBytes: string, signature: string) => Promise<{
3900
+ digest: string;
3901
+ }>;
3902
+ /**
3903
+ * Confirm on-chain settlement of a broadcast digest: `success`/`failed`, or
3904
+ * `null` while not yet observed. REQUIRED on any pay that reaches settlement —
3905
+ * a pay is refused (`FINALITY_UNAVAILABLE`) before signing when this is absent,
3906
+ * so a settled tx is never mis-reported as a false `FINALIZATION_TIMEOUT`.
3907
+ */
3908
+ getSettledTx?: (digest: string) => Promise<{
3909
+ status: 'success' | 'failed';
3910
+ reason?: string;
3911
+ } | null>;
3912
+ /**
3913
+ * Await the proof-presentation delivery before returning (DEFAULT `true` —
3914
+ * today's behavior: the result carries the delivered `body` + `receipt`). Set
3915
+ * `false` to return `paid:true` with the digest + settlement summary as soon
3916
+ * as settlement is finality-confirmed, skipping the (possibly slow, e.g.
3917
+ * ~13s Walrus blob-publish) delivery fetch — the caller presents the proof and
3918
+ * fetches the body later. Non-breaking: only an explicit `false` changes flow.
3919
+ */
3920
+ awaitDelivery?: boolean;
3921
+ /**
3922
+ * Current Sui epoch from the agent's own chain client (see
3923
+ * {@link currentEpochReader}). The x402 dialect needs it to bound the
3924
+ * transaction's expiration; absent or failing, x402 is refused before
3925
+ * anything is reserved. MPP never calls it.
3926
+ */
3927
+ getCurrentEpoch?: () => Promise<bigint | number>;
3928
+ /**
3929
+ * Chain identifier from the agent's own chain client (see
3930
+ * {@link chainIdentifierReader}). Needed only for an x402 offer that pins
3931
+ * `address-balance` gas (ADR-0055); absent or failing, that offer is refused
3932
+ * before anything is reserved.
3933
+ */
3934
+ getChainIdentifier?: () => Promise<string>;
3935
+ /**
3936
+ * Build the complete x402 pay transaction. Default
3937
+ * {@link buildSpendAccountX402PayTx}. Whatever it returns is still checked
3938
+ * against the intended pay before signing.
3939
+ */
3940
+ buildX402PayTx?: (input: BuildX402PayTxInput) => Promise<{
3941
+ txBytes: string;
3942
+ }>;
3943
+ /**
3944
+ * Total presentations of one x402 credential while the gateway answers 503
3945
+ * (default 10). The gateway's execution store is single-flight per
3946
+ * challenge, so re-presenting the same credential cannot submit twice.
3947
+ */
3948
+ x402PresentAttempts?: number;
3949
+ /** Wait between x402 re-presentations (default: a 1000 ms timer). */
3950
+ sleep?: (ms: number) => Promise<void>;
3951
+ /**
3952
+ * Server-side log port for internal failure detail. Never surfaces to the
3953
+ * caller result (error hygiene). Defaults to the core structured error
3954
+ * logger (one JSON line, scope `delegated-payer`).
3955
+ */
3956
+ log?: DelegatedPayerLog;
3957
+ }
3958
+ /** One structured line about an internal payer failure. Never reaches the caller's result. */
3959
+ type DelegatedPayerLog = (entry: {
3960
+ code: CodeFor<'sdk'>;
3961
+ msg: string;
3962
+ level?: 'error' | 'warn';
3963
+ context?: Record<string, unknown>;
3964
+ }, error?: unknown) => void;
3965
+ interface DelegatedPayerConfig {
3966
+ /** Gateway origin the resource URL must match. */
3967
+ gatewayUrl: string;
3968
+ }
3969
+ /**
3970
+ * The offer-pinned sponsor gas of a delegate x402 offer, parsed. An empty
3971
+ * `payment` is the `address-balance` pin: gas comes from the sponsor's address
3972
+ * balance (ADR-0055).
3973
+ */
3974
+ interface X402GasPin {
3975
+ owner: string;
3976
+ budget: bigint;
3977
+ price: bigint;
3978
+ payment: {
3979
+ objectId: string;
3980
+ version: string;
3981
+ digest: string;
3982
+ }[];
3983
+ }
3984
+ /** Inputs for {@link buildSpendAccountX402PayTx}: the pay kind's fields plus the pinned gas. */
3985
+ interface BuildX402PayTxInput extends Omit<BuildPayTxInput, 'gas'> {
3986
+ /** Offer-pinned sponsor gas; see {@link readX402GasPin}. */
3987
+ gas: X402GasPin;
3988
+ /** Current epoch; the transaction expires 32 epochs after it. */
3989
+ currentEpoch: bigint;
3990
+ /**
3991
+ * Chain identifier. Required when `gas.payment` is empty (address-balance
3992
+ * gas), which takes a `ValidDuring` expiration instead of `Epoch`.
3993
+ */
3994
+ chainIdentifier?: string;
3995
+ /** `ValidDuring` nonce for address-balance gas; random u32 when absent. */
3996
+ nonce?: number;
3997
+ }
3998
+ /**
3999
+ * Pay a shared-pool 402 resource with a BYO delegated key via pay.
4000
+ * MPP by default; `dialect: 'x402'` presents a signed transaction credential
4001
+ * instead (docs/decisions/ADR-0045-delegate-x402-from-the-spend-account.md).
4002
+ *
4003
+ * Ordering is load-bearing: offer verify -> binding/expiry -> reserve ->
4004
+ * capability -> hash -> build -> validate -> sign -> execute -> complete.
4005
+ */
4006
+ /**
4007
+ * Economic terms already verified against a prepared settlement kind.
4008
+ *
4009
+ * A caller that verified a kind built from one 402 offer, and then hands the
4010
+ * settlement to this payer, must pin what that verification covered. The payer
4011
+ * mints its own offer from its own 402 hop; without this pin, nothing compares
4012
+ * the two, and the bytes that were checked are not the bytes that get signed.
4013
+ * Absent for direct signer mode, which reads exactly one offer.
4014
+ */
4015
+ interface PreparedSettlementTerms {
4016
+ /** Recipient the verified kind pays. */
4017
+ recipient: string;
4018
+ /** Atomic amount the verified kind moves. */
4019
+ amount: string;
4020
+ /** Coin type the verified kind spends. */
4021
+ asset: string;
4022
+ /** Policy target hash the verified kind binds. */
4023
+ targetHash: string;
4024
+ }
4025
+ /**
4026
+ * The agent's own statement of what it is buying, checked against the offer
4027
+ * before anything else happens.
4028
+ *
4029
+ * This is the input that lets an agent hold nothing but its key and a gateway
4030
+ * URL. The offer HMAC ({@link DelegatedPayerDeps.offerSecret}) proves an offer
4031
+ * came from the party that minted it — which, on this path, is the same gateway
4032
+ * the agent is paying and reached over TLS at an origin the payer already pins.
4033
+ * A gateway that wanted to overcharge never needed to forge its own offer; it
4034
+ * could simply mint an honest one for the wrong amount. So the HMAC was never
4035
+ * the check that protected the agent from its counterparty, and requiring the
4036
+ * agent to hold the gateway's secret to perform it bought nothing while making
4037
+ * every agent able to forge offers for every other.
4038
+ *
4039
+ * What does protect the agent is a ceiling it set itself, which no gateway can
4040
+ * see or change. That is this.
4041
+ */
4042
+ interface SpendIntent {
4043
+ /** Inclusive per-payment ceiling in atomic units, as a decimal string. */
4044
+ maxAmount: string;
4045
+ /** The coin type the agent is willing to spend. */
4046
+ asset: string;
4047
+ /**
4048
+ * The exact recipient the agent expects to pay. Optional: an agent buying
4049
+ * from a catalog usually learns `payTo` from the offer itself. When it does
4050
+ * know, pinning it here is the strongest single check available, because
4051
+ * recipient substitution — not overspend — is the attack the caps do not stop.
4052
+ */
4053
+ recipient?: string;
4054
+ }
4055
+ /** Optional guarded-settle fields carried on a build input. */
4056
+ interface GuardedSettleFields {
4057
+ exclusionDirectoryId?: string;
4058
+ recipientRegistryId?: string;
4059
+ exclusionDirectoryInitialSharedVersion?: string;
4060
+ recipientRegistryInitialSharedVersion?: string;
4061
+ expiresAtMs?: string | number;
4062
+ }
4063
+
4064
+ /**
4065
+ * Agent-held settlement wiring for the `pay` tool.
4066
+ *
4067
+ * The gateway prepares (it holds no key). Settlement needs the delegate key, so
4068
+ * it can only happen in the process that holds one. This module answers a single
4069
+ * question for a given grant: *is this process that grant's agent, and is it
4070
+ * configured to settle?* Any "no" returns null and `pay` falls back to handing
4071
+ * back unsigned bytes — the pre-existing behavior.
4072
+ *
4073
+ * Two conditions gate it, and the first is the security one:
4074
+ *
4075
+ * 1. **The persisted key must be the key the grant names.** A hosted gateway
4076
+ * running this same tool code either holds no credentials file (null) or
4077
+ * holds one for some unrelated key (address mismatch → null). It can only
4078
+ * settle by already possessing the grant's delegate seed — which is exactly
4079
+ * the custody ADR-0015 removed, not a state a flag protects against.
4080
+ * 2. **The settlement dependencies must all be present.** A half-configured
4081
+ * settler is worse than none: it would sign and then fail to confirm. Missing
4082
+ * anything → null, prepare-only.
4083
+ *
4084
+ * The key is read, never minted. See `loadLocalSigner`.
4085
+ */
4086
+
4087
+ /** Everything `pay` needs to settle rather than prepare. */
4088
+ interface AgentHeldSettlement {
4089
+ signer: DelegatedKeySigner;
4090
+ getObjectJson: GetObjectJson;
4091
+ payerDeps: DelegatedPayerDeps;
4092
+ }
4093
+ /**
4094
+ * Resolve agent-held settlement for one grant, or null to stay prepare-only.
4095
+ * Injectable so `createServer` can be driven without touching disk,
4096
+ * chain, or environment.
4097
+ */
4098
+ type AgentHeldResolver = (cfg: McpConfig, spendAccountPay: McpSpendAccountPayAuth) => AgentHeldSettlement | null;
4099
+ /** Test seam: drop the process ledger so suites do not share reservations. */
4100
+ declare function resetAgentHeldProcessLedger(): void;
4101
+ declare function resolveAgentHeldSettlement(cfg: McpConfig, spendAccountPay: McpSpendAccountPayAuth, env?: NodeJS.ProcessEnv): AgentHeldSettlement | null;
4102
+
4103
+ /**
4104
+ * Shared live-trace vocabulary.
4105
+ *
4106
+ * Owned by the SDK because two independent consumers need it: `apps/gateway`,
4107
+ * which emits and stores traces, and `@cmdoss/suipay-mcp`, which proxies them.
4108
+ * A published package cannot reach into a deployed service's source tree for
4109
+ * its own public types, so the names both sides speak live here.
4110
+ *
4111
+ * Gateway-only concerns — the store contract, run keys, redaction brands,
4112
+ * retention limits — stay in `apps/gateway/src/trace/types.ts`, which
4113
+ * re-exports everything below so its existing importers are unaffected.
4114
+ */
4115
+ type TraceSource = 'mcp_wire' | 'suipay' | 'sui';
4116
+ type TraceStatus = 'started' | 'ok' | 'warning' | 'error' | 'ambiguous';
4117
+ type TraceEventKind = 'mcp_connected' | 'tools_listed' | 'tool_called' | 'tool_result' | 'tool_error' | 'challenge_received' | 'authority_matched' | 'authority_revalidated' | 'sponsor_requested' | 'transaction_sponsored' | 'delegate_signed' | 'transaction_submitted' | 'payment_finalized' | 'proof_presented' | 'upstream_delivered' | 'upstream_delivery_failed' | 'settlement_projected' | 'settlement_projection_failed' | 'receipt_issued' | 'payment_failed' | 'payment_ambiguous';
4118
+ interface TraceEventInput {
4119
+ traceId: string;
4120
+ requestId: string | null;
4121
+ buyerAccountId: string;
4122
+ connectionId: string;
4123
+ at: string;
4124
+ source: TraceSource;
4125
+ kind: TraceEventKind;
4126
+ status: TraceStatus;
4127
+ summary: string;
4128
+ publicPayload: Record<string, unknown>;
4129
+ technicalPayload?: Record<string, unknown>;
4130
+ }
4131
+ /**
4132
+ * Correlation constraints an emitter can attach to one event.
4133
+ *
4134
+ * `requireSoleActiveRunForBuyer` is the server-side (ADR-0011) fallback's
4135
+ * atomicity guard: the event is persisted only if, at append time, that buyer
4136
+ * still has exactly one active run. It closes the window between selecting the
4137
+ * sole run and appending to it — a second run opening in between makes the
4138
+ * append fail closed rather than land on a run that is no longer sole.
4139
+ */
4140
+ interface TraceEmitOptions {
4141
+ requireSoleActiveRunForBuyer?: string;
4142
+ }
4143
+ interface TraceSink {
4144
+ emit(event: TraceEventInput, options?: TraceEmitOptions): Promise<void>;
4145
+ }
4146
+ type TraceRunEndReason = 'completed' | 'idle' | 'superseded' | 'event_cap' | 'byte_cap' | 'shutdown';
4147
+ interface TraceRun {
4148
+ id: string;
4149
+ buyerAccountId: string;
4150
+ connectionId: string;
4151
+ clientName: string | null;
4152
+ startedAt: string;
4153
+ lastEventAt: string;
4154
+ endedAt: string | null;
4155
+ endReason: TraceRunEndReason | null;
4156
+ /** Persisted events accepted into this run. */
4157
+ eventCount: number;
4158
+ /** Serialized sanitized payload bytes accepted into this run. */
4159
+ payloadBytes: number;
4160
+ }
4161
+ interface TraceRunResolver {
4162
+ resolveRun(input: {
4163
+ buyerAccountId: string;
4164
+ connectionId: string;
4165
+ jsonRpcMethod: string | null;
4166
+ clientName: string | null;
4167
+ now: number;
4168
+ }): Promise<TraceRun>;
4169
+ }
4170
+
4171
+ /**
4172
+ * Transparent MCP wire proxy.
4173
+ *
4174
+ * This module is the *only* place in the system that parses MCP methods and
4175
+ * JSON-RPC ids. The gateway authenticates and hands over a run manager and a
4176
+ * sink; it never sniffs an MCP body a second time. Payment code emits domain
4177
+ * facts, never wire facts. That single-owner rule is what stops two subsystems
4178
+ * from disagreeing about which tool call a payment belongs to.
4179
+ *
4180
+ * Transparency is the top invariant, and it is structural rather than
4181
+ * best-effort:
4182
+ *
4183
+ * - With no runtime, this file is a pass-through and does not touch the
4184
+ * request or the response at all.
4185
+ * - With a runtime, observation reads `Request.clone()` and `Response.clone()`
4186
+ * only. The exact `Response` instance the handler produced is what the caller
4187
+ * receives, so byte equality is by construction, not by careful copying.
4188
+ * - Response observation is started and deliberately not awaited. A trace
4189
+ * store that hangs cannot hold an MCP response open.
4190
+ * - The request side cannot be fire-and-forget — the proxy must know the run
4191
+ * and the JSON-RPC ids before the handler runs — so it is bounded instead:
4192
+ * one deadline over envelope parsing plus run selection, and the same byte
4193
+ * cap the response observer uses. A hung store or an oversized body costs
4194
+ * the trace, never the request.
4195
+ * - Every observation path is wrapped: a hostile body, a failing run manager or
4196
+ * a throwing sink degrades to "no trace", never to a changed response.
4197
+ *
4198
+ * Volume control lives here too. One `tool_called` per JSON-RPC id and one
4199
+ * terminal `tool_result` / `tool_error` per id — never one row per SSE frame.
4200
+ */
4201
+
4202
+ /** Everything the proxy needs to attribute wire facts to one owned run. */
4203
+ interface McpTraceRuntime {
4204
+ buyerAccountId: string;
4205
+ connectionId: string;
4206
+ runs: TraceRunResolver;
4207
+ sink: TraceSink;
4208
+ /**
4209
+ * HMAC secret for signed cross-request context. Supplied by the composition
4210
+ * root so a published SDK never reads a gateway-only environment variable.
4211
+ * Absent means internal hops carry no correlation and the gateway simply
4212
+ * emits no linked events.
4213
+ */
4214
+ secret?: string | null;
4215
+ /** Injected clock; tests pin it, production leaves it out. */
4216
+ now?: () => number;
4217
+ }
4218
+ /** The proxy-resolved context handed down to payment code (Task 5 seams). */
4219
+ interface McpTraceContext {
4220
+ traceId: string;
4221
+ requestId: string | null;
4222
+ }
4223
+ interface McpTraceHooks {
4224
+ runtime: McpTraceRuntime;
4225
+ context: McpTraceContext;
4226
+ sink: TraceSink;
4227
+ }
4228
+ /** One JSON-RPC message read off the request side. */
4229
+ interface McpEnvelopeEntry {
4230
+ method: string | null;
4231
+ jsonRpcId: string | number | null;
4232
+ /** Canonical, header-safe request id. `null` for notifications. */
4233
+ requestId: string | null;
4234
+ toolName: string | null;
4235
+ toolArguments: unknown;
4236
+ clientName: string | null;
4237
+ clientVersion: string | null;
4238
+ protocolVersion: string | null;
4239
+ }
4240
+ interface McpEnvelope {
4241
+ batch: boolean;
4242
+ entries: McpEnvelopeEntry[];
4243
+ /** First entry's method — what run selection keys on. */
4244
+ method: string | null;
4245
+ requestId: string | null;
4246
+ clientName: string | null;
4247
+ }
4248
+ /**
4249
+ * Canonical MCP request id.
4250
+ *
4251
+ * JSON-RPC allows both `7` and `"7"` as distinct ids, and they must stay
4252
+ * distinct: correlating a payment to the wrong tool call is worse than not
4253
+ * correlating it. Numbers keep their JSON form under `n:`; strings are
4254
+ * base64url-encoded under `s:` so an id containing newlines, colons or quotes
4255
+ * survives being carried in an HTTP header without escaping games.
4256
+ */
4257
+ declare function canonicalMcpRequestId(id: unknown): string | null;
4258
+ /**
4259
+ * Read the JSON-RPC envelope from a request **clone**.
4260
+ *
4261
+ * The caller owns cloning; this consumes the body it is given. An unparsable,
4262
+ * bodiless or over-cap request yields an empty envelope rather than an error — a
4263
+ * malformed request is the transport's problem to answer, not tracing's problem
4264
+ * to block.
4265
+ */
4266
+ declare function inspectMcpEnvelope(request: Request, maxBytes?: number): Promise<McpEnvelope>;
4267
+ interface TraceMcpHttpRequestInput {
4268
+ request: Request;
4269
+ /**
4270
+ * The real MCP handler. Receives the untouched original request, plus the
4271
+ * resolved trace context when tracing is live.
4272
+ */
4273
+ handle: (request: Request, hooks?: McpTraceHooks) => Promise<Response>;
4274
+ runtime?: McpTraceRuntime | null;
4275
+ /** Cap on bytes read for observation, request and response. Never unbounded. */
4276
+ maxObservedBytes?: number;
4277
+ /**
4278
+ * Deadline for envelope parsing plus run selection, the only trace work that
4279
+ * happens before the handler. Past it the exchange proceeds untraced.
4280
+ */
4281
+ runSetupTimeoutMs?: number;
4282
+ }
4283
+ /**
4284
+ * Wrap one MCP HTTP exchange in observation.
4285
+ *
4286
+ * The response returned here is the exact object `handle` produced. Nothing on
4287
+ * the observation path can change it, delay it, or prevent it.
4288
+ */
4289
+ declare function traceMcpHttpRequest(input: TraceMcpHttpRequestInput): Promise<Response>;
4290
+
4291
+ /**
4292
+ * Shared interfaces for the pay-operation module.
4293
+ *
4294
+ * This is the unified prepare/verify/sign/submit/resume pipeline. It extracts
4295
+ * the offer-acquisition and authority-resolution logic shared by the SDK payer
4296
+ * and the MCP prepare module into one place.
4297
+ *
4298
+ * Design constraints:
4299
+ * - Never signs, executes, or holds a key (pure read + PTB-build).
4300
+ * - Never touches the payment ledger (SDK payer's exactly-once concern).
4301
+ * - Returns the full Offer object so callers can build proofs/summaries.
4302
+ * - The signer is a callback interface (never holds private keys).
4303
+ * - Gas strategy is injectable (agent-provided or sponsor callback).
4304
+ */
4305
+
4306
+ interface PayOperationDeps {
4307
+ fetchImpl?: typeof fetch;
4308
+ /** Preferred dialect (default 'mpp'). */
4309
+ preferredDialect?: Dialect;
4310
+ /**
4311
+ * Optional prefetched 402 Response. When present, resolvePayment reuses it
4312
+ * instead of fetching again (mirrors resolveDirectX402). When omitted,
4313
+ * resolvePayment fetches url with request.
4314
+ */
4315
+ prefetchedResponse?: Response;
4316
+ /**
4317
+ * Called with the offer immediately after reading the 402. Caller may
4318
+ * verify HMAC, check SpendIntent, check expiry, check preparedTerms.
4319
+ * Throw to abort with { status: 'failed', code: OFFER_VALIDATION_FAILED }.
4320
+ */
4321
+ validateOffer?: (offer: Offer, paymentId: string) => void | Promise<void>;
4322
+ /**
4323
+ * Build unsigned kind bytes. Caller controls whether initialSharedVersion
4324
+ * comes from chain (SDK) or is hardcoded '1' (MCP prepare).
4325
+ */
4326
+ buildPayKind: (input: BuildPayKindInput) => Promise<BuildPayKindOutput>;
4327
+ /**
4328
+ * Resolve the per-recipient `RecipientRegistry` object id bound in the offer's
4329
+ * exclusion directory. REQUIRED for a guarded delegate offer — including
4330
+ * a single-rail delegate offer and one whose authenticated `acceptedRails`
4331
+ * co-advertise the delegate rail with a gateway-executed rail. When present,
4332
+ * the operation threads the guarded-settle inputs into `buildPayKind` so the
4333
+ * built tx calls the GUARDED entrypoint and consumes the shared on-chain
4334
+ * marker. Without this resolver a guarded offer fails closed rather than
4335
+ * building an unguarded settle.
4336
+ */
4337
+ resolveExclusionRegistry?: (input: {
4338
+ /** The exclusion directory object id from the offer's registryIdentity. */
4339
+ directoryId: string;
4340
+ /** The settlement package (from the offer / registryIdentity). */
4341
+ packageId: string;
4342
+ /** The recipient (offer.payTo) whose registry to resolve. */
4343
+ recipient: string;
4344
+ }) => Promise<{
4345
+ recipientRegistryId: string;
4346
+ /**
4347
+ * Initial shared versions of the directory + registry (both shared objects).
4348
+ * OPTIONAL here: a client-backed builder (`tx.object`) resolves versions at
4349
+ * build time and does not need them, while the SDK's offline
4350
+ * (`sharedObjectRef`) builder does. When present they are threaded through
4351
+ * `buildPayKind` and exposed on the resolved payment so an offline caller can
4352
+ * rebuild the same guarded PTB.
4353
+ */
4354
+ directoryInitialSharedVersion?: string;
4355
+ registryInitialSharedVersion?: string;
4356
+ }>;
4357
+ }
4358
+ interface BuildPayKindInput {
4359
+ packageId: string;
4360
+ delegate: string;
4361
+ coinType: string;
4362
+ poolObjectId: string;
4363
+ grantObjectId: string;
4364
+ onChainPolicyId: number | string;
4365
+ targetHash: string;
4366
+ amount: string;
4367
+ paymentIdHash: Uint8Array;
4368
+ termsHash: Uint8Array;
4369
+ recipient: string;
4370
+ /** Delegation scope — selects the on-chain pay function (see `DelegationScope`). */
4371
+ accessMode: DelegationScope;
4372
+ /**
4373
+ * Guarded settle inputs. Present for a guarded delegate offer; when set,
4374
+ * the builder emits the GUARDED delegate entrypoint threading the exclusion
4375
+ * directory + per-recipient registry + signed expiry. Required on the fresh
4376
+ * lineage even for a single-rail delegate offer (there is no unguarded twin).
4377
+ */
4378
+ exclusionDirectoryId?: string;
4379
+ recipientRegistryId?: string;
4380
+ expiresAtMs?: string | number;
4381
+ /**
4382
+ * Initial shared versions of the directory + registry, for an offline builder
4383
+ * that references them by `sharedObjectRef`. Absent for a client-backed builder
4384
+ * that resolves shared versions at build time (`tx.object`).
4385
+ */
4386
+ exclusionDirectoryInitialSharedVersion?: string;
4387
+ recipientRegistryInitialSharedVersion?: string;
4388
+ }
4389
+ interface BuildPayKindOutput {
4390
+ /** Unsigned transaction kind bytes (base64). */
4391
+ kindBytes: string;
4392
+ }
4393
+
4394
+ /**
4395
+ * Shared pay-request helpers.
4396
+ *
4397
+ * The V1 allowance sponsored payer (ADR-0010) is retired; only the
4398
+ * rail-neutral request surface the SpendAccount payer depends on survives here:
4399
+ * the `PayResult` shape every payer returns. `paidRequestInit` is the SDK helper
4400
+ * that builds the one RequestInit replayed byte for byte on both calls.
4401
+ */
4402
+
4403
+ type PayResult = {
4404
+ status: 'ok' | 'failed' | 'ambiguous';
4405
+ /**
4406
+ * `true` — settlement confirmed. `false` — money did not leave the
4407
+ * account. `'unknown'` — execute/finality did not resolve; a retry can
4408
+ * pay twice.
4409
+ */
4410
+ paid: boolean | 'unknown';
4411
+ /** Whether money moved; always agrees with `paid`. */
4412
+ paymentState?: PaymentState;
4413
+ body?: unknown;
4414
+ receipt?: unknown;
4415
+ /** Registry code on a failed or ambiguous result. */
4416
+ code?: string;
4417
+ retryable?: boolean;
4418
+ nextAction?: NextAction;
4419
+ detail?: string;
4420
+ txDigest?: string;
4421
+ paymentId?: string;
4422
+ challengeId?: string;
4423
+ httpStatus?: number;
4424
+ responseClass?: 'unpaid_ok' | 'rejected' | 'unavailable';
4425
+ };
4426
+
4427
+ /**
4428
+ * SpendAccount PREPARE-only client (non-custodial MCP).
4429
+ *
4430
+ * The remote MCP `pay` tool runs inside the gateway, which holds NO key that can
4431
+ * spend. So this module does not sign or submit: it PREPARES a payment and hands
4432
+ * back an unsigned `spend_account::settle_policy` / `settle_any_recipient` transaction plus everything the client
4433
+ * needs. The client — which holds the delegate key — sponsors, signs locally,
4434
+ * and submits through the same personal-message challenge → local-sign → submit flow the
4435
+ * REST/SDK delegate path uses. Only signatures ever reach the gateway; the
4436
+ * private key is never placed in an HTTP body, a bearer, or any header.
4437
+ *
4438
+ * Flow: 402 Offer → request-binding → package/network SSOT →
4439
+ * resolveGrantTarget(snapshot, offer.targetHash) (pause/revoke gate) → cap/coin
4440
+ * checks → assertLive (fresh authority) → build unsigned kind bytes → return the
4441
+ * signing request. There is deliberately no sponsor call, no decrypt, no
4442
+ * signature, and no forwarded bearer here.
4443
+ *
4444
+ * See docs/design/mcp-non-custodial-signing.md and ADR-0013 §3.
4445
+ */
4446
+
4447
+ type SharedObjectReader = (objectId: string) => Promise<{
4448
+ owner?: unknown;
4449
+ } | null | undefined>;
4450
+ /**
4451
+ * Read/prepare-only session for the non-custodial MCP pay tool. It carries the
4452
+ * immutable grant snapshot and an optional prepare-time live gate — and no key,
4453
+ * by construction. There is no `decryptDelegateSeed` and no `sponsorAuthorization`.
4454
+ */
4455
+ interface SpendAccountPrepareSession {
4456
+ snapshot: GrantSnapshot;
4457
+ /** SpendAccount package id (V2). */
4458
+ packageId: string;
4459
+ /**
4460
+ * Re-assert the grant is still live (not paused/revoked/expired) against fresh
4461
+ * canonical state, invoked immediately before a signing request is handed back.
4462
+ * Throw to abort. Optional; when absent, only the request-time snapshot gates
4463
+ * the prepare (on-chain `spend_account::settle_policy` remains the final backstop for any
4464
+ * spend the client later submits).
4465
+ */
4466
+ assertLive?: () => Promise<void>;
4467
+ }
4468
+ interface SpendAccountPayDeps {
4469
+ fetchImpl?: typeof fetch;
4470
+ /**
4471
+ * Build only-transaction-kind bytes for the canonical guarded debit
4472
+ * (`spend_account::settle_policy` / `settle_any_recipient`).
4473
+ *
4474
+ * The guarded-settle fields ({@link GuardedSettleFields}) are required on the
4475
+ * fresh lineage: every delegate settle consumes the shared exclusion marker.
4476
+ * Dropping them fails closed rather than building an unguarded call that no
4477
+ * longer exists on chain.
4478
+ */
4479
+ buildPayKind?: (input: {
4480
+ delegate: string;
4481
+ coinType: string;
4482
+ poolObjectId: string;
4483
+ grantObjectId: string;
4484
+ policyId: number | string;
4485
+ targetHash: string;
4486
+ amount: string;
4487
+ paymentIdHash: Uint8Array;
4488
+ termsHash: Uint8Array;
4489
+ recipient?: string;
4490
+ accessMode?: 'scoped' | 'open';
4491
+ } & GuardedSettleFields) => Promise<{
4492
+ kindBytes: string;
4493
+ }>;
4494
+ /**
4495
+ * Resolve the per-recipient `RecipientRegistry` bound in the offer's exclusion
4496
+ * directory (guarded offers only). Injected seam for tests; production
4497
+ * leaves it unset and the prepare wires a live gRPC-backed resolver from the
4498
+ * configured `ExclusionDirectory` id when present, else fails closed.
4499
+ */
4500
+ resolveExclusionRegistry?: PayOperationDeps['resolveExclusionRegistry'];
4501
+ /**
4502
+ * Read a shared object's owner so prepare binds the real initial version.
4503
+ * Missing owner fails the prepare; version 1 is not a substitute.
4504
+ */
4505
+ readSharedObject?: SharedObjectReader;
4506
+ /**
4507
+ * Live trace for this prepare. Purely observational: emission records what the
4508
+ * canonical read decisions already returned — an event is written after a check
4509
+ * passes and can never be the thing that lets the next step run.
4510
+ */
4511
+ trace?: SpendAccountPayTrace;
4512
+ }
4513
+ interface SpendAccountPayTrace {
4514
+ sink: TraceSink;
4515
+ traceId: string;
4516
+ requestId: string | null;
4517
+ buyerAccountId: string;
4518
+ connectionId: string;
4519
+ /** HMAC secret for signed cross-request context. Absent disables signing. */
4520
+ secret?: string | null;
4521
+ /** Injected clock, for tests. */
4522
+ now?: () => number;
4523
+ }
4524
+ /** The unsigned payment the client signs locally and submits. */
4525
+ interface SpendAccountSigningRequest {
4526
+ /**
4527
+ * Unsigned `spend_account::settle_policy` / `settle_any_recipient` transaction-kind bytes (base64), sender set to
4528
+ * `delegateAddress`. The client sponsors these for gas, signs with the delegate
4529
+ * key, and submits — the gateway never receives the key.
4530
+ */
4531
+ unsignedKindBytes: string;
4532
+ delegateAddress: string;
4533
+ packageId: string;
4534
+ poolObjectId: string;
4535
+ grantObjectId: string;
4536
+ /** On-chain policy id the pay is bound to. */
4537
+ policyId: number | string;
4538
+ coinType: string;
4539
+ targetHash: string;
4540
+ amount: string;
4541
+ /** Hex (no 0x) of the payment-id hash bound into the transaction. */
4542
+ paymentIdHashHex: string;
4543
+ /** Hex (no 0x) of the terms hash bound into the transaction. */
4544
+ termsHashHex: string;
4545
+ challengeId: string;
4546
+ /** The exact paid request to replay after the client submits. */
4547
+ resource: {
4548
+ url: string;
4549
+ method: string;
4550
+ };
4551
+ dialect: Dialect;
4552
+ /** Recipient the agent requested (offer.payTo). */
4553
+ recipient: string;
4554
+ /** Where the client (holding the key) sponsors and submits. */
4555
+ submit: {
4556
+ sponsorUrl: string;
4557
+ executeUrl: string;
4558
+ moveCallTarget: string;
4559
+ };
4560
+ /**
4561
+ * ISO-8601 timestamp when this prepared operation expires. After this time the
4562
+ * unsigned bytes are no longer valid and the client must re-call pay() for a
4563
+ * fresh prepare. Derived from the offer TTL.
4564
+ */
4565
+ expiresAt: string;
4566
+ /** Restated hard rule for the agent host. */
4567
+ note: string;
4568
+ }
4569
+ interface PreparedPayment {
4570
+ status: 'prepared';
4571
+ paid: false;
4572
+ signingRequest: SpendAccountSigningRequest;
4573
+ }
4574
+ /** Prepared signing request, or a canonical failure (never a spend). */
4575
+ type SpendAccountPrepareResult = PreparedPayment | PayResult;
4576
+ /** Default kind builder (no chain client — pure PTB). */
4577
+ declare function buildSpendAccountPayKind(input: {
4578
+ packageId: string;
4579
+ delegate: string;
4580
+ coinType: string;
4581
+ poolObjectId: string;
4582
+ grantObjectId: string;
4583
+ policyId: number | string;
4584
+ targetHash: string;
4585
+ amount: string;
4586
+ paymentIdHash: Uint8Array;
4587
+ termsHash: Uint8Array;
4588
+ poolInitialSharedVersion?: string;
4589
+ grantInitialSharedVersion?: string;
4590
+ clockInitialSharedVersion?: string;
4591
+ } & GuardedSettleFields): Promise<{
4592
+ kindBytes: string;
4593
+ }>;
4594
+ /**
4595
+ * Refuse blind signing: a client validating a sponsored transaction must be able
4596
+ * to prove the sponsored bytes reconstruct the intended spend_account::settle_policy. Kept
4597
+ * here (and exported) so both the client signer and its tests share one check.
4598
+ */
4599
+ declare function verifySpendAccountPayReconstructs(bytes: string, expected: {
4600
+ kindBytes: string;
4601
+ packageId: string;
4602
+ delegate: string;
4603
+ poolObjectId: string;
4604
+ grantObjectId: string;
4605
+ amount: string;
4606
+ }): void;
4607
+ /**
4608
+ * Prepare a delegate payment WITHOUT signing. Reads the 402 offer, binds it,
4609
+ * gates on the immutable grant snapshot + a fresh authority check, builds the
4610
+ * unsigned transaction, and returns a signing request. The client holding the
4611
+ * delegate key signs locally and submits. This function never decrypts, signs,
4612
+ * sponsors, or submits.
4613
+ *
4614
+ * Uses `resolvePayment` from the SDK pay-operation module for the
4615
+ * shared offer-acquisition + authority-resolution pipeline (steps 1–5 + assertLive
4616
+ * + hash derivation + buildPayKind). This module wraps that with MCP-specific
4617
+ * concerns: trace events, dialect-mode ceiling check, and signing-request
4618
+ * construction.
4619
+ */
4620
+ declare function prepareSpendAccountPayment(args: {
4621
+ url: string;
4622
+ /** The one normalized paid request, replayed byte for byte after signing. */
4623
+ request?: PaidHttpRequest;
4624
+ session: SpendAccountPrepareSession;
4625
+ cfg: McpConfig;
4626
+ deps?: SpendAccountPayDeps;
4627
+ /** Preferred dialect when the 402 advertises both (default mpp). */
4628
+ preferredDialect?: Dialect;
4629
+ }): Promise<SpendAccountPrepareResult>;
4630
+
4631
+ /**
4632
+ * Transport-neutral SuiPay MCP server + tool registry.
4633
+ * Used by stdio (index.ts) and Streamable HTTP (http.ts).
4634
+ * Remote HTTP passes McpAuthContext so tools enforce OAuth scope + shared-pool pay.
4635
+ */
4636
+
4637
+ declare const PACKAGE_NAME = "@cmdoss/suipay-mcp";
4638
+ declare const TOOLS: readonly [{
4639
+ readonly name: "access_context";
4640
+ readonly description: "Inspect profiles, policies, service targets, spend caps, usage, and lifecycle state enforced for this authenticated SuiPay session. Call before choosing a paid service.";
4641
+ readonly inputSchema: {
4642
+ readonly type: "object";
4643
+ readonly properties: {};
4644
+ };
4645
+ }, {
4646
+ readonly name: "pay";
4647
+ readonly description: string;
4648
+ readonly inputSchema: {
4649
+ readonly type: "object";
4650
+ readonly properties: {
4651
+ readonly url: {
4652
+ readonly type: "string";
4653
+ readonly description: "Full gateway resource URL.";
4654
+ };
4655
+ readonly method: {
4656
+ readonly type: "string";
4657
+ readonly enum: readonly ["GET", "POST"];
4658
+ readonly description: "HTTP method of the paid request. Defaults to GET.";
4659
+ };
4660
+ readonly json: {
4661
+ readonly type: "object";
4662
+ readonly description: "JSON request body for a POST. Sent as application/json and bound to the payment.";
4663
+ };
4664
+ readonly file: {
4665
+ readonly type: "string";
4666
+ readonly description: "Absolute path under SUIPAY_MCP_FILE_ROOT (unset disables attach). Stdio POST only; requires fileField. Regular non-empty file whose decoded size fits the paid-body ceiling. Not a URL, FIFO, device, or path under ~/.suipay. Bytes fill json[fileField] as canonical base64.";
4667
+ };
4668
+ readonly fileField: {
4669
+ readonly type: "string";
4670
+ readonly description: "JSON key to set from file (e.g. contentBase64). Required with file. Pattern [A-Za-z][A-Za-z0-9_]{0,63}. Must not already be present on json.";
4671
+ };
4672
+ readonly recipient: {
4673
+ readonly type: "string";
4674
+ readonly description: "Sui address you expect to be paid. The payment is refused, unsigned, if the prepared transaction pays anyone else.";
4675
+ };
4676
+ readonly maxAmount: {
4677
+ readonly type: "string";
4678
+ readonly description: "Atomic ceiling you will spend on this call. The payment is refused, unsigned, if the offer costs more.";
4679
+ };
4680
+ };
4681
+ readonly required: readonly ["url"];
4682
+ };
4683
+ }, {
4684
+ readonly name: "discover";
4685
+ readonly description: "Search SuiPay gateway resources. After login, each row includes name, path, url, catalog price, and whether the current session can cover one call at that price (descriptive only — pay still enforces the grant).";
4686
+ readonly inputSchema: {
4687
+ readonly type: "object";
4688
+ readonly properties: {
4689
+ readonly query: {
4690
+ readonly type: "string";
4691
+ readonly description: "Optional service search terms.";
4692
+ };
4693
+ };
4694
+ };
4695
+ }, {
4696
+ readonly name: "receipts";
4697
+ readonly description: "List SuiPay settlement receipts, optionally filtered by challenge id.";
4698
+ readonly inputSchema: {
4699
+ readonly type: "object";
4700
+ readonly properties: {
4701
+ readonly challengeId: {
4702
+ readonly type: "string";
4703
+ readonly description: "Optional payment challenge id.";
4704
+ };
4705
+ };
4706
+ };
4707
+ }, {
4708
+ readonly name: "suipay_login";
4709
+ readonly description: "Mint or reuse the local delegate key (version-2, mode 0600) and return a clickable console URL immediately so the owner can bind a spend-account grant. Does not wait for the wallet. Default target is Railway suipay-dev; pass target=\"local\" (or start the binary with --local) for the laptop stack. Stdio only; hosted /mcp never holds a spendable key.";
4710
+ readonly inputSchema: {
4711
+ readonly type: "object";
4712
+ readonly properties: {
4713
+ readonly label: {
4714
+ readonly type: "string";
4715
+ readonly description: "Label shown in SuiPay console.";
4716
+ };
4717
+ readonly target: {
4718
+ readonly type: "string";
4719
+ readonly enum: readonly ["dev", "local"];
4720
+ readonly description: "Where to bind the grant. Default is Railway suipay-dev. Pass \"local\" for localhost:3000 / 127.0.0.1:4340.";
4721
+ };
4722
+ readonly gatewayResourceUrl: {
4723
+ readonly type: "string";
4724
+ readonly description: "Gateway resource URL whose 402 defines recipient, asset, and package.";
4725
+ };
4726
+ };
4727
+ };
4728
+ }, {
4729
+ readonly name: "suipay_logout";
4730
+ readonly description: "Remove the local delegate-key credentials file. Missing file is success. Force clears a corrupt file without printing the seed.";
4731
+ readonly inputSchema: {
4732
+ readonly type: "object";
4733
+ readonly properties: {
4734
+ readonly force: {
4735
+ readonly type: "boolean";
4736
+ readonly description: "Remove local credentials even if the file is unreadable.";
4737
+ };
4738
+ };
4739
+ };
4740
+ }];
4741
+ /**
4742
+ * Create a Server with the public SuiPay tool surface registered.
4743
+ *
4744
+ * `trace` is the proxy-resolved run for this HTTP exchange. It is threaded into
4745
+ * tool dependencies so payment code can emit *domain* events, and nothing else:
4746
+ * this wrapper deliberately emits no tool lifecycle of its own, because the
4747
+ * proxy observes the actual JSON-RPC wire and a second source would double-count
4748
+ * every call and disagree on ids.
4749
+ */
4750
+ interface McpServerOptions {
4751
+ /**
4752
+ * How `pay` finds an agent-held delegate key for the authenticated grant.
4753
+ * Defaults to the persisted local key (`resolveAgentHeldSettlement`), which
4754
+ * returns null on any process that does not hold the key the grant names — so
4755
+ * the default is prepare-only everywhere except the agent's own machine.
4756
+ * Injectable for tests; there is no way to make it hand over a key the grant
4757
+ * does not already authorize.
4758
+ */
4759
+ resolveAgentHeld?: AgentHeldResolver;
4760
+ /** Override the exclusion-registry resolver (tests / offline). */
4761
+ resolveExclusionRegistry?: SpendAccountPayDeps['resolveExclusionRegistry'];
4762
+ /**
4763
+ * Wire that created this server. Hosted HTTP never forwards `file` into `pay`.
4764
+ * Stdio is the default so existing tests stay local.
4765
+ */
4766
+ transport?: 'stdio' | 'http';
4767
+ }
4768
+ declare function createServer(cfg: McpConfig, auth?: McpAuthContext, trace?: McpTraceHooks, options?: McpServerOptions): Server;
4769
+
4770
+ /**
4771
+ * Streamable HTTP transport for SuiPay MCP.
4772
+ * Stateless per-request (sessionIdGenerator undefined) — same public tools as stdio.
4773
+ * Auth context is required for remote gateway /mcp (bearer resolved upstream).
4774
+ *
4775
+ * The optional trace runtime turns on live observation. It is a pure wrapper:
4776
+ * `traceMcpHttpRequest` reads clones and returns the transport's own Response,
4777
+ * so passing a runtime cannot change what an MCP client sees.
4778
+ */
4779
+
4780
+ /**
4781
+ * Handle one MCP Streamable HTTP request (initialize, tools/list, tools/call, …).
4782
+ * Creates a fresh transport+server pair per request (stateless mode).
4783
+ */
4784
+ declare function handleSuipayMcpHttpRequest(req: Request, cfg: McpConfig, auth?: McpAuthContext, trace?: McpTraceRuntime | null, options?: McpServerOptions): Promise<Response>;
4785
+
4786
+ export { type AgentHeldResolver as A, buildSpendAccountPayKind as B, type CodeFor as C, type DelegatedKeySigner as D, canonicalMcpRequestId as E, createServer as F, type GetObjectJson as G, handleSuipayMcpHttpRequest as H, inspectMcpEnvelope as I, loadMcpConfig as J, parseMcpTargetFlag as K, prepareSpendAccountPayment as L, type McpConfig as M, type NextAction as N, type Offer as O, type PaidHttpRequest as P, resetAgentHeldProcessLedger as Q, resolveAgentHeldSettlement as R, type SpendAccountSigningRequest as S, TOOLS as T, resolveGrantTarget as U, resolveMcpTarget as V, sameMcpGateway as W, type X402PayProgress as X, traceMcpHttpRequest as Y, verifySpendAccountPayReconstructs as Z, type DelegatedPayerSession as a, type DelegatedPayerConfig as b, type DelegatedPayerDeps as c, type SpendIntent as d, type DelegatedPayResult as e, type DelegationScope as f, type GrantPolicyBinding as g, type PaymentAttemptLedger as h, type DelegatedPayerLog as i, type PreparedSettlementTerms as j, type McpAuthContext as k, type McpTraceHooks as l, type SpendAccountPayDeps as m, createReader as n, type AgentHeldSettlement as o, MCP_TARGET_PRESETS as p, type McpEnvelope as q, type McpEnvelopeEntry as r, type McpServerOptions as s, type McpTarget as t, type McpTraceContext as u, type McpTraceRuntime as v, PACKAGE_NAME as w, type PreparedPayment as x, type SpendAccountPrepareResult as y, type SpendAccountPrepareSession as z };