@haven_ai/sdk 0.0.0-dev.202609031523.fd49e1a

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,2808 @@
1
+ import { PaymentRequirements } from 'x402/types';
2
+
3
+ /**
4
+ * Verifiable payment receipts.
5
+ *
6
+ * A self-contained proof bundle for a settled Haven payment that anyone can
7
+ * verify **independently of Haven**. The anchor is the agent delegate's
8
+ * signature over the on-chain transfer hash: recover the signer and confirm it
9
+ * is the agent's delegate, and you have cryptographic proof the agent authorised
10
+ * exactly this transfer — no need to trust Haven's backend. The on-chain
11
+ * `txHash` is the settlement source of truth (verify on any explorer).
12
+ *
13
+ * This lives in the SDK so agents and users can verify receipts client-side
14
+ * with zero Haven trust.
15
+ */
16
+ declare const RECEIPT_VERSION = "haven-receipt-1";
17
+ interface PaymentReceipt {
18
+ version: typeof RECEIPT_VERSION;
19
+ paymentId: string;
20
+ payment: {
21
+ token: string;
22
+ tokenAddress: string;
23
+ amount: string;
24
+ amountSek: string | null;
25
+ recipient: string;
26
+ safe: string;
27
+ chainId: number;
28
+ settledAt: string | null;
29
+ resourceUrl: string | null;
30
+ };
31
+ /** The agent's cryptographic authorisation — what makes the receipt verifiable. */
32
+ authorization: {
33
+ delegate: string;
34
+ signHash: string;
35
+ signature: string | null;
36
+ };
37
+ onChain: {
38
+ txHash: string | null;
39
+ chainId: number;
40
+ };
41
+ }
42
+ type ReceiptVerification = {
43
+ verified: true;
44
+ recoveredSigner: string;
45
+ } | {
46
+ verified: false;
47
+ reason: 'missing_signature' | 'bad_signature' | 'signer_mismatch';
48
+ recoveredSigner?: string;
49
+ };
50
+ /**
51
+ * Verify a receipt independently: recover the signer from the authorisation and
52
+ * confirm it is the agent's delegate. Pure — `recover` is injectable but
53
+ * defaults to standard ECDSA recovery, so this runs anywhere (no Haven backend).
54
+ */
55
+ declare function verifyPaymentReceipt(receipt: PaymentReceipt, recover?: (hash: string, signature: string) => string): ReceiptVerification;
56
+
57
+ interface HavenClientConfig {
58
+ /** Haven API key (sk_agent_xxx) */
59
+ apiKey: string;
60
+ /** Agent's delegate EOA private key. If provided, the SDK handles signing automatically. */
61
+ delegateKey?: string;
62
+ /** Haven API base URL (default: http://localhost:3001) */
63
+ baseUrl?: string;
64
+ /** Optional wallet identity to send as the x402-wallet header. */
65
+ x402Wallet?: string;
66
+ /** Timeout in ms for individual HTTP requests (default: 30000) */
67
+ requestTimeout?: number;
68
+ /** Timeout (ms) for MERCHANT-facing requests — x402/MPP probes, MCP
69
+ * handshakes, paid retries. Separate from requestTimeout (Haven API):
70
+ * merchants may settle on-chain synchronously, so the default is
71
+ * deliberately generous. #1300. */
72
+ merchantTimeout?: number;
73
+ /** Timeout in ms when polling for tx confirmation (default: 90000) */
74
+ confirmationTimeout?: number;
75
+ /** Polling interval in ms when waiting for confirmation (default: 3000) */
76
+ pollingInterval?: number;
77
+ /**
78
+ * Extra headers to attach to every request to the Haven API.
79
+ *
80
+ * Used by the MCP server to tag requests with `X-Haven-MCP-Tool: <name>`
81
+ * so the backend can record an audit-log entry per tool invocation. Has
82
+ * no effect on outbound merchant requests (x402 / MPP) — those are
83
+ * standard HTTP and never carry Haven-internal headers.
84
+ */
85
+ defaultHeaders?: Record<string, string>;
86
+ /**
87
+ * JSON-RPC RPC URLs keyed by EIP-155 chain ID.
88
+ *
89
+ * When provided for a chain, the SDK waits for ≥1 on-chain confirmation of
90
+ * the AllowanceModule funding tx before retrying the merchant. This prevents
91
+ * the race where the merchant's `balanceOf(delegate)` call runs before the
92
+ * funding block has propagated to the merchant's RPC node.
93
+ *
94
+ * Without this option the SDK proceeds as soon as Haven's backend confirms
95
+ * submission (backward-compatible default). Set it to a reliable RPC
96
+ * endpoint (e.g. Alchemy / Infura) for production usage.
97
+ *
98
+ * @example { 8453: 'https://mainnet.base.org' }
99
+ */
100
+ chainRpcs?: Record<number, string>;
101
+ }
102
+ interface PaymentRequest {
103
+ /** Token symbol: "EURe", "USDC.e", or "xDAI" */
104
+ token: string;
105
+ /** Amount as a decimal string, e.g. "5.00" */
106
+ amount: string;
107
+ /** Recipient Ethereum address (0x...) */
108
+ to: string;
109
+ /**
110
+ * Optional dedupe key (#1207): a retried request with the same key returns
111
+ * the FIRST request's result instead of minting a second transfer or a
112
+ * second approval. Same contract as /machine-payments/send. Max 128 chars.
113
+ */
114
+ idempotencyKey?: string;
115
+ }
116
+ interface SignData {
117
+ /** The hash to sign (keccak256, 0x-prefixed) */
118
+ hash: string;
119
+ /**
120
+ * Delegation rail: 'eip712_userop' (funding redemption) or
121
+ * 'eip712_delegation' (erc7710 settlement child). Absent = legacy
122
+ * AllowanceModule (raw ECDSA over `hash`). The session rail's
123
+ * 'eip191_userop' is retired (#834).
124
+ *
125
+ * When present, `hash` is NOT what gets signed — `typed_data` is (#1138).
126
+ */
127
+ signature_scheme?: 'eip712_userop' | 'eip712_delegation';
128
+ /**
129
+ * EIP-712 payload the account validates, signed VERBATIM (#829). Present
130
+ * whenever `signature_scheme` is — never reconstruct it from `components`.
131
+ */
132
+ typed_data?: {
133
+ domain: Record<string, unknown>;
134
+ types: Record<string, unknown>;
135
+ primaryType: string;
136
+ message: Record<string, unknown>;
137
+ };
138
+ /** Breakdown of values that were hashed — useful for debugging */
139
+ components: {
140
+ safe: string;
141
+ token: string;
142
+ to: string;
143
+ amount: string;
144
+ payment_token: string;
145
+ payment: string;
146
+ nonce: number;
147
+ };
148
+ /** Human-readable signing instructions */
149
+ instructions: string;
150
+ }
151
+ interface PaymentIntent {
152
+ /** Unique payment ID */
153
+ paymentId: string;
154
+ /** Current status */
155
+ status: 'pending_signature';
156
+ /** ISO 8601 expiry timestamp */
157
+ expiresAt: string;
158
+ /** Data needed to sign the payment */
159
+ signData: SignData;
160
+ }
161
+ type PaymentStatus = 'pending_signature' | 'submitted' | 'confirmed' | 'pending_approval' | 'approved' | 'proposed' | 'executed' | 'rejected' | 'expired' | 'failed';
162
+ interface PaymentResult {
163
+ /** Unique payment ID */
164
+ paymentId: string;
165
+ /** Final status */
166
+ status: PaymentStatus;
167
+ /** Token that was sent */
168
+ token: string;
169
+ /** Amount that was sent (human-readable) */
170
+ amount: string;
171
+ /** Recipient address */
172
+ to: string;
173
+ /** On-chain transaction hash (present when confirmed) */
174
+ txHash: string | null;
175
+ /** Error message (present when failed) */
176
+ errorMessage: string | null;
177
+ /** Block explorer URL for the transaction (chain-dependent) */
178
+ explorerUrl: string | null;
179
+ /** ISO 8601 timestamps */
180
+ createdAt: string;
181
+ signedAt: string | null;
182
+ submittedAt: string | null;
183
+ confirmedAt: string | null;
184
+ expiresAt: string;
185
+ /**
186
+ * Platform fee surfaced on the result so it's never silently collected. Dark
187
+ * today (`amount` "0", `applied` false); always present so it's visible the
188
+ * moment fees go live.
189
+ */
190
+ fee?: PaymentFee | null;
191
+ }
192
+ /** The Haven platform fee applied to a payment (#386). */
193
+ interface PaymentFee {
194
+ /** Human-readable fee amount ("0" while the fee module is dark). */
195
+ amount: string;
196
+ /** Token the fee is denominated in. */
197
+ token: string;
198
+ /** Fee as basis points of gross (0 while dark). */
199
+ basisPoints: number;
200
+ /** True when a non-zero fee was actually applied. */
201
+ applied: boolean;
202
+ }
203
+ /** Payment requirements from an HTTP 402 response (x402 protocol). */
204
+ interface X402PaymentRequired {
205
+ x402Version: number;
206
+ resource: {
207
+ url: string;
208
+ description?: string;
209
+ mimeType?: string;
210
+ [key: string]: unknown;
211
+ };
212
+ accepts: X402PaymentOption[];
213
+ error?: string;
214
+ extensions?: Record<string, unknown>;
215
+ }
216
+ /** A single payment option from x402 PaymentRequired. */
217
+ interface X402PaymentOption {
218
+ scheme: string;
219
+ network: string;
220
+ amount: string;
221
+ maxAmountRequired?: string;
222
+ resource?: string;
223
+ description?: string;
224
+ mimeType?: string;
225
+ asset: string;
226
+ payTo: string;
227
+ maxTimeoutSeconds: number;
228
+ /**
229
+ * Merchant-supplied scheme metadata. Two keys are load-bearing for Haven
230
+ * (#1453), both from MetaMask's erc7710 x402 shape:
231
+ *
232
+ * assetTransferMethod — 'erc7710' marks this entry as settleable by
233
+ * redeeming a delegation chain. Absent/other means
234
+ * the standard EIP-3009 authorization.
235
+ * facilitatorAddresses — who may redeem it, pinned into the settlement
236
+ * child's redeemer caveat (#1058).
237
+ *
238
+ * Left as an open record on purpose: the field is the merchant's, and
239
+ * narrowing it to Haven's two keys would silently drop everything else a
240
+ * merchant sends. Read it through `x402AssetTransferMethod` /
241
+ * `x402FacilitatorAddresses` rather than indexing it raw.
242
+ */
243
+ extra?: Record<string, unknown>;
244
+ }
245
+ /** Receipt returned after a successful x402 payment. */
246
+ interface X402Receipt {
247
+ success: boolean;
248
+ paymentId: string;
249
+ txHash: string;
250
+ token: string;
251
+ amount: string;
252
+ to: string;
253
+ resourceUrl: string;
254
+ explorerUrl: string;
255
+ accepted?: X402PaymentOption;
256
+ paymentHeader?: string;
257
+ merchantTo?: string | null;
258
+ payer?: string;
259
+ chainId?: number;
260
+ haven?: {
261
+ paymentId: string;
262
+ fundingTxHash: string;
263
+ fundingExplorerUrl: string;
264
+ };
265
+ merchant?: {
266
+ payTo: string | null;
267
+ settlementTxHash?: string | null;
268
+ settlementExplorerUrl?: string | null;
269
+ };
270
+ x402?: {
271
+ amount: string;
272
+ token: string;
273
+ network: string;
274
+ asset: string;
275
+ resource: string;
276
+ };
277
+ }
278
+ interface X402AuthorizationOptions {
279
+ /** Stable caller-supplied key for this user intent. Prevents duplicate approvals across fresh 402 quotes. */
280
+ idempotencyKey?: string;
281
+ /**
282
+ * #1307: the merchant MCP-tool call context this quote was made against
283
+ * (merchant_url, tool_name, arguments, mcp_transport). Persisted on the
284
+ * intent so `getX402MerchantCallContext` can rehydrate it by payment_id at
285
+ * settle/complete time instead of the caller re-threading it. Optional —
286
+ * omit for a non-MCP-tool x402 merchant (plain HTTP resource).
287
+ */
288
+ mcpCallContext?: X402McpCallContext;
289
+ /**
290
+ * #1348: the agent's delegate address, when the caller already resolved it
291
+ * from `getAgent()` in this same flow — skips `createX402Intent`'s internal
292
+ * agent fetch (one full round trip on every guided purchase). Staleness
293
+ * caveat (#1358 review): the backend derives the funding shape by comparing
294
+ * `payTo` to the CURRENT delegate address, so a value made stale by a
295
+ * delegate rotation mid-flow is not always a clean failure — a pinned-budget
296
+ * agent gets a 403, but an open-budget delegation agent would route to the
297
+ * settlement shape with the stale address. The window is one tool call
298
+ * (previously sub-millisecond, now the merchant-quote duration), never
299
+ * externally suppliable; server-truth hardening is tracked in #1360. Only
300
+ * pass an address fetched in THIS flow; omit to keep the self-contained
301
+ * fetch.
302
+ */
303
+ delegateAddress?: string;
304
+ }
305
+ /**
306
+ * Keyless x402 construct result.
307
+ *
308
+ * Returned by `createX402Intent` — the non-custodial half of an x402 payment.
309
+ * It carries the unsigned funding hash (`signData.hash`, Safe → delegate EOA)
310
+ * plus everything the *edge* needs to build and sign the EIP-3009 merchant
311
+ * header itself. The construct path never signs; both delegate signatures
312
+ * (funding hash + merchant header) happen on the machine that holds the key.
313
+ */
314
+ interface X402Intent {
315
+ /** Haven payment id for the funding transfer. */
316
+ paymentId: string;
317
+ /** Stable key used to create or refresh this x402 funding intent. */
318
+ idempotencyKey: string;
319
+ status: 'pending_signature';
320
+ /** ISO 8601 expiry of the funding intent, if returned. */
321
+ expiresAt?: string;
322
+ /** The unsigned funding hash to sign with the delegate key (Safe → delegate EOA). */
323
+ signData: SignData;
324
+ /** The selected x402 option — the edge needs this to build the EIP-3009 header. */
325
+ accepted: X402PaymentOption;
326
+ /** Resource URL the 402 came from. */
327
+ resourceUrl: string;
328
+ /** Merchant payTo address (the final recipient of the EIP-3009 transfer). */
329
+ merchantTo: string;
330
+ /** Atomic amount the edge signer must authorize in the merchant header. */
331
+ amountAtomic: string;
332
+ /** Token contract the merchant header must pay. */
333
+ asset: string;
334
+ /** x402 network the merchant header must use. */
335
+ network: string;
336
+ /** Haven-authenticated binding over the x402 expected context. */
337
+ expectedAuth: X402ExpectedAuth;
338
+ /**
339
+ * #1690: the payer identity Haven bound into the expected context (v3),
340
+ * relayed VERBATIM to the signer's wire shape. Absent until the backend
341
+ * flips X402_EMIT_PAYER_CONTEXT.
342
+ */
343
+ payerDelegate?: string;
344
+ payerAgentId?: string;
345
+ /**
346
+ * EIP-712 digest of `signData.typed_data`, present on the delegation rail
347
+ * (#1138). The edge signer needs it to reconstruct the v2 expected-context
348
+ * message that Haven signed.
349
+ */
350
+ expectedTypedDataHash?: string;
351
+ /** Delegate EOA the funding transfer tops up (the x402 payer). */
352
+ fundingTo: string;
353
+ }
354
+ interface X402ExpectedContext {
355
+ paymentId: string;
356
+ payloadHash: string;
357
+ resourceUrl: string;
358
+ merchantTo: string;
359
+ amount: string;
360
+ asset: string;
361
+ network: string;
362
+ /** Optional ISO expiry for the funding/quote window. When present, it is bound into the Haven-authenticated context. */
363
+ expiresAt?: string;
364
+ /**
365
+ * EIP-712 digest of the typed data the account actually validates
366
+ * (delegation rail, #1138). Present ⇒ the context is **version 2** and the
367
+ * signer must sign that typed data, never `payloadHash`.
368
+ *
369
+ * On the delegation rail `payloadHash` is the bare ERC-4337 UserOp hash,
370
+ * which is NOT what the account validates — binding it alone would leave the
371
+ * edge signer unable to verify the payload it is being asked to sign. Binding
372
+ * this digest makes Haven's declaration cover the real payload.
373
+ */
374
+ typedDataHash?: string;
375
+ /**
376
+ * The DELEGATE ADDRESS this quote was created for (#1690). Present ⇒ the
377
+ * context is **version 3** and the signer refuses to sign when this is not
378
+ * its own delegate — the guard that turns "quote as agent A, sign as agent
379
+ * B" from an on-chain revert three layers later into a named refusal.
380
+ * Inside the Haven-signed message on purpose: outside it, it is forgeable.
381
+ */
382
+ payerDelegate?: string;
383
+ /** The paying agent's id, for the refusal message's diagnosis (#1690). */
384
+ payerAgentId?: string;
385
+ }
386
+ interface X402ExpectedAuth {
387
+ /**
388
+ * 1 = hash-only (legacy rail). 2 = carries `typedDataHash` (delegation rail,
389
+ * #1138).
390
+ *
391
+ * Deliberately `number`, not a literal union (#1143). This is an **inbound**
392
+ * value: a signer parses a context Haven produced, and a signer older than the
393
+ * backend will legitimately receive a version it does not know. A closed union
394
+ * makes that state unrepresentable, which pushed the rejection down to the
395
+ * schema boundary and produced a raw validation error naming neither the cause
396
+ * nor the fix. The supported set lives in the signer
397
+ * (`SUPPORTED_X402_EXPECTED_VERSIONS`), which fails closed on anything outside
398
+ * it with an actionable message.
399
+ */
400
+ version: number;
401
+ message: string;
402
+ signature: string;
403
+ signer: string;
404
+ }
405
+ /** Serializable HTTP request state for retrying the same x402 merchant request. */
406
+ interface X402RequestSnapshot {
407
+ url: string;
408
+ method: string;
409
+ headers: [string, string][];
410
+ body?: string;
411
+ }
412
+ interface X402McpTransport {
413
+ handshakeRequired: boolean;
414
+ source: 'path' | 'bazaar';
415
+ }
416
+ /**
417
+ * #1307: the merchant MCP-tool call an x402 quote was made against — carried
418
+ * through `createX402Intent`'s options so Haven can persist it for the
419
+ * settle-leg rehydration handoff (`getX402MerchantCallContext`). Convenience
420
+ * metadata for retrying the merchant's OWN JSON-RPC call, never payment
421
+ * authority.
422
+ */
423
+ interface X402McpCallContext {
424
+ merchantUrl: string;
425
+ toolName: string;
426
+ arguments?: Record<string, unknown>;
427
+ mcpTransport?: X402McpTransport;
428
+ }
429
+ /**
430
+ * Response shape of `getX402MerchantCallContext` — the stored merchant call
431
+ * context for a payment_id, rehydrated instead of re-threaded (#1307).
432
+ */
433
+ interface X402MerchantCallContext {
434
+ paymentId: string;
435
+ merchantUrl: string;
436
+ toolName: string;
437
+ arguments: Record<string, unknown>;
438
+ mcpTransport?: X402McpTransport;
439
+ }
440
+ /** Quote parsed from an HTTP 402 response without creating a Haven payment. */
441
+ interface X402Quote {
442
+ rail: 'x402';
443
+ idempotencyKey: string;
444
+ paymentRequired: X402PaymentRequired;
445
+ accepted: X402PaymentOption;
446
+ /**
447
+ * #2054: which selector produced `accepted`, and therefore which entry every
448
+ * amount on this quote describes. `'standard'` is the untagged,
449
+ * EIP-3009-settleable entry; `'erc7710'` means the merchant advertises NO
450
+ * standard entry, so the quote describes its erc7710 one — settleable only
451
+ * from a delegation-rail account, a fact the quote layer cannot see (the
452
+ * rail is a property of the ACCOUNT, not of the 402). This field is
453
+ * descriptive: the actual settlement scheme is still chosen later, with the
454
+ * rail in hand, by `selectX402SettlementScheme`.
455
+ */
456
+ acceptedScheme: 'standard' | 'erc7710';
457
+ request: X402RequestSnapshot;
458
+ mcpTransport?: X402McpTransport;
459
+ resourceUrl: string;
460
+ description: string | null;
461
+ mimeType: string | null;
462
+ amountAtomic: string;
463
+ amount: string;
464
+ token: string;
465
+ /**
466
+ * #1351: decimals for `asset` on `network`, resolved from the SAME
467
+ * address→token binding that produced `token` — the quote's own authority on
468
+ * how many atomic units one human unit is. `null` when the merchant's asset
469
+ * is not a token Haven recognises on that network, in which case `token` is
470
+ * an unverified fallback label and NO human→atomic conversion is safe.
471
+ * Consumers converting a human-denominated figure (a user-intent spending
472
+ * cap) MUST fail closed on `null` rather than assume 6.
473
+ */
474
+ decimals: number | null;
475
+ asset: string;
476
+ network: string;
477
+ chainId: number | null;
478
+ merchantAddress: string;
479
+ maxTimeoutSeconds: number;
480
+ }
481
+ /** State bundle an agent can persist while waiting for manual x402 approval. */
482
+ interface X402ResumeState {
483
+ rail: 'x402';
484
+ paymentId: string;
485
+ idempotencyKey: string;
486
+ paymentRequired: X402PaymentRequired;
487
+ accepted: X402PaymentOption;
488
+ url: string;
489
+ request?: X402RequestSnapshot;
490
+ resourceUrl: string;
491
+ description: string | null;
492
+ amountAtomic: string;
493
+ amount: string;
494
+ token: string;
495
+ asset: string;
496
+ network: string;
497
+ chainId: number | null;
498
+ merchantAddress: string;
499
+ }
500
+ type PaymentResumeState = X402ResumeState;
501
+ interface ResumeAuthorizedX402Input extends X402AuthorizationOptions {
502
+ /** Payment or approval request ID returned by authorizeX402 / haven.fetch. */
503
+ paymentId: string;
504
+ /** Original or freshly parsed x402 requirements for the merchant retry. */
505
+ paymentRequired: X402PaymentRequired;
506
+ }
507
+ interface ResumeX402PaymentInput extends X402AuthorizationOptions {
508
+ /** Payment or approval request ID returned by authorizeX402 / haven.fetch. */
509
+ paymentId: string;
510
+ /** Original paid URL. If paymentRequired is omitted, Haven will call it once to re-read the 402 challenge. */
511
+ url: string;
512
+ /** Original fetch options. Reused for the 402 probe and final merchant retry. */
513
+ init?: RequestInit;
514
+ /** Serializable original request captured by quoteX402() / pending approval errors. */
515
+ request?: X402RequestSnapshot;
516
+ /** Original or freshly parsed x402 requirements. Supplying this avoids an extra merchant 402 probe. */
517
+ paymentRequired?: X402PaymentRequired;
518
+ }
519
+ type MachinePaymentRail = 'x402' | 'mpp_demo' | 'mpp_crypto' | 'stripe_deposit' | 'spt';
520
+ interface HavenAgent {
521
+ id: string;
522
+ name: string;
523
+ status: string;
524
+ safeAddress: string;
525
+ delegateAddress: string;
526
+ chainId: number;
527
+ /**
528
+ * Which on-chain policy primitive gates this agent's spend (#1306): the
529
+ * legacy Safe AllowanceModule (import-only accounts) or the delegation
530
+ * rail's active budget delegations (#1090). Read-only reporting — the
531
+ * on-chain state is the actual gate either way, this only says which
532
+ * mechanism a caller should read/derive from.
533
+ */
534
+ executionRail: 'legacy' | 'delegation';
535
+ }
536
+ interface HavenAllowance {
537
+ id: string;
538
+ tokenAddress: string;
539
+ tokenSymbol: string;
540
+ configuredAmount: string;
541
+ resetPeriodMin: number;
542
+ onchain: {
543
+ amount: string;
544
+ spent: string;
545
+ remaining: string;
546
+ effectiveSpent: string;
547
+ resetTimeMin: number;
548
+ lastResetMin: number;
549
+ nonce: number;
550
+ isResetPending: boolean;
551
+ /**
552
+ * Delegation rail only (#1319, provenance for #1145's fallback): true
553
+ * when `remaining` came from a live on-chain enforcer read, false when
554
+ * the read failed and `remaining` is the fallback full configured
555
+ * budget. Undefined on the legacy AllowanceModule rail, which has no
556
+ * fallback concept. Reporting only — the on-chain policy remains the
557
+ * actual spend gate either way.
558
+ */
559
+ remainingIsFromChain?: boolean;
560
+ };
561
+ }
562
+ interface HavenAllowanceSummary {
563
+ agentId: string;
564
+ safeAddress: string;
565
+ delegateAddress: string;
566
+ chainId: number;
567
+ allowances: HavenAllowance[];
568
+ }
569
+ /**
570
+ * Post-purchase allowance/budget summary attached to a settled x402 payment
571
+ * (#1310). Read-only reporting — the on-chain policy remains the actual
572
+ * spend gate either way, this only says what is left after the purchase.
573
+ *
574
+ * Deliberately the SAME rail-labeled field spelling as #1306's
575
+ * catalog-purchase preflight `allowance` block (never a new spelling),
576
+ * minus the preflight-only `sufficient` field: post-purchase reporting
577
+ * answers "what is left", not "was this purchase covered". Read through the
578
+ * exact same source as {@link HavenAllowanceSummary} / `haven_get_allowances`
579
+ * (`GET /machine-payments/allowances`; delegation-rail values are the #1090
580
+ * `deriveDelegationBudgets`-backed enforcer read, never `agent_allowances`),
581
+ * so this can never disagree with `haven_get_allowances` for the same
582
+ * fixture.
583
+ */
584
+ interface PostPurchaseAllowanceSummary {
585
+ /** Which on-chain policy primitive gates this agent's spend (#1306 labeling). */
586
+ rail: 'legacy' | 'delegation';
587
+ /** Remaining atomic units, read through the same source as {@link HavenAllowance.onchain.remaining}. */
588
+ remaining_atomic: string;
589
+ /** Human-readable remaining, e.g. "4.96 USDC". Omitted when the token's decimals are unknown. */
590
+ remaining_display?: string;
591
+ token_symbol?: string;
592
+ token_address?: string;
593
+ /** Minutes — mirrors {@link HavenAllowance.resetPeriodMin} / the delegation's period. */
594
+ reset_period?: number;
595
+ source: 'allowance_module' | 'active_delegations';
596
+ }
597
+ /**
598
+ * Affirmative spend-readiness for the authenticated agent, derived from the raw
599
+ * agent status plus the remaining spend authority the backend reports per rail
600
+ * (the on-chain AllowanceModule on the legacy rail; the active budget
601
+ * delegation on the delegation rail — #1135):
602
+ * - `ready` — active and at least one token has remaining spend authority.
603
+ * - `needs_approval`— active but no remaining spend authority to auto-spend.
604
+ * The over-budget outcome differs by rail: on the legacy
605
+ * AllowanceModule rail the payment is queued for the wallet
606
+ * owner to approve in Haven; on the delegation rail there is
607
+ * NO approval queue — an over-budget redemption reverts
608
+ * on-chain, so the owner must grant or raise the budget in
609
+ * Haven before the agent can pay.
610
+ * - `revoked` — the agent's status is not `active`; nothing auto-executes.
611
+ *
612
+ * Note: a hard-paused/disabled credential is rejected by the API before this
613
+ * call returns, so it surfaces as an API error rather than `revoked`. `revoked`
614
+ * is reached when the request authenticates but the agent status is non-active.
615
+ *
616
+ * Wallet token balance is intentionally NOT folded in here: the on-chain
617
+ * remaining allowance is the gate Haven enforces, and insufficient wallet
618
+ * funding surfaces at pay time as INSUFFICIENT_FUNDS.
619
+ */
620
+ type HavenAgentReadiness = 'ready' | 'needs_approval' | 'revoked';
621
+ /** Compact, agent-facing per-token spend authority for the bootstrap summary. */
622
+ interface HavenAgentAllowanceSummary {
623
+ tokenSymbol: string;
624
+ /** Live on-chain remaining allowance in atomic units. */
625
+ remainingAtomic: string;
626
+ /** Human-readable remaining, e.g. "4.96 USDC". */
627
+ remainingDisplay: string;
628
+ /** Configured allowance amount (atomic) the owner granted. */
629
+ configuredAmount: string;
630
+ resetPeriodMin: number;
631
+ isResetPending: boolean;
632
+ }
633
+ /**
634
+ * One-shot "am I ready?" bootstrap: identity + live spend authority + a
635
+ * readiness signal, so an agent can answer "who am I and can I pay right now"
636
+ * from a single call at session start. Superset of {@link HavenAgent}.
637
+ */
638
+ interface HavenAgentSummary extends HavenAgent {
639
+ /**
640
+ * @deprecated Use {@link HavenAgentSummary.spend_authority_readiness} —
641
+ * same value, honest name. This signal covers hosted identity + on-chain
642
+ * spend authority ONLY; it says nothing about the LOCAL signer, which the
643
+ * hosted side cannot see (verify via a signer tool or connect --doctor).
644
+ * Kept as an alias; removal earliest after the next release train (#1590).
645
+ */
646
+ readiness: HavenAgentReadiness;
647
+ /**
648
+ * Spend-authority readiness: hosted identity + on-chain remaining spend
649
+ * authority. Deliberately named for what it covers — the LOCAL signer's
650
+ * availability is NOT included and must be verified separately (a signer
651
+ * tool call, or the connector's `--doctor`, whose exact command this build
652
+ * renders from `HAVEN_CONNECTOR_CHANNEL` — see `connector-channel.ts`).
653
+ */
654
+ spend_authority_readiness: HavenAgentReadiness;
655
+ allowances: HavenAgentAllowanceSummary[];
656
+ }
657
+ interface HavenPaymentReceipt {
658
+ id: string;
659
+ paymentId: string;
660
+ paymentIntentId?: string | null;
661
+ approvalRequestId?: string | null;
662
+ rail: string;
663
+ proofStatus: string;
664
+ txHash: string;
665
+ chainId: number;
666
+ resourceUrl: string;
667
+ merchantAddress: string | null;
668
+ payerAddress: string;
669
+ settlementAddress: string;
670
+ tokenSymbol: string;
671
+ tokenAddress: string;
672
+ amountRaw: string;
673
+ amount: string;
674
+ challengeId: string | null;
675
+ idempotencyKey: string | null;
676
+ challengePayload?: Record<string, unknown> | null;
677
+ selectedPayment?: Record<string, unknown> | null;
678
+ paymentProofHeaderName: string | null;
679
+ protocolReceiptHeaderName: string | null;
680
+ protocolReceiptPayload?: Record<string, unknown> | null;
681
+ merchantStatus: number | null;
682
+ confirmedAt: string | null;
683
+ createdAt: string;
684
+ updatedAt: string;
685
+ }
686
+ /**
687
+ * How long this SDK waits for an on-chain confirmation before it stops
688
+ * waiting (#1756).
689
+ *
690
+ * Lives here rather than in `client.ts` so the payment-confirmation poller
691
+ * and the delegate sweep share ONE number instead of forking it. The SDK's
692
+ * other chain waits are already bounded (`waitForFundingTx` at 30 s), so a
693
+ * fourth independently chosen literal is exactly the drift this constant
694
+ * exists to prevent.
695
+ */
696
+ declare const DEFAULT_CONFIRMATION_TIMEOUT_MS = 90000;
697
+ /**
698
+ * Whether a sweep transfer was observed to confirm (#1756).
699
+ *
700
+ * The distinction is the point: `unconfirmed` means the transfer was
701
+ * BROADCAST and may still land, which is neither success nor failure. It must
702
+ * never be collapsed into either — reporting a still-pending transaction as
703
+ * done, or as failed, are the same defect in opposite directions.
704
+ */
705
+ type SweepConfirmation =
706
+ /** A receipt was observed. The funds are in the Safe. */
707
+ 'confirmed'
708
+ /**
709
+ * Broadcast, but no receipt within `DEFAULT_CONFIRMATION_TIMEOUT_MS` (or the
710
+ * node returned no receipt). The transaction is still in the mempool and may
711
+ * mine at any time. `txHash` is the broadcast hash — check it on the
712
+ * explorer before re-running the sweep, and expect a re-run to find nothing
713
+ * stranded if it has since landed.
714
+ */
715
+ | 'unconfirmed';
716
+ /** One transferred asset in a delegate sweep. */
717
+ interface SweepEntry {
718
+ /** 'USDC' or 'ETH' */
719
+ asset: string;
720
+ /** Human-readable amount swept (e.g. "0.12") */
721
+ amount: string;
722
+ /** Atomic amount swept */
723
+ amountAtomic: string;
724
+ /**
725
+ * Transaction hash of the sweep transfer.
726
+ *
727
+ * The RECEIPT hash when `confirmation` is `confirmed`; the BROADCAST hash
728
+ * when it is `unconfirmed` — which is the whole reason the sweep returns
729
+ * instead of throwing on a deadline, since this hash is the only thing that
730
+ * lets a user recover the transfer by hand (#1756).
731
+ */
732
+ txHash: string;
733
+ /** Block explorer URL for the tx */
734
+ explorerUrl: string;
735
+ /**
736
+ * Did this transfer confirm on-chain within the deadline? (#1756)
737
+ *
738
+ * `unconfirmed` entries have MOVED NOTHING YET and may still move. Do not
739
+ * report a sweep as complete without checking this on every entry.
740
+ */
741
+ confirmation: SweepConfirmation;
742
+ }
743
+ /** Result of a `sweepDelegate()` call. */
744
+ interface SweepResult {
745
+ /** Address funds were swept FROM */
746
+ fromAddress: string;
747
+ /** Address funds were swept TO (always the originating Safe) */
748
+ toAddress: string;
749
+ /** Chain the sweep occurred on */
750
+ chainId: number;
751
+ /** One entry per transferred asset. Empty when nothing was stranded. */
752
+ transfers: SweepEntry[];
753
+ /**
754
+ * True when ANY entry is `unconfirmed` — i.e. the sweep broadcast something
755
+ * it could not confirm within the deadline (#1756).
756
+ *
757
+ * Derived from `transfers`, and present anyway because the consumer most
758
+ * likely to misread this result is an LLM reading the JSON of the
759
+ * `haven_sweep_delegate` tool, which will otherwise see a populated
760
+ * `transfers` array and report the money as recovered.
761
+ */
762
+ unconfirmed: boolean;
763
+ }
764
+ type PaymentStateKind = 'payment_intent' | 'approval_request';
765
+ interface AgentPaymentEnumSchema {
766
+ type: 'string';
767
+ enum: readonly string[];
768
+ description: string;
769
+ 'x-enumDescriptions': Record<string, string>;
770
+ }
771
+ declare const AgentPaymentPhase: {
772
+ /** The agent must sign and submit the prepared payment before Haven can relay it. */
773
+ readonly AgentSignatureRequired: "agent_signature_required";
774
+ /** Haven has received the signed payment and the agent should poll for confirmation. */
775
+ readonly PaymentSubmitted: "payment_submitted";
776
+ /** The direct payment is confirmed; the agent does not need to do more for this payment id. */
777
+ readonly PaymentConfirmed: "payment_confirmed";
778
+ /**
779
+ * #2115: RETIRED wire value — no live rail produces it. It described the
780
+ * Safe rail's approval queue, which no longer exists. Kept so a stored value
781
+ * still typechecks; see `AgentPaymentPhaseDescriptions` below for the
782
+ * agent-visible wording, which this comment used to contradict.
783
+ */
784
+ readonly UserApprovalRequired: "user_approval_required";
785
+ /** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user. */
786
+ readonly UserExecutionRequired: "user_execution_required";
787
+ /** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user. */
788
+ readonly WaitingForAdditionalApprovals: "waiting_for_additional_approvals";
789
+ /** The Haven funding leg was sent; the agent can continue the merchant/protocol leg. */
790
+ readonly FundingSent: "funding_sent";
791
+ /** The payment was rejected and cannot proceed; the agent should stop and tell the user. */
792
+ readonly Rejected: "rejected";
793
+ /** The payment expired before completion. */
794
+ readonly Expired: "expired";
795
+ /** Haven could not complete the payment; the agent should stop and surface the failure. */
796
+ readonly Failed: "failed";
797
+ /**
798
+ * Pre-flight check determined the delegate's existing balance plus the
799
+ * remaining on-chain budget cannot cover the requested amount, so no
800
+ * payment intent was created. The account must be funded or the agent's
801
+ * budget raised before retrying — #2115: the old wording contrasted this
802
+ * with `UserApprovalRequired` as if that were a live alternative, and named
803
+ * the retired rail's Safe and per-token allowance as the fix.
804
+ */
805
+ readonly InsufficientFunds: "insufficient_funds";
806
+ /**
807
+ * Haven's funding leg (account → delegate, the #946 EIP-3009 bridge)
808
+ * confirmed on-chain, but the merchant rejected the x402 retry. The delegate
809
+ * wallet may hold stranded USDC that was never settled to the merchant. The
810
+ * agent should stop, tell the user, and wait for the sweep flow to reclaim
811
+ * the funds.
812
+ */
813
+ readonly FundedButUnsettled: "funded_but_unsettled";
814
+ };
815
+ type AgentPaymentPhase = (typeof AgentPaymentPhase)[keyof typeof AgentPaymentPhase];
816
+ declare const AgentPaymentNextAction: {
817
+ /** Sign with the delegate key and submit the payment to Haven. */
818
+ readonly SignAndSubmitPayment: "sign_and_submit_payment";
819
+ /** Poll getPaymentStatus later using this payment id. */
820
+ readonly CheckStatusLater: "check_status_later";
821
+ /** No further agent action is required for this payment id. */
822
+ readonly None: "none";
823
+ /**
824
+ * #2115: RETIRED wire value — no live rail produces it and nothing maps to
825
+ * it. Stop and tell the user rather than polling; no approval will arrive.
826
+ */
827
+ readonly WaitForUserApproval: "wait_for_user_approval";
828
+ /** #2115: RETIRED wire value — no live rail produces it. Stop and tell the user rather than polling. */
829
+ readonly WaitForUserToCompletePayment: "wait_for_user_to_complete_payment";
830
+ /** Resume this payment id and retry the original x402 request with the merchant payment header. */
831
+ readonly RetryOriginalX402Request: "retry_original_x402_request";
832
+ /** Stop retrying this payment and tell the user what happened. */
833
+ readonly StopAndTellUser: "stop_and_tell_user";
834
+ /** Ask again only if the user still wants the payment after expiry. */
835
+ readonly RequestAgainIfUserStillWantsIt: "request_again_if_user_still_wants_it";
836
+ /** #1307: retry the SAME tool call, supplying the explicit context fields the server could not rehydrate. */
837
+ readonly RetryWithExplicitContext: "retry_with_explicit_context";
838
+ /**
839
+ * The x402 funding/quote window expired. Re-quote the same logical merchant
840
+ * operation with the same idempotency key to stay double-charge-safe.
841
+ */
842
+ readonly PaymentWindowExpired: "payment_window_expired";
843
+ /**
844
+ * Stop and tell the user that the originating Safe needs to be funded or
845
+ * the agent's per-token allowance needs to be raised before the payment
846
+ * can succeed. A user approval will not fix this state on its own.
847
+ */
848
+ readonly FundSafeOrRaiseAllowance: "fund_safe_or_raise_allowance";
849
+ /**
850
+ * The delegate wallet may hold funds that were sent from the Safe but never
851
+ * settled to the merchant. The wallet owner should initiate a sweep to
852
+ * return those funds to the originating Safe.
853
+ */
854
+ readonly SweepStrandedFunds: "sweep_stranded_funds";
855
+ };
856
+ type AgentPaymentNextAction = (typeof AgentPaymentNextAction)[keyof typeof AgentPaymentNextAction];
857
+ declare const AgentPaymentFailureCode: {
858
+ /** A merchant-authoritative x402 price exceeds the caller's pre-funding max_amount cap. */
859
+ readonly PriceExceedsMax: "PRICE_EXCEEDS_MAX";
860
+ /** The x402 funding/quote window expired before the signer or hosted settle step could finish. */
861
+ readonly PaymentWindowExpired: "PAYMENT_WINDOW_EXPIRED";
862
+ /** The Haven funding leg succeeded, but the merchant rejected the paid retry. */
863
+ readonly MerchantRejectedAfterFunding: "MERCHANT_REJECTED_AFTER_FUNDING";
864
+ /** #1300 review: funding is on-chain but the merchant never ANSWERED the
865
+ * paid retry within the timeout. NOT proof of rejection — the merchant
866
+ * holds a valid EIP-3009 authorization and may still settle late, so the
867
+ * guidance is verify-then-sweep, never blind sweep. */
868
+ readonly MerchantUnresponsiveAfterFunding: "MERCHANT_UNRESPONSIVE_AFTER_FUNDING";
869
+ /**
870
+ * #1307: the caller omitted merchant_url/tool_name (asking Haven to
871
+ * rehydrate the stored MCP merchant-call context by payment_id), but no
872
+ * usable context was stored for this intent — either it was never an
873
+ * MCP-tool quote, or the stored context is incomplete. The fallback is
874
+ * mechanical: re-send merchant_url, tool_name, arguments, and
875
+ * mcp_transport explicitly (the version-skew path).
876
+ */
877
+ readonly MerchantCallContextUnavailable: "MERCHANT_CALL_CONTEXT_UNAVAILABLE";
878
+ /**
879
+ * #1351: the caller supplied BOTH the atomic `max_amount` and the
880
+ * human-denominated `max_amount_human` cap for one purchase. Haven refuses
881
+ * to guess which the user meant — the two differ by a factor of 10^decimals,
882
+ * so picking wrong is exactly the silent-overspend this cap exists to
883
+ * prevent. Rejected before any merchant probe, funding intent, or signature.
884
+ */
885
+ readonly AmbiguousMaxAmount: "AMBIGUOUS_MAX_AMOUNT";
886
+ /**
887
+ * #1351: a human-denominated cap was supplied, but it cannot be converted to
888
+ * atomic units against THIS quote — either the quote's asset has no known
889
+ * decimals on its network, or the cap carries more fraction digits than the
890
+ * asset can represent (truncating it would silently change the user's cap).
891
+ * The fallback is the exact atomic `max_amount`.
892
+ */
893
+ readonly MaxAmountUnconvertible: "MAX_AMOUNT_UNCONVERTIBLE";
894
+ };
895
+ type AgentPaymentFailureCode = (typeof AgentPaymentFailureCode)[keyof typeof AgentPaymentFailureCode];
896
+ /**
897
+ * Stable rail identifier carried on Haven agent payment responses and resume
898
+ * state.
899
+ *
900
+ * Two layers of vocabulary share this enum because both reach the wire:
901
+ *
902
+ * - **Categorical rails** identify the rail family and are used as the
903
+ * `PaymentResumeState` discriminator: `direct`, `x402` (`mpp` remains a
904
+ * valid categorical VALUE on historical status reads, but #1328 retired
905
+ * the `MppResumeState` variant that used to carry it — the mpp_demo
906
+ * client resume flow no longer exists).
907
+ * - **Granular rails** identify the specific protocol the backend persists
908
+ * and returns on response bodies: `mpp_demo`, `mpp_crypto`,
909
+ * `stripe_deposit`, `spt`. `x402` doubles as both categorical and
910
+ * granular.
911
+ *
912
+ * Consumers reading the top-level `rail` field on a payment status response
913
+ * should treat any `mpp*` value as the MPP family — this still applies to
914
+ * historical `mpp_demo` rows, which remain readable.
915
+ */
916
+ declare const AgentPaymentRail: {
917
+ /** Standard Haven payment from the user's Safe through an approved delegate allowance. */
918
+ readonly Direct: "direct";
919
+ /** x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg. */
920
+ readonly X402: "x402";
921
+ /** Machine Payment Protocol family — categorical value used as a resume-state discriminator. */
922
+ readonly Mpp: "mpp";
923
+ /** Haven internal MPP demo rail. Not for production traffic. */
924
+ readonly MppDemo: "mpp_demo";
925
+ /** Crypto-settled MPP rail. */
926
+ readonly MppCrypto: "mpp_crypto";
927
+ /** Stripe-deposit-backed MPP rail. */
928
+ readonly StripeDeposit: "stripe_deposit";
929
+ /** Stripe Payment Token MPP rail. */
930
+ readonly Spt: "spt";
931
+ };
932
+ type AgentPaymentRail = (typeof AgentPaymentRail)[keyof typeof AgentPaymentRail];
933
+ type PaymentPhase = AgentPaymentPhase;
934
+ type PaymentNextAction = AgentPaymentNextAction;
935
+ declare const AGENT_PAYMENT_PHASE_VALUES: ("rejected" | "expired" | "failed" | "agent_signature_required" | "payment_submitted" | "payment_confirmed" | "user_approval_required" | "user_execution_required" | "waiting_for_additional_approvals" | "funding_sent" | "insufficient_funds" | "funded_but_unsettled")[];
936
+ declare const AGENT_PAYMENT_NEXT_ACTION_VALUES: ("sign_and_submit_payment" | "check_status_later" | "none" | "wait_for_user_approval" | "wait_for_user_to_complete_payment" | "retry_original_x402_request" | "stop_and_tell_user" | "request_again_if_user_still_wants_it" | "retry_with_explicit_context" | "payment_window_expired" | "fund_safe_or_raise_allowance" | "sweep_stranded_funds")[];
937
+ declare const AGENT_PAYMENT_FAILURE_CODE_VALUES: ("PRICE_EXCEEDS_MAX" | "PAYMENT_WINDOW_EXPIRED" | "MERCHANT_REJECTED_AFTER_FUNDING" | "MERCHANT_UNRESPONSIVE_AFTER_FUNDING" | "MERCHANT_CALL_CONTEXT_UNAVAILABLE" | "AMBIGUOUS_MAX_AMOUNT" | "MAX_AMOUNT_UNCONVERTIBLE")[];
938
+ declare const AGENT_PAYMENT_RAIL_VALUES: ("x402" | "mpp_demo" | "mpp_crypto" | "stripe_deposit" | "spt" | "direct" | "mpp")[];
939
+ declare const AgentPaymentPhaseDescriptions: Record<AgentPaymentPhase, string>;
940
+ declare const AgentPaymentNextActionDescriptions: Record<AgentPaymentNextAction, string>;
941
+ declare const AgentPaymentFailureCodeDescriptions: Record<AgentPaymentFailureCode, string>;
942
+ /**
943
+ * #1308: machine-readable warning codes carried in the `warnings` array on
944
+ * x402 MCP tool responses. Warnings are ADVISORY — they never replace a
945
+ * refusal, and existing failure codes stay authoritative for errors. The
946
+ * legacy `cap_warning` string field is kept for compatibility; the structured
947
+ * entry carries the same message under MISSING_MAX_AMOUNT.
948
+ */
949
+ declare const AgentPaymentWarningCode: {
950
+ /** No max_amount cap was supplied — the live quoted price was accepted as-is. */
951
+ readonly MissingMaxAmount: "MISSING_MAX_AMOUNT";
952
+ /** The signing window closes soon; sign promptly or re-quote with the same idempotency key. */
953
+ readonly QuoteExpiresSoon: "QUOTE_EXPIRES_SOON";
954
+ /** The merchant URL was resolved via discovery — pass the RESOLVED url forward. */
955
+ readonly MerchantUrlDiscovered: "MERCHANT_URL_DISCOVERED";
956
+ /**
957
+ * #1306: the catalog's last-verified price_atomic differs from the LIVE
958
+ * merchant quote for a guided catalog purchase. The catalog price is only
959
+ * ever indicative; the live quote in the same response is authoritative.
960
+ */
961
+ readonly CatalogPriceDiffers: "CATALOG_PRICE_DIFFERS";
962
+ /**
963
+ * #1306: the rail-aware allowance/budget pre-check could not be read (RPC
964
+ * failure, etc). `sufficient` is reported as null rather than a fabricated
965
+ * true/false — the on-chain policy remains the actual gate either way.
966
+ */
967
+ readonly AllowanceCheckUnavailable: "ALLOWANCE_CHECK_UNAVAILABLE";
968
+ /**
969
+ * #1319: the delegation-rail read itself SUCCEEDED, but the remaining
970
+ * figure it returned is the #1145 fallback (the full configured budget)
971
+ * rather than a live ERC20PeriodTransferEnforcer read — `sufficient` is a
972
+ * real true/false, just computed from an optimistic number. Distinct from
973
+ * {@link AgentPaymentWarningCode.AllowanceCheckUnavailable}, which fires
974
+ * when the read failed outright and `sufficient` degrades to null. The
975
+ * on-chain policy re-checks at redemption either way; this only says the
976
+ * guidance shown here may be optimistic.
977
+ */
978
+ readonly AllowanceReadOptimistic: "ALLOWANCE_READ_OPTIMISTIC";
979
+ };
980
+ type AgentPaymentWarningCode = (typeof AgentPaymentWarningCode)[keyof typeof AgentPaymentWarningCode];
981
+ interface AgentPaymentWarning {
982
+ code: AgentPaymentWarningCode;
983
+ message: string;
984
+ }
985
+ /**
986
+ * #1308: the structured next-step contract on x402 MCP tool responses. It
987
+ * EXTENDS the existing taxonomy — `next_action` values come from
988
+ * AgentPaymentNextAction, never a parallel vocabulary. `next_arguments`
989
+ * carries the small, literally-usable arguments; bulky pass-through fields
990
+ * (payment_required) are named in `reason` and taken from the SAME response.
991
+ */
992
+ interface AgentNextStep {
993
+ next_action: AgentPaymentNextAction;
994
+ /** Fully-qualified tool name for the next call, when one exists. */
995
+ next_tool?: string;
996
+ /** Small literal arguments for next_tool. Bulky fields are referenced by reason. */
997
+ next_arguments?: Record<string, unknown>;
998
+ /** False when the agent should stop and involve the user before continuing. */
999
+ safe_to_continue: boolean;
1000
+ reason: string;
1001
+ }
1002
+ /**
1003
+ * #1349: compact, Haven-generated reporting evidence for a completed x402
1004
+ * merchant purchase. `status`, money fields, merchant endpoint/address, and
1005
+ * funding transaction come from Haven payment state; `product` and
1006
+ * `invoice_id` are optional merchant-supplied display metadata. The raw
1007
+ * merchant result remains separate evidence and MUST NOT be used to infer
1008
+ * settlement status.
1009
+ */
1010
+ interface AgentPurchaseSummary {
1011
+ /** Set only after Haven has completed the funding and merchant-settlement flow. */
1012
+ status: 'settled';
1013
+ product: string | null;
1014
+ amount: string | null;
1015
+ amount_atomic: string | null;
1016
+ asset: string | null;
1017
+ network: string | null;
1018
+ merchant: {
1019
+ address: string | null;
1020
+ resource_url: string | null;
1021
+ };
1022
+ /** Merchant-supplied identifier, or null when the merchant did not supply one. */
1023
+ invoice_id: string | null;
1024
+ funding_tx_hash: string | null;
1025
+ /** Optional merchant receipt reference parsed from PAYMENT-RESPONSE; not Haven settlement proof. */
1026
+ settlement_tx_hash: string | null;
1027
+ /** Same read-only allowance block returned at the top level, or null when unavailable. */
1028
+ allowance: PostPurchaseAllowanceSummary | null;
1029
+ }
1030
+ /** #1308: compact reporting summary — what the agent tells the user. */
1031
+ interface AgentPaymentSummary {
1032
+ payment_id: string;
1033
+ status: string;
1034
+ amount?: string;
1035
+ amount_atomic?: string;
1036
+ token?: string;
1037
+ network?: string;
1038
+ expires_at?: string;
1039
+ product?: string;
1040
+ /**
1041
+ * Default reporting contract for a successful `haven_settle_mcp_tool` call.
1042
+ * The merchant's raw `result` remains available separately as advanced
1043
+ * evidence; do not parse it to determine whether a payment settled.
1044
+ */
1045
+ purchase_summary?: AgentPurchaseSummary;
1046
+ }
1047
+ declare const AgentPaymentRailDescriptions: Record<AgentPaymentRail, string>;
1048
+ declare const AgentPaymentPhaseSchema: AgentPaymentEnumSchema;
1049
+ declare const AgentPaymentNextActionSchema: AgentPaymentEnumSchema;
1050
+ declare const AgentPaymentFailureCodeSchema: AgentPaymentEnumSchema;
1051
+ declare const AgentPaymentRailSchema: AgentPaymentEnumSchema;
1052
+ interface PaymentStatusResult {
1053
+ paymentId: string;
1054
+ kind: PaymentStateKind;
1055
+ rail: string;
1056
+ status: PaymentStatus | string;
1057
+ phase: PaymentPhase;
1058
+ nextAction: PaymentNextAction;
1059
+ amount: string;
1060
+ token: string;
1061
+ resourceUrl: string | null;
1062
+ merchantAddress: string | null;
1063
+ /** Delegate EOA captured on the payment intent when it was created. */
1064
+ payerAddress?: string | null;
1065
+ txHash: string | null;
1066
+ expiresAt: string;
1067
+ chainId: number;
1068
+ message: string;
1069
+ /** Platform fee surfaced so it's never silently collected (#386). */
1070
+ fee?: PaymentFee | null;
1071
+ amountAtomic?: string | null;
1072
+ asset?: string | null;
1073
+ network?: string | null;
1074
+ description?: string | null;
1075
+ idempotencyKey?: string | null;
1076
+ x402?: {
1077
+ amountAtomic: string | null;
1078
+ asset: string | null;
1079
+ network: string | null;
1080
+ resourceUrl: string | null;
1081
+ merchantAddress: string | null;
1082
+ description: string | null;
1083
+ idempotencyKey: string | null;
1084
+ };
1085
+ mpp?: {
1086
+ amountAtomic: string | null;
1087
+ asset: string | null;
1088
+ network: string | null;
1089
+ resourceUrl: string | null;
1090
+ merchantAddress: string | null;
1091
+ description: string | null;
1092
+ idempotencyKey: string | null;
1093
+ challengeId: string | null;
1094
+ };
1095
+ }
1096
+ /**
1097
+ * Result of an erc7710 direct settlement (#1454).
1098
+ *
1099
+ * Deliberately NOT an `X402Receipt`. A 3009 receipt describes a completed
1100
+ * two-leg payment — funding tx included — whereas here nothing has settled yet
1101
+ * when this returns: the merchant redeems the delegation chain when the caller
1102
+ * retries with the header. Reusing the receipt type would let a caller read
1103
+ * `txHash` as "paid" on a payment that has not moved a cent.
1104
+ */
1105
+ interface X402Erc7710Settlement {
1106
+ paymentId: string;
1107
+ /**
1108
+ * Pass verbatim as the `PAYMENT-SIGNATURE` header on the merchant retry —
1109
+ * that name ALONE. erc7710 is always x402 v2, and this header carries the
1110
+ * delegation chain, so also sending the legacy `X-PAYMENT` overflows the
1111
+ * merchant's header limit (HTTP 431, #2341).
1112
+ */
1113
+ paymentHeader: string;
1114
+ /** The merchant address the child delegation is pinned to. */
1115
+ merchantPayTo: string;
1116
+ amountAtomic: string;
1117
+ asset: string;
1118
+ network: string;
1119
+ /** Facilitators the child is redeemable by, when the merchant advertised any. */
1120
+ facilitatorAddresses: string[] | null;
1121
+ }
1122
+ /** @internal */
1123
+ /** One payable service in Haven's merchant catalog (epic #1717). */
1124
+ interface HavenCatalogEntry {
1125
+ id: string;
1126
+ name: string;
1127
+ description: string;
1128
+ category: string;
1129
+ resourceUrl: string;
1130
+ rail: 'x402' | 'mpp';
1131
+ protocol: 'http' | 'mcp';
1132
+ toolName: string | null;
1133
+ toolArguments: Record<string, unknown> | null;
1134
+ priceDisplay: string | null;
1135
+ priceAtomic: string | null;
1136
+ asset: string | null;
1137
+ network: string | null;
1138
+ status: 'active' | 'degraded' | 'delisted';
1139
+ verifiedAt: string | null;
1140
+ /**
1141
+ * Where the entry came from. `operator` = curated in migrations/scripts
1142
+ * (the operator vouches; no verification badges). `ingestion` = submitted
1143
+ * through the Verified Payable Directory and passed domain-ownership proof
1144
+ * plus the read-only quote probe.
1145
+ */
1146
+ source: 'operator' | 'ingestion';
1147
+ /** True only for `ingestion` entries. See the epic's trust claim (never merchant honesty or quality). */
1148
+ domainVerified: boolean;
1149
+ verifiedPayable: boolean;
1150
+ }
1151
+ /** @internal */
1152
+ /** Wire shape of POST /catalog/submit (#1717, #1716). */
1153
+ interface CatalogSubmissionAccepted {
1154
+ id: string;
1155
+ verify_token: string;
1156
+ status: 'submitted' | 'ownership_verified' | 'verified_payable';
1157
+ }
1158
+ /** @internal Client-facing submission handle. */
1159
+ interface HavenCatalogSubmission {
1160
+ id: string;
1161
+ verifyToken: string;
1162
+ status: 'submitted' | 'ownership_verified' | 'verified_payable';
1163
+ }
1164
+ declare class HavenError extends Error {
1165
+ readonly code: string;
1166
+ readonly statusCode?: number | undefined;
1167
+ readonly paymentId?: string | undefined;
1168
+ constructor(message: string, code: string, statusCode?: number | undefined, paymentId?: string | undefined);
1169
+ }
1170
+ declare class HavenApiError extends HavenError {
1171
+ readonly body?: unknown | undefined;
1172
+ constructor(message: string, statusCode: number, body?: unknown | undefined, paymentId?: string);
1173
+ }
1174
+ /**
1175
+ * #1300: quoteX402 hit a URL that answered something other than 402 — the
1176
+ * typed form of "this is not the x402 endpoint". Exists so consumers (the
1177
+ * hosted MCP's #1271 discovery trigger) can key on a class instead of
1178
+ * message text.
1179
+ */
1180
+ /**
1181
+ * #1300: a merchant-facing fetch hit the client-side merchantTimeout. Typed
1182
+ * so consumers can distinguish "merchant never answered" from a real HTTP
1183
+ * error response — the funded-retry path routes this to verify-then-sweep
1184
+ * guidance instead of a bare 504.
1185
+ */
1186
+ declare class MerchantTimeoutError extends HavenApiError {
1187
+ readonly merchantErrorCode: "merchant_timeout";
1188
+ constructor(message: string);
1189
+ }
1190
+ declare class X402UnexpectedStatusError extends HavenApiError {
1191
+ readonly x402ErrorCode: "unexpected_non_402_status";
1192
+ constructor(message: string, statusCode: number);
1193
+ }
1194
+ /**
1195
+ * #1521: the idempotency key resolved to a payment that has already settled,
1196
+ * and the delegate can no longer fund a fresh authorization for it.
1197
+ *
1198
+ * This is the typed form of "you already bought this". It exists because the
1199
+ * alternative was indefensible: the SDK used to mint a new EIP-3009
1200
+ * authorization against the spent delegate and hand it back paired with the
1201
+ * ORIGINAL payment's `txHash`, so the caller learned what had happened only
1202
+ * from a merchant-side balance error that reads identically to a broken
1203
+ * payment rail.
1204
+ *
1205
+ * `receipt` is the ORIGINAL payment — a real receipt for real settled funds,
1206
+ * deliberately carrying no `paymentHeader`, because any header minted here
1207
+ * would be exactly the unfundable artifact this error replaces.
1208
+ */
1209
+ declare class X402AlreadySettledError extends HavenApiError {
1210
+ readonly receipt: X402Receipt;
1211
+ /**
1212
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1213
+ * authorization, so this payment demonstrably completed.
1214
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1215
+ * could not be established either way. Same refusal, weaker claim; say
1216
+ * which, rather than assert what was not checked.
1217
+ */
1218
+ readonly basis: 'settled' | 'unverifiable';
1219
+ readonly x402ErrorCode: "already_settled";
1220
+ constructor(message: string, receipt: X402Receipt,
1221
+ /**
1222
+ * `settled` — the delegate was checked on-chain and cannot fund a fresh
1223
+ * authorization, so this payment demonstrably completed.
1224
+ * `unverifiable` — no `chainRpcs` entry for the chain, so fundability
1225
+ * could not be established either way. Same refusal, weaker claim; say
1226
+ * which, rather than assert what was not checked.
1227
+ */
1228
+ basis: 'settled' | 'unverifiable');
1229
+ }
1230
+ declare class HavenPaymentStateError extends HavenApiError {
1231
+ readonly state: PaymentStatusResult;
1232
+ resumeState?: X402ResumeState;
1233
+ constructor(message: string, statusCode: number, state: PaymentStatusResult, body?: unknown);
1234
+ get status(): string;
1235
+ get phase(): PaymentPhase;
1236
+ get nextAction(): PaymentNextAction;
1237
+ }
1238
+ declare class HavenSigningError extends HavenError {
1239
+ constructor(message: string);
1240
+ }
1241
+ /**
1242
+ * Refusal codes the local signer returns when it does not recognise the
1243
+ * VERSION of a Haven-signed binding it was asked to sign (#1309). Distinct
1244
+ * from `AgentPaymentFailureCode`: these describe a **signer capability**
1245
+ * problem (this install cannot evaluate what Haven sent), not a payment-domain
1246
+ * outcome, and they never reach the backend's REST/OpenAPI surface — only the
1247
+ * local signer's own MCP tool responses (`haven_sign` / `haven_sign_x402` /
1248
+ * `haven_sign_sweep_delegate`). That is also why this pair does not go through
1249
+ * the `AgentPaymentFailureCode` four-gate (sdk → backend mirror → spec →
1250
+ * api-types): there is no backend mirror to keep in sync with.
1251
+ */
1252
+ declare const SignerRefusalCode: {
1253
+ /** `SUPPORTED_X402_EXPECTED_VERSIONS` in `@haven_ai/signer` does not include the received version. */
1254
+ readonly UnsupportedExpectedContextVersion: "UNSUPPORTED_EXPECTED_CONTEXT_VERSION";
1255
+ /** `SUPPORTED_SWEEP_BINDING_VERSIONS` in `@haven_ai/signer` does not include the received version. */
1256
+ readonly UnsupportedSweepBindingVersion: "UNSUPPORTED_SWEEP_BINDING_VERSION";
1257
+ };
1258
+ type SignerRefusalCode = (typeof SignerRefusalCode)[keyof typeof SignerRefusalCode];
1259
+ /**
1260
+ * Canonical recovery guidance for a stale local signer (#1309) — the ONE
1261
+ * string both the signer's structured refusal (`fallback` field, carried by
1262
+ * `HavenUnsupportedSignerVersionError`) and the hosted quote's advisory
1263
+ * `signer_compatibility.fallback` (#1155) render, so an agent that meets
1264
+ * either surface is told the identical fix. A second hand-maintained copy of
1265
+ * this sentence is exactly how the two surfaces could start disagreeing about
1266
+ * what to do.
1267
+ */
1268
+ declare function signerUpdateFallback(channel?: string): string;
1269
+ /**
1270
+ * The same sentence rendered for THIS build's channel (#2423). Every existing
1271
+ * consumer keeps importing this constant and keeps getting a string; the only
1272
+ * thing that moved is that `alpha` is no longer typed into it.
1273
+ *
1274
+ * The hosted MCP server is the one caller that does NOT use this constant: it
1275
+ * is deployed rather than published, so it renders `signerUpdateFallback()`
1276
+ * with the channel its own environment names.
1277
+ */
1278
+ declare const SIGNER_UPDATE_FALLBACK: string;
1279
+ /**
1280
+ * Thrown by the local signer when a Haven-signed binding (x402 expected
1281
+ * context or sweep authorization) carries a version outside what this signer
1282
+ * install enforces (#1143, structured as #1309). Machine-readable: `code`,
1283
+ * `supportedVersions`, and `receivedVersion` are DERIVED from the signer's own
1284
+ * `SUPPORTED_X402_EXPECTED_VERSIONS` / `SUPPORTED_SWEEP_BINDING_VERSIONS`
1285
+ * constants at the throw site, never a second literal — see
1286
+ * `assertSupportedBindingVersion` in `@haven_ai/signer`.
1287
+ *
1288
+ * This narrows HOW the refusal is reported. It does not weaken it: nothing is
1289
+ * signed either way, and the version stays inside the Haven-signed binding
1290
+ * message (callers must not "fix" a mismatch by rewriting it).
1291
+ */
1292
+ declare class HavenUnsupportedSignerVersionError extends HavenError {
1293
+ readonly supportedVersions: readonly number[];
1294
+ readonly receivedVersion: number;
1295
+ readonly fallback: string;
1296
+ constructor(message: string, code: SignerRefusalCode, supportedVersions: readonly number[], receivedVersion: number, fallback: string);
1297
+ }
1298
+ declare class HavenTimeoutError extends HavenError {
1299
+ constructor(paymentId: string);
1300
+ }
1301
+
1302
+ /**
1303
+ * Gasless delegate-sweep primitives — the single source of truth shared by the
1304
+ * edge signer (which signs) and the Haven backend (which relays).
1305
+ *
1306
+ * A stranded delegate EOA holds USDC but no ETH, so a raw ERC-20 transfer can't
1307
+ * pay for its own gas. Instead the delegate signs an *off-chain* EIP-3009
1308
+ * `TransferWithAuthorization` and the Haven relayer submits it on-chain and pays
1309
+ * gas. The relayer is only a gas payer: it holds no allowance and is never a
1310
+ * spender, so a relayer compromise cannot move user funds.
1311
+ *
1312
+ * Framework-neutral on purpose: `buildSweepTypedData` returns a plain
1313
+ * `{ domain, types, primaryType, message }` that both viem
1314
+ * (`signTypedData`/`recoverTypedDataAddress`) and ethers v6
1315
+ * (`signTypedData`/`verifyTypedData`) accept, so the signer (viem) and backend
1316
+ * (ethers) stay in lockstep without sharing a crypto library.
1317
+ */
1318
+ /** Base mainnet. The only chain Haven sweeps today. */
1319
+ declare const SWEEP_BASE_CHAIN_ID = 8453;
1320
+ /** Base Sepolia testnet — used by the dev environment / QA harness. */
1321
+ declare const SWEEP_BASE_SEPOLIA_CHAIN_ID = 84532;
1322
+ /** Canonical Circle USDC on Base (FiatTokenV2_2). */
1323
+ declare const SWEEP_BASE_USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
1324
+ /** Circle's canonical Base Sepolia testnet USDC. */
1325
+ declare const SWEEP_BASE_SEPOLIA_USDC_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
1326
+ /** True when the gasless sweep supports a chain (its USDC domain + address are known). */
1327
+ declare function isSweepableChain(chainId: number): boolean;
1328
+ /** EIP-712 `TransferWithAuthorization` struct, per EIP-3009. */
1329
+ declare const TRANSFER_WITH_AUTHORIZATION_TYPES: {
1330
+ readonly TransferWithAuthorization: readonly [{
1331
+ readonly name: "from";
1332
+ readonly type: "address";
1333
+ }, {
1334
+ readonly name: "to";
1335
+ readonly type: "address";
1336
+ }, {
1337
+ readonly name: "value";
1338
+ readonly type: "uint256";
1339
+ }, {
1340
+ readonly name: "validAfter";
1341
+ readonly type: "uint256";
1342
+ }, {
1343
+ readonly name: "validBefore";
1344
+ readonly type: "uint256";
1345
+ }, {
1346
+ readonly name: "nonce";
1347
+ readonly type: "bytes32";
1348
+ }];
1349
+ };
1350
+ interface SweepEip712Domain {
1351
+ name: string;
1352
+ version: string;
1353
+ chainId: number;
1354
+ verifyingContract: string;
1355
+ }
1356
+ /**
1357
+ * A fully-specified EIP-3009 authorization. All amounts/times are decimal
1358
+ * strings (JSON-safe) and `nonce` is a 0x-prefixed 32-byte hex value. `token`
1359
+ * and `chainId` are carried explicitly so the signer can assert they are
1360
+ * canonical before signing.
1361
+ */
1362
+ interface SweepAuthorization {
1363
+ /** Delegate EOA the funds are swept FROM. */
1364
+ from: string;
1365
+ /** Originating Safe the funds are swept TO. */
1366
+ to: string;
1367
+ /** Atomic USDC amount (decimal string). */
1368
+ value: string;
1369
+ /** Unix seconds the authorization becomes valid (decimal string, usually "0"). */
1370
+ validAfter: string;
1371
+ /** Unix seconds the authorization expires (decimal string). */
1372
+ validBefore: string;
1373
+ /** Random 0x-prefixed 32-byte hex nonce. */
1374
+ nonce: string;
1375
+ /** USDC contract address. */
1376
+ token: string;
1377
+ /** Chain id (8453 today). */
1378
+ chainId: number;
1379
+ }
1380
+ /**
1381
+ * Haven's signature over the sweep authorization context, signed with the same
1382
+ * binding key the x402 expected-context uses. Lets the edge signer verify the
1383
+ * authorization actually came from Haven (and wasn't crafted by a compromised
1384
+ * hosted server pointing `to` at an attacker) before it signs.
1385
+ */
1386
+ interface SweepExpectedAuth {
1387
+ /**
1388
+ * Currently always 1. Typed as `number` for the same reason as
1389
+ * `X402ExpectedAuth.version` (#1143): it is inbound, so a stale signer must be
1390
+ * able to *receive* an unknown version in order to report it. The signer's
1391
+ * `SUPPORTED_SWEEP_BINDING_VERSIONS` is the authority on what it will sign.
1392
+ */
1393
+ version: number;
1394
+ message: string;
1395
+ signature: string;
1396
+ signer: string;
1397
+ }
1398
+ /** What `POST /machine-payments/sweep/prepare` returns when funds are stranded. */
1399
+ interface SweepPreparation {
1400
+ authorization: SweepAuthorization;
1401
+ expectedAuth: SweepExpectedAuth;
1402
+ }
1403
+ /** Wire response from `POST /machine-payments/sweep/prepare` (snake_case). */
1404
+ interface SweepPrepareResponse {
1405
+ /** Present and true when the delegate holds nothing to recover. */
1406
+ nothing_stranded?: boolean;
1407
+ /**
1408
+ * Present and true when the stranded balance is below the sweep floor (#700):
1409
+ * it is left on the delegate as dust rather than recovered, because the gas to
1410
+ * sweep it would exceed its value. `min_usdc` carries the configured floor. No
1411
+ * `authorization` is built.
1412
+ */
1413
+ below_min?: boolean;
1414
+ min_usdc?: string;
1415
+ /** The authorization to sign — absent when nothing is stranded or below the floor. */
1416
+ authorization?: SweepAuthorization;
1417
+ /** Haven's binding over the authorization — absent when nothing is stranded. */
1418
+ expected_auth?: SweepExpectedAuth;
1419
+ asset?: string;
1420
+ amount?: string;
1421
+ amount_atomic?: string;
1422
+ chain_id: number;
1423
+ sign_instructions?: string;
1424
+ message?: string;
1425
+ }
1426
+ /** Wire response from `POST /machine-payments/sweep/submit` (snake_case). */
1427
+ interface SweepSubmitResponse {
1428
+ tx_hash: string;
1429
+ asset: string;
1430
+ amount: string;
1431
+ amount_atomic: string;
1432
+ from_address: string;
1433
+ to_address: string;
1434
+ chain_id: number;
1435
+ explorer_url: string;
1436
+ idempotent_replay?: boolean;
1437
+ }
1438
+ /** Result of a submitted gasless sweep. */
1439
+ interface SweepSubmitResult {
1440
+ txHash: string;
1441
+ amount: string;
1442
+ amountAtomic: string;
1443
+ asset: string;
1444
+ fromAddress: string;
1445
+ toAddress: string;
1446
+ chainId: number;
1447
+ explorerUrl: string;
1448
+ }
1449
+ interface SweepTypedData {
1450
+ domain: SweepEip712Domain;
1451
+ types: typeof TRANSFER_WITH_AUTHORIZATION_TYPES;
1452
+ primaryType: 'TransferWithAuthorization';
1453
+ message: {
1454
+ from: string;
1455
+ to: string;
1456
+ value: bigint;
1457
+ validAfter: bigint;
1458
+ validBefore: bigint;
1459
+ nonce: string;
1460
+ };
1461
+ }
1462
+ /** Resolve the canonical USDC contract for a sweepable chain, or throw. */
1463
+ declare function sweepUsdcAddress(chainId: number): string;
1464
+ /** Resolve the USDC EIP-712 domain for a sweepable chain, or throw. */
1465
+ declare function sweepUsdcDomain(chainId: number): SweepEip712Domain;
1466
+ /**
1467
+ * Build the EIP-712 typed data for an authorization, validating that the token
1468
+ * and chain are canonical (the domain's `verifyingContract` must match the
1469
+ * authorization's `token`). Returns bigint-valued fields so both viem and
1470
+ * ethers v6 sign/recover identically.
1471
+ */
1472
+ declare function buildSweepTypedData(auth: SweepAuthorization): SweepTypedData;
1473
+ /**
1474
+ * Canonical, deterministic string the backend signs and the signer re-derives
1475
+ * for the authorization binding. The `Haven sweep authorization v1` namespace
1476
+ * (and `kind`) is distinct from the x402 expected-context namespace so an x402
1477
+ * binding can never be replayed as a sweep authorization even though they share
1478
+ * a signing key.
1479
+ */
1480
+ declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): string;
1481
+
1482
+ /**
1483
+ * Merchant delivery and the evidence trail behind it (#1620, epic #1613).
1484
+ *
1485
+ * Where `mcp-merchant-transport.ts` (#1616) owns the wire — timeouts,
1486
+ * sessions, SSE framing — this module owns what has to be TRUE around a
1487
+ * merchant call once a payment exists: which wallet the merchant should see,
1488
+ * what the payment's live state permits, and what gets written down
1489
+ * afterwards.
1490
+ *
1491
+ * The reporting is deliberately best-effort and deliberately asymmetric. A
1492
+ * merchant that REJECTS a retry after Haven already moved money is a
1493
+ * reconciliation event and is recorded as one; a merchant that accepts is
1494
+ * evidence, plus its own receipt when it offers one. Neither write may ever
1495
+ * change the caller-visible outcome — the resource is already paid for, and
1496
+ * an exception thrown from bookkeeping would turn a completed payment into a
1497
+ * reported failure. That is why every one of these swallows.
1498
+ *
1499
+ * Scheme-neutral by construction: it is handed a receipt or a payment id and
1500
+ * never asks how the money moved, which is what lets the #1508 no-funding-leg
1501
+ * path through the same door as the 3009 path.
1502
+ *
1503
+ * Internal to `HavenClient`. Exported for direct tests and composition only.
1504
+ */
1505
+ /** #2292: what an agent says a merchant answered to a retry Haven did not make. */
1506
+ type X402MerchantOutcome = 'accepted' | 'rejected';
1507
+ /** #2292: what Haven wrote down for such a report. */
1508
+ interface X402MerchantOutcomeReport {
1509
+ paymentId: string;
1510
+ outcome: X402MerchantOutcome;
1511
+ /** Haven's own funding tx for this payment — the anchor, never caller-supplied. */
1512
+ txHash: string;
1513
+ /** Haven's own recorded resource URL — likewise never caller-supplied. */
1514
+ resourceUrl: string;
1515
+ recorded: 'reconciliation_event' | 'evidence';
1516
+ }
1517
+
1518
+ declare class HavenClient {
1519
+ private readonly delegateKey;
1520
+ private readonly havenApi;
1521
+ private readonly accountReads;
1522
+ private readonly delegateSweep;
1523
+ private readonly x402Wallet;
1524
+ private readonly merchantTransport;
1525
+ private readonly confirmationTimeout;
1526
+ private readonly pollingInterval;
1527
+ private readonly chainRpcs;
1528
+ private readonly inFlightX402;
1529
+ /**
1530
+ * The EIP-3009 funding-leg lifecycle (#1618). The facade holds a reference
1531
+ * and delegates; it does not reimplement any of it.
1532
+ */
1533
+ private readonly fundingLeg;
1534
+ /**
1535
+ * The erc7710 direct-settlement lifecycle (#1619). Separate from the funding
1536
+ * leg on purpose: this scheme has no funding leg to share.
1537
+ */
1538
+ private readonly erc7710;
1539
+ /**
1540
+ * Merchant delivery and the evidence trail behind it (#1620). Scheme-neutral
1541
+ * on purpose — both settlement schemes finish through the same door.
1542
+ */
1543
+ private readonly merchantCompletion;
1544
+ /** Delegate address derived from the private key (if provided) */
1545
+ readonly delegateAddress: string | undefined;
1546
+ constructor(config: HavenClientConfig);
1547
+ /**
1548
+ * Run `fn` with extra Haven-API headers scoped to the async work it
1549
+ * performs. Used by the MCP server to tag every Haven API request that
1550
+ * a single tool dispatch makes with `X-Haven-MCP-Tool: <name>` so the
1551
+ * backend can write an audit-log row attributing the call.
1552
+ *
1553
+ * The headers are held in an `AsyncLocalStorage` so overlapping
1554
+ * dispatches do not leak headers into each other's requests. The store
1555
+ * inherits across `await` boundaries, so any Haven API call made while
1556
+ * `fn` is awaiting will pick up the right headers.
1557
+ *
1558
+ * Has no effect on outbound merchant requests (x402 / MPP) — those
1559
+ * never go through the internal `request<T>` path that reads the
1560
+ * context.
1561
+ */
1562
+ withRequestContext<T>(headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;
1563
+ /**
1564
+ * Send a payment in one call.
1565
+ *
1566
+ * Creates the intent, signs the hash, submits the signature,
1567
+ * and polls until confirmed (or throws on failure/timeout).
1568
+ *
1569
+ * Requires `delegateKey` to be set in the client config.
1570
+ */
1571
+ pay(request: PaymentRequest): Promise<PaymentResult>;
1572
+ /**
1573
+ * Step 1: Create a payment intent.
1574
+ *
1575
+ * Returns the intent with the hash to sign.
1576
+ */
1577
+ createIntent(request: PaymentRequest): Promise<PaymentIntent>;
1578
+ /**
1579
+ * Keyless x402 construct.
1580
+ *
1581
+ * The non-custodial half of an x402 payment: posts the funding request to
1582
+ * `/x402` and returns the unsigned funding hash plus the data the caller
1583
+ * needs to build and sign the EIP-3009 merchant header itself. Crucially it
1584
+ * does **not** sign — neither the funding hash nor the merchant header — so
1585
+ * it works without a `delegateKey`. Both delegate signatures happen on the
1586
+ * machine that holds the key (the edge); the hosted MCP server relays only.
1587
+ *
1588
+ * Use this from the hosted, keyless server. The all-in-one `authorizeX402`
1589
+ * remains for local clients that hold the key.
1590
+ *
1591
+ * Throws (via the shared payment-state path) when the amount exceeds the
1592
+ * on-chain allowance — there is nothing to sign until the user approves.
1593
+ */
1594
+ createX402Intent(paymentRequired: X402PaymentRequired, options?: X402AuthorizationOptions): Promise<X402Intent>;
1595
+ /**
1596
+ * Step 2: Sign a hash with the delegate key.
1597
+ *
1598
+ * Returns the 65-byte signature (0x-prefixed).
1599
+ * Requires `delegateKey` to be set in the client config.
1600
+ */
1601
+ sign(hash: string): string;
1602
+ /**
1603
+ * Sign a payment's `sign_data` with the correct scheme for its rail.
1604
+ *
1605
+ * Dispatching on the server-provided scheme means a caller never has to
1606
+ * know which rail an account is on; an unknown scheme is a hard error,
1607
+ * never a guessed signature. The session rail's 'eip191_userop' is retired
1608
+ * (#834) — the backend refuses those intents with HTTP 410 before any
1609
+ * sign_data reaches a client, so encountering it here is a hard error too.
1610
+ */
1611
+ private signForData;
1612
+ /**
1613
+ * Step 3: Submit a signature to execute the payment.
1614
+ *
1615
+ * The signature can come from `client.sign()` or from external signing.
1616
+ */
1617
+ submitSignature(paymentId: string, signature: string): Promise<{
1618
+ status: string;
1619
+ txHash?: string;
1620
+ }>;
1621
+ /**
1622
+ * Get the current status of a payment.
1623
+ */
1624
+ getPayment(paymentId: string): Promise<PaymentResult>;
1625
+ /**
1626
+ * Get agent-actionable status for a payment intent or approval request.
1627
+ *
1628
+ * Use this for IDs returned by agent tools and machine-payment/x402 flows.
1629
+ * `getPayment()` remains available for payment-intent-only integrations.
1630
+ */
1631
+ getPaymentStatus(paymentId: string): Promise<PaymentStatusResult>;
1632
+ /**
1633
+ * Get the agent identity tied to this API key.
1634
+ */
1635
+ getAgent(): Promise<HavenAgent>;
1636
+ /**
1637
+ * One-shot "am I ready?" bootstrap: identity + live spend authority + a
1638
+ * readiness signal, in a single call. Folds {@link getAgent} and
1639
+ * {@link getAllowances} together and derives a {@link HavenAgentReadiness}
1640
+ * so an agent can answer "who am I and can I pay right now" at session start
1641
+ * without two round trips and manual assembly.
1642
+ */
1643
+ getAgentSummary(): Promise<HavenAgentSummary>;
1644
+ /**
1645
+ * Sweep stranded USDC and ETH from the delegate EOA back to the originating Safe.
1646
+ *
1647
+ * The delegate key held by this client signs and submits the transfer transactions
1648
+ * directly — Haven's backend never handles the key or constructs signed txs
1649
+ * (CASP/MiCA Red Line #2). Funds always go to the Safe linked to this agent.
1650
+ *
1651
+ * Requires `chainRpcs` to be set for the agent's chain in `HavenClientConfig`.
1652
+ */
1653
+ sweepDelegate(): Promise<SweepResult>;
1654
+ /**
1655
+ * Hosted (keyless) split-signer sweep — step 1 of 2.
1656
+ *
1657
+ * Asks the backend to build a gasless EIP-3009 sweep authorization for the
1658
+ * delegate's stranded USDC. Returns `nothing_stranded` when the delegate is
1659
+ * empty, otherwise an `authorization` + Haven `expected_auth` to hand to the
1660
+ * edge signer's `haven_sign_sweep_delegate`. No key is required on this client.
1661
+ */
1662
+ prepareSweep(): Promise<SweepPrepareResponse>;
1663
+ /**
1664
+ * Hosted (keyless) split-signer sweep — step 2 of 2.
1665
+ *
1666
+ * Relays the delegate-signed authorization. The Haven relayer submits the
1667
+ * on-chain `transferWithAuthorization` and pays gas; this client never holds
1668
+ * the key.
1669
+ */
1670
+ submitSweep(authorization: SweepAuthorization, signature: string): Promise<SweepSubmitResponse>;
1671
+ /**
1672
+ * Get configured and on-chain allowances for the authenticated agent.
1673
+ */
1674
+ getAllowances(): Promise<HavenAllowanceSummary>;
1675
+ /**
1676
+ * Post-purchase allowance/budget summary for a settled payment (#1310).
1677
+ *
1678
+ * Reuses the EXACT rail-aware read path {@link getAllowances} / #1306's
1679
+ * catalog-purchase preflight `allowance` block use — `GET
1680
+ * /machine-payments/allowances`, with delegation-rail values coming from
1681
+ * the #1090 `deriveDelegationBudgets`-backed enforcer read, never
1682
+ * `agent_allowances` — so this can never disagree with
1683
+ * {@link getAllowances} for the same fixture. The settled token is
1684
+ * resolved from {@link getPaymentStatus} so callers pass only
1685
+ * `paymentId`, never a second haven_get_agent-style round trip.
1686
+ *
1687
+ * NEVER throws: any failed read (status lookup, agent lookup, or the
1688
+ * allowance/budget lookup itself) degrades to `{ allowance: null,
1689
+ * warnings: [ALLOWANCE_CHECK_UNAVAILABLE] }` rather than converting a
1690
+ * successful settlement into a failure — the on-chain policy remains the
1691
+ * actual spend gate regardless of whether this report can be produced.
1692
+ *
1693
+ * Freshness caveat (#1319): the delegation rail's on-chain enforcer read
1694
+ * can silently fall back to the optimistic full period budget without
1695
+ * throwing when the RPC read itself fails (#1145's fund-safe design,
1696
+ * unchanged here). {@link getAllowances}'s `onchain.remainingIsFromChain`
1697
+ * now carries that provenance on the wire, and the #1306 catalog-purchase
1698
+ * preflight (`haven_prepare_catalog_purchase`) surfaces it as a warning —
1699
+ * this summary does not (yet). `remaining_atomic` here reflects the last
1700
+ * successful chain read, not a guaranteed-live one, and callers should not
1701
+ * phrase it as guaranteed-fresh.
1702
+ */
1703
+ getPostPurchaseAllowanceSummary(paymentId: string): Promise<{
1704
+ allowance: PostPurchaseAllowanceSummary | null;
1705
+ warnings: AgentPaymentWarning[];
1706
+ payment: PaymentStatusResult | null;
1707
+ }>;
1708
+ /**
1709
+ * `haven_get_payment_status` convenience: fetch status and, for a
1710
+ * genuinely SETTLED x402 payment, attach the same post-purchase
1711
+ * allowance/budget summary a settle response carries.
1712
+ *
1713
+ * #1310/#1311 parity: this is the ONE home for logic that was duplicated
1714
+ * verbatim in `packages/mcp-server/src/tools.ts` and `packages/mcp/src/tools.ts`
1715
+ * (both hosted and local `haven_get_payment_status` handlers) — extracted
1716
+ * here because both packages already depend on `@haven_ai/sdk` and call
1717
+ * methods on a `HavenClient` instance, so this needed no new dependency
1718
+ * edge. `funded_but_unsettled` is deliberately excluded: that phase means
1719
+ * the merchant did NOT accept the retry. Every other phase/rail returns
1720
+ * the status untouched.
1721
+ */
1722
+ getPaymentStatusWithPostPurchaseAllowance(paymentId: string): Promise<PaymentStatusResult & {
1723
+ allowance?: PostPurchaseAllowanceSummary | null;
1724
+ warnings?: AgentPaymentWarning[];
1725
+ }>;
1726
+ /**
1727
+ * Discover payable services from Haven's merchant catalog (epic #1717).
1728
+ *
1729
+ * Read-only: returns catalog entries (price, rail, protocol) so an agent
1730
+ * can choose a service and pay it with the regular payment tools in the
1731
+ * same session. Never creates payments or signatures.
1732
+ */
1733
+ discoverTools(options?: {
1734
+ category?: string;
1735
+ search?: string;
1736
+ rail?: 'x402' | 'mpp';
1737
+ /**
1738
+ * Filter on the entry's provenance (epic #1717): `'verified'` returns
1739
+ * only self-submitted, domain-verified, probe-verified directory
1740
+ * entries; `'operator'` only the operator-curated ones; `'any'` (the
1741
+ * default) returns the merged listing.
1742
+ */
1743
+ verified?: 'any' | 'verified' | 'operator';
1744
+ }): Promise<HavenCatalogEntry[]>;
1745
+ /**
1746
+ * Submit a merchant's payable (x402/MCP) endpoint to the Verified Payable
1747
+ * Directory (epic #1717, #1716). Queue-only: writes a submission row and
1748
+ * returns the id + verify_token. The request path makes no outbound
1749
+ * request; domain-ownership proof and the read-only quote probe run later
1750
+ * on the leader-locked monitor. Ownership proof is ALWAYS required before
1751
+ * any listing — this method cannot skip it. `website` is a honeypot field
1752
+ * that bots fill; leave it unset.
1753
+ */
1754
+ submitCatalogEntry(resourceUrl: string, options?: {
1755
+ website?: string;
1756
+ }): Promise<HavenCatalogSubmission>;
1757
+ /**
1758
+ * Fetch one submission's coarse status by id (epic #1717, #1716). Public
1759
+ * and read-only. While the submission can still prove ownership the
1760
+ * response carries the exact well-known / DNS-TXT `instructions`; the
1761
+ * verify token is never returned here.
1762
+ */
1763
+ getCatalogSubmissionStatus(id: string): Promise<{
1764
+ id: string;
1765
+ status: 'submitted' | 'ownership_verified' | 'verified_payable' | 'failed' | 'delisted';
1766
+ instructions?: {
1767
+ expires_at: string;
1768
+ well_known: {
1769
+ url: string;
1770
+ content: string;
1771
+ instruction: string;
1772
+ };
1773
+ dns_txt: {
1774
+ name: string;
1775
+ value: string;
1776
+ instruction: string;
1777
+ };
1778
+ } | null;
1779
+ }>;
1780
+ /**
1781
+ * Fetch one curated catalog entry by id (#1306).
1782
+ *
1783
+ * Chain-scoped for free by the backend's SQL when the client is
1784
+ * agent-authenticated (#1299): an unknown id and an id curated for a
1785
+ * DIFFERENT chain than this agent's both 404 identically — this method does
1786
+ * not (and must not) re-filter by chain in JS. Read-only, like
1787
+ * {@link discoverTools}.
1788
+ */
1789
+ getCatalogEntry(id: string): Promise<HavenCatalogEntry>;
1790
+ /**
1791
+ * List recent machine-payment receipts/evidence for bookkeeping.
1792
+ */
1793
+ listReceipts(options?: {
1794
+ limit?: number;
1795
+ }): Promise<HavenPaymentReceipt[]>;
1796
+ /**
1797
+ * Fetch the verifiable receipt bundle for a settled payment and verify it
1798
+ * locally. The server's own verification is ignored — the receipt is verified
1799
+ * here (independently of Haven) by recovering the signer from the
1800
+ * authorisation, so the result is trustworthy even if the backend lied.
1801
+ */
1802
+ getReceipt(paymentId: string): Promise<{
1803
+ receipt: PaymentReceipt;
1804
+ verification: ReceiptVerification;
1805
+ }>;
1806
+ /**
1807
+ * Rehydrate the x402 resume-state bundle for a payment id (#1328: the MPP
1808
+ * resume-state variant retired along with the rest of the mpp_demo surface).
1809
+ *
1810
+ * The server returns stored protocol context only. The client still signs the
1811
+ * merchant proof locally when resumeX402Payment() runs.
1812
+ */
1813
+ getResumeState(paymentId: string): Promise<PaymentResumeState>;
1814
+ /**
1815
+ * Poll until a payment reaches a terminal status (confirmed, failed, expired).
1816
+ */
1817
+ waitForConfirmation(paymentId: string): Promise<PaymentResult>;
1818
+ /**
1819
+ * Authorize an x402 payment.
1820
+ *
1821
+ * Takes the parsed PaymentRequired from a 402 response, selects a compatible
1822
+ * option, funds the delegate wallet through Haven, and returns the standard
1823
+ * x402 header that the merchant can verify and settle.
1824
+ *
1825
+ * Requires `delegateKey` to be set in the client config.
1826
+ */
1827
+ authorizeX402(paymentRequired: X402PaymentRequired, options?: X402AuthorizationOptions): Promise<X402Receipt>;
1828
+ /**
1829
+ * Probe a paid endpoint and return its x402 quote without creating a Haven
1830
+ * payment or approval request.
1831
+ */
1832
+ quoteX402(url: string, init?: RequestInit, options?: X402AuthorizationOptions): Promise<X402Quote>;
1833
+ /**
1834
+ * Probe an MCP tool for its x402 quote without creating a payment.
1835
+ *
1836
+ * Unlike the generic {@link quoteX402} helper, this completes the
1837
+ * Streamable-HTTP MCP lifecycle before sending the unpaid `tools/call`.
1838
+ * Hosted MCP uses this path while remaining keyless: it resolves only the
1839
+ * agent's public delegate address for `x402-wallet`; signing remains local.
1840
+ * It refuses before the quote when the merchant does not establish a session;
1841
+ * callers that need a plain x402 endpoint must use {@link quoteX402}.
1842
+ */
1843
+ quoteMcpX402(url: string, init?: RequestInit, options?: X402AuthorizationOptions): Promise<X402Quote>;
1844
+ /**
1845
+ * Pay a previously inspected x402 quote and retry the exact captured request.
1846
+ */
1847
+ payX402Quote(quote: X402Quote, options?: X402AuthorizationOptions): Promise<Response>;
1848
+ /**
1849
+ * Pay a merchant through **erc7710 direct settlement** (#1454, epic #1450).
1850
+ *
1851
+ * **Nothing has settled when this returns** — that is why it does not return
1852
+ * an `X402Receipt`; the caller still has to retry the merchant with the
1853
+ * header. **MCP callers must pass `options.resourceUrl`**, because an in-band
1854
+ * MCP 402 challenge frequently carries no `resource` object at all.
1855
+ *
1856
+ * Both caveats, and why this scheme has no funding leg, are explained where
1857
+ * the lifecycle lives: `x402-erc7710.ts` (#1619).
1858
+ */
1859
+ settleX402Erc7710(paymentRequired: X402PaymentRequired, options?: {
1860
+ resourceUrl?: string;
1861
+ }): Promise<X402Erc7710Settlement>;
1862
+ /**
1863
+ * The AUTHORIZE half of erc7710 settlement (#1456): select the scheme, build
1864
+ * the request, and return the child to be signed — without signing it.
1865
+ *
1866
+ * Split out because the hosted topology cannot use `settleX402Erc7710()`:
1867
+ * that method signs in-process with `delegateKey`, and hosted Haven does not
1868
+ * have one and must not.
1869
+ */
1870
+ prepareX402Erc7710(paymentRequired: X402PaymentRequired, options?: {
1871
+ resourceUrl?: string;
1872
+ /**
1873
+ * The account's rail, when the caller has ALREADY read it — passing it
1874
+ * skips a duplicate fetch (#1456). An optimisation, not a trust
1875
+ * boundary: the backend independently refuses a non-delegation account
1876
+ * at the rail seam (the #1986 retired-rail 410, #2245).
1877
+ */
1878
+ delegationRail?: boolean;
1879
+ /**
1880
+ * #1547: the merchant MCP-tool call this authorization was quoted
1881
+ * against, persisted so the settle leg can rehydrate it by payment_id
1882
+ * (#1307).
1883
+ */
1884
+ mcpCallContext?: X402McpCallContext;
1885
+ /**
1886
+ * #2041: replay key, as `createX402Intent` already takes one. Without it
1887
+ * a retried authorize mints a second signable settlement child instead
1888
+ * of replaying the first.
1889
+ */
1890
+ idempotencyKey?: string;
1891
+ }): Promise<{
1892
+ paymentId: string;
1893
+ signData: SignData;
1894
+ settlement: Omit<X402Erc7710Settlement, 'paymentHeader'>;
1895
+ }>;
1896
+ /**
1897
+ * The SETTLE half (#1456): exchange the signed child for the merchant header.
1898
+ *
1899
+ * The SDK builds no header on this path — the backend assembles the MetaMask
1900
+ * erc7710 payload. Whoever produced the signature (an in-process delegate
1901
+ * key, or the local edge signer over the hosted boundary) is irrelevant.
1902
+ */
1903
+ submitX402Erc7710(paymentId: string, signature: string): Promise<string>;
1904
+ resumeAuthorizedX402(input: ResumeAuthorizedX402Input): Promise<X402Receipt>;
1905
+ resumeX402Payment(input: ResumeX402PaymentInput | X402ResumeState): Promise<Response>;
1906
+ /**
1907
+ * Fetch wrapper that automatically handles HTTP 402 responses.
1908
+ *
1909
+ * Works like the standard `fetch()` but intercepts 402 responses,
1910
+ * pays via x402 through Haven, and retries the request.
1911
+ *
1912
+ * ```ts
1913
+ * const response = await haven.fetch('https://paid-api.com/data')
1914
+ * const data = await response.json()
1915
+ * ```
1916
+ *
1917
+ * **MCP-over-x402 auto-handshake (issue #315):** when the endpoint is
1918
+ * MCP-shaped — the URL path ends in `/mcp`, or the 402 body carries a
1919
+ * Coinbase Bazaar `extensions.bazaar` block — the SDK runs the MCP
1920
+ * `initialize` handshake, threads the resulting `mcp-session-id`,
1921
+ * `Accept: application/json, text/event-stream`, and `x402-wallet` headers
1922
+ * through every request, and collapses SSE responses to the JSON-RPC
1923
+ * `result`. The caller just passes `(url, { body })` and never sees the
1924
+ * protocol plumbing. A non-MCP server (handshake error / no session id)
1925
+ * falls back to standard x402 behaviour.
1926
+ *
1927
+ * Requires `delegateKey` to be set in the client config.
1928
+ */
1929
+ fetch(url: string, init?: RequestInit, options?: X402AuthorizationOptions): Promise<Response>;
1930
+ /**
1931
+ * Deliver an already-signed x402 payment header to the merchant and return
1932
+ * the merchant's response. Used by the hosted MCP server to complete the
1933
+ * merchant leg of an MCP tool payment after the edge signer has built the
1934
+ * merchant payment header.
1935
+ *
1936
+ * Custody note: this never needs the delegate key. It relays a signed,
1937
+ * amount/merchant/nonce-bound EIP-3009 authorization the edge signer already
1938
+ * produced — the hosted server cannot mint or reuse signing authority.
1939
+ *
1940
+ * When the URL is MCP-shaped (`/mcp` path) or the quote-time transport context
1941
+ * says the merchant was Bazaar-discoverable, runs a fresh `initialize`
1942
+ * handshake (the quote-time session is gone once funding confirms; the x402
1943
+ * challenge is stateless w.r.t. the MCP session, so a fresh session is
1944
+ * accepted), threads the session + wallet headers, sets the x402 payment
1945
+ * header under the names that scheme requires (#2341), and
1946
+ * collapses an SSE JSON-RPC response to its `result`.
1947
+ */
1948
+ /**
1949
+ * Wait for a payment's Safe→delegate funding tx to reach ≥1 on-chain
1950
+ * confirmation. The hosted x402 completion path MUST call this after funding
1951
+ * and before delivering the merchant payment header, so the merchant's
1952
+ * balanceOf(delegate) / transferWithAuthorization verification sees the funded
1953
+ * balance — otherwise it rejects with "Payment verification failed". The
1954
+ * SDK's local path already does this (see `X402FundingLeg.authorize`); the hosted
1955
+ * split flow regressed when the 5→3 collapse removed the incidental
1956
+ * inter-call latency that used to mask it.
1957
+ *
1958
+ * **NOT a no-op when the funding tx hash is absent** (#1508). The WAIT is
1959
+ * skipped without a hash or a chain RPC, but the `GET /payments/:id` read
1960
+ * below runs UNCONDITIONALLY — it is how the fallback hash and the chainId
1961
+ * are obtained. That distinction is load-bearing: this method must never be
1962
+ * called on a scheme with no funding leg, because the read itself fails once
1963
+ * the intent reaches a status the backend maps to a non-2xx (`submitted` is a
1964
+ * 409), turning a settled payment into a reported error. The previous wording
1965
+ * here said "No-op when the funding tx hash ... is unavailable", and the
1966
+ * hosted erc7710 path was written against that promise — see
1967
+ * `deliverMerchantPayment`'s `noFundingLeg` option.
1968
+ */
1969
+ ensureFundingConfirmed(paymentId: string, fundingTxHash?: string): Promise<void>;
1970
+ completeX402MerchantCall(input: {
1971
+ url: string;
1972
+ init?: RequestInit;
1973
+ paymentId: string;
1974
+ paymentHeader: string;
1975
+ mcpTransport?: X402McpTransport;
1976
+ /**
1977
+ * #1508: the payment settles with NO funding leg (erc7710). This method was
1978
+ * written for EIP-3009 and encodes that lifecycle in two places — the
1979
+ * readiness gate wants `confirmed`, and a Haven funding tx hash is
1980
+ * mandatory. Neither is reachable on a scheme where the MERCHANT redeems
1981
+ * the delegation chain: the intent sits at `submitted` by design, and there
1982
+ * is no Haven-submitted transaction at all. Set this to take the
1983
+ * no-funding-leg path through both.
1984
+ */
1985
+ noFundingLeg?: boolean;
1986
+ }): Promise<{
1987
+ status: number;
1988
+ ok: boolean;
1989
+ body: unknown;
1990
+ settlementTxHash?: string;
1991
+ }>;
1992
+ /**
1993
+ * #2292: report the outcome of a merchant retry the AGENT performed.
1994
+ *
1995
+ * The hosted `haven_complete_mcp_tool` / `completeX402MerchantCall` path is
1996
+ * for merchants Haven calls itself. On the plain-HTTP x402 path Haven never
1997
+ * talks to the merchant, so the outcome of that retry had no way back —
1998
+ * see `MerchantCompletion.reportMerchantOutcome` for what is verified about
1999
+ * a caller-asserted report and what deliberately is not.
2000
+ */
2001
+ reportX402MerchantOutcome(input: {
2002
+ paymentId: string;
2003
+ outcome: X402MerchantOutcome;
2004
+ merchantStatus: number;
2005
+ merchantBody?: string;
2006
+ }): Promise<X402MerchantOutcomeReport>;
2007
+ /**
2008
+ * GET /x402/:id/merchant-call-context — the settle-leg twin of #1263's
2009
+ * sign-context fetch (#1307). Re-serves the stored merchant MCP-tool call
2010
+ * context (merchant_url, tool_name, arguments, mcp_transport) recorded at
2011
+ * quote time, so `haven_settle_mcp_tool` / `haven_complete_mcp_tool` can
2012
+ * omit those fields and let Haven rehydrate them by payment_id instead of
2013
+ * the caller re-threading them. Throws `HavenApiError` (404 unknown/foreign
2014
+ * payment_id, 409 no stored context, 410 expired) — the caller decides the
2015
+ * fallback (re-send the full context explicitly).
2016
+ */
2017
+ getX402MerchantCallContext(paymentId: string): Promise<X402MerchantCallContext>;
2018
+ /**
2019
+ * Wait for a funding tx to be mined with ≥1 confirmation before the
2020
+ * merchant retry, eliminating the race where the merchant's
2021
+ * `balanceOf(delegate)` runs before the funding block propagates.
2022
+ *
2023
+ * Skipped when `chainRpcs` does not include the chain; in that case Haven's
2024
+ * backend has already confirmed on-chain submission and callers accept the
2025
+ * small propagation window as a trade-off for not configuring an RPC URL.
2026
+ */
2027
+ private throwIfNonSignableAuthorizationState;
2028
+ /**
2029
+ * Execute a tool call by name and input.
2030
+ *
2031
+ * Designed to plug directly into agent tool-call handlers:
2032
+ *
2033
+ * ```ts
2034
+ * if (block.type === 'tool_use') {
2035
+ * const result = await haven.executeTool(block.name, block.input)
2036
+ * // send result back to the model
2037
+ * }
2038
+ * ```
2039
+ */
2040
+ executeTool(toolName: string, input: Record<string, unknown>): Promise<Record<string, unknown>>;
2041
+ private post;
2042
+ private get;
2043
+ }
2044
+
2045
+ /**
2046
+ * Pre-built tool definitions for AI agent frameworks.
2047
+ *
2048
+ * These definitions describe Haven's direct SDK tool-calling surface in the
2049
+ * formats expected by Claude (Anthropic) and OpenAI.
2050
+ *
2051
+ * The agent payment surface used by these tools is shared with the
2052
+ * `@haven_ai/mcp` server — both consume `toolDescriptions` from
2053
+ * `./tool-descriptions.ts`. Each consumer composes its own user-visible string
2054
+ * from the same semantic fragments, so guidance lands in both surfaces at
2055
+ * once and a downstream test asserts the shared summary appears in every
2056
+ * consumer description.
2057
+ *
2058
+ * Usage with Claude:
2059
+ * const response = await anthropic.messages.create({
2060
+ * tools: havenTools.claude(),
2061
+ * ...
2062
+ * })
2063
+ *
2064
+ * Usage with OpenAI:
2065
+ * const response = await openai.chat.completions.create({
2066
+ * tools: havenTools.openai(),
2067
+ * ...
2068
+ * })
2069
+ */
2070
+ interface ClaudeTool {
2071
+ name: string;
2072
+ description: string;
2073
+ input_schema: {
2074
+ type: 'object';
2075
+ properties: Record<string, unknown>;
2076
+ required: readonly string[];
2077
+ };
2078
+ }
2079
+ declare function claudeTools(): ClaudeTool[];
2080
+ interface OpenAITool {
2081
+ type: 'function';
2082
+ function: {
2083
+ name: string;
2084
+ description: string;
2085
+ parameters: {
2086
+ type: 'object';
2087
+ properties: Record<string, unknown>;
2088
+ required: readonly string[];
2089
+ };
2090
+ };
2091
+ }
2092
+ declare function openaiTools(): OpenAITool[];
2093
+ declare const havenTools: {
2094
+ /** Tool definitions in Anthropic/Claude format */
2095
+ claude: typeof claudeTools;
2096
+ /** Tool definitions in OpenAI function-calling format */
2097
+ openai: typeof openaiTools;
2098
+ };
2099
+
2100
+ /**
2101
+ * Sign a hash using raw ECDSA (no Ethereum message prefix).
2102
+ *
2103
+ * This matches what Safe's AllowanceModule `checkSignature` expects —
2104
+ * a direct ecrecover over the hash, NOT the "\x19Ethereum Signed Message" variant.
2105
+ *
2106
+ * Uses ethers.SigningKey.sign() instead of wallet.signMessage() to avoid the prefix.
2107
+ */
2108
+ declare function signHash(privateKey: string, hash: string): string;
2109
+ /**
2110
+ * Sign a delegation-rail payment (#829).
2111
+ *
2112
+ * The delegate SMART ACCOUNT validates an EIP-712 signature over the packed
2113
+ * UserOperation — signing the bare 4337 hash would be rejected on-chain. The
2114
+ * backend sends the exact typed data in `sign_data.typed_data`; we sign it
2115
+ * verbatim and never reconstruct it (a second source of truth could drift
2116
+ * from the account's own rules).
2117
+ */
2118
+ interface Eip712TypedData {
2119
+ domain: Record<string, unknown>;
2120
+ types: Record<string, unknown>;
2121
+ primaryType: string;
2122
+ message: Record<string, unknown>;
2123
+ }
2124
+ declare function signUserOpTypedDataForDelegation(privateKey: string, typedData: Eip712TypedData): Promise<string>;
2125
+ /**
2126
+ * Derive the Ethereum address from a private key.
2127
+ */
2128
+ declare function addressFromKey(privateKey: string): string;
2129
+ /**
2130
+ * Verify that a signature over a hash recovers to the expected address.
2131
+ */
2132
+ declare function verifySignature(hash: string, signature: string, expectedAddress: string): boolean;
2133
+
2134
+ /**
2135
+ * Shared semantic descriptions for Haven agent payment tools.
2136
+ *
2137
+ * Two surfaces in this repo expose Haven as a tool: the Claude / OpenAI
2138
+ * function-calling tool definitions in `tools.ts` (used for direct SDK
2139
+ * integrations) and the MCP server in `packages/mcp` (used by any MCP-speaking
2140
+ * agent runtime). The two surfaces use different tool *names* — the SDK's
2141
+ * tools are tuned for tool-calling conventions (`make_payment`,
2142
+ * `authorize_x402_payment`); the MCP tools follow the MCP `haven_*` naming
2143
+ * (`haven_pay_x402_quote`).
2144
+ *
2145
+ * The underlying *operations* are the same, so the descriptive prose should
2146
+ * live in one place. Both surfaces import from this module and compose their
2147
+ * own tool descriptions from these semantic fragments. Drift is caught by
2148
+ * tests asserting each consumer's description string contains the shared
2149
+ * `summary` from this module.
2150
+ */
2151
+ interface ToolDescription {
2152
+ /** One-line summary of the operation. Used as the first sentence of every
2153
+ * downstream description and as a stable substring for drift tests. */
2154
+ summary: string;
2155
+ /** Natural-language user intents that should make an agent prefer this
2156
+ * tool over adjacent tools. Empty or omitted when the summary is enough. */
2157
+ selectionGuidance?: string;
2158
+ /** Concrete behaviour the tool performs end-to-end, including which
2159
+ * non-custodial guarantee applies. */
2160
+ behavior: string;
2161
+ /** What the agent should do next on error / declined states.
2162
+ * Empty string if not applicable. */
2163
+ nextActionGuidance: string;
2164
+ }
2165
+ /**
2166
+ * Build a single description string from the three fragments. Joined with
2167
+ * spaces so consumers can split on the summary substring if they need to.
2168
+ */
2169
+ declare function composeDescription(d: ToolDescription): string;
2170
+ declare const toolDescriptions: {
2171
+ readonly quoteX402: {
2172
+ readonly summary: "Inspect an HTTP 402 x402 paid resource without creating a Haven payment, signature, approval, or on-chain transaction.";
2173
+ readonly behavior: "Probes the merchant directly and parses the 402 response. Pure read-only client behavior — Haven is not contacted.";
2174
+ readonly nextActionGuidance: "On success the returned quote is the input to haven_pay_x402_quote. Do not call the merchant again — Haven re-uses the captured request when paying.";
2175
+ };
2176
+ readonly payX402: {
2177
+ readonly summary: "Pay an inspected x402 quote. The delegate key signs locally; Haven only validates and relays signed, on-chain-constrained payment transactions.";
2178
+ readonly selectionGuidance: "Do not use this for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.";
2179
+ readonly behavior: "Signs the payment locally and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later.";
2180
+ readonly nextActionGuidance: string;
2181
+ };
2182
+ readonly payX402OneShot: {
2183
+ readonly summary: "Fetch an x402 paid HTTP resource in a single call. Handles the full probe -> pay -> retry round trip and returns the merchant response.";
2184
+ readonly selectionGuidance: "Prefer this over the quote+pay split when the agent just wants the paid resource and does not need to inspect the price first. If you already have a quote from haven_quote_x402, use haven_pay_x402_quote instead. Do not use for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.";
2185
+ readonly behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the payment locally, then retries the original request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only) and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later. If the resource returns a non-402 status, returns it unchanged without contacting Haven.";
2186
+ readonly nextActionGuidance: string;
2187
+ };
2188
+ readonly resumeX402: {
2189
+ readonly summary: "Resume an x402 payment whose Haven-side authorization already succeeded but whose merchant retry did not complete.";
2190
+ readonly behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the authorized Haven funding, and retries the merchant request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only). No new Haven payment is created.";
2191
+ readonly nextActionGuidance: string;
2192
+ };
2193
+ readonly getPaymentStatus: {
2194
+ readonly summary: "Fetch structured Haven payment status, including phase and nextAction taxonomy for agent recovery.";
2195
+ readonly behavior: "Accepts a payment intent id and returns the full state taxonomy (phase, nextAction, rail, amount, merchant, resource url, idempotency key, message).";
2196
+ readonly nextActionGuidance: "";
2197
+ };
2198
+ readonly getResumeState: {
2199
+ readonly summary: "Rehydrate stored x402 resume_state by payment_id.";
2200
+ readonly behavior: "Returns the x402 context the agent originally received when the payment was authorized, reconstructed from Haven's database. This is context only; signing still happens locally when a resume tool is called.";
2201
+ readonly nextActionGuidance: "";
2202
+ };
2203
+ readonly getAgent: {
2204
+ readonly summary: "Return the authenticated agent identity AND its live spend authority in one call: Haven wallet, delegate, chain, raw status, spend_authority_readiness, and per-token remaining allowance (atomic + human-readable). The recommended first call in a new session to confirm who you are and whether Haven will let you spend right now.";
2205
+ readonly selectionGuidance: "Use this as the one-shot orientation/bootstrap at the start of a session, or whenever you need to confirm identity together with whether the agent can spend right now. For a detailed per-token breakdown (configured vs spent vs reset window) use haven_get_allowances.";
2206
+ readonly behavior: "Reads identity plus the live spend-authority snapshot in one shot — the agent's active on-chain budget delegation. spend_authority_readiness (readiness is a deprecated alias, same value) is \"ready\" when at least one token has remaining spend authority, \"needs_approval\" when the agent is active but has none, and \"revoked\" when the credential is not active. It covers hosted identity + on-chain spend authority ONLY — the hosted server cannot see the LOCAL signer, so \"ready\" does not mean the signer can start; verify the signer with a signer tool call or connect --doctor. An over-budget payment is declined before any money moves: there is no approval queue, so ask the owner to grant or raise the budget in Haven rather than waiting for an approval. allowances[] carries remainingAtomic and remainingDisplay per token. Identity fields (id, name, status, safeAddress, delegateAddress, chainId) are unchanged from before.";
2207
+ readonly nextActionGuidance: "";
2208
+ };
2209
+ readonly getAllowances: {
2210
+ readonly summary: "Return configured and on-chain allowance state for the authenticated agent. On-chain allowance is the real spend gate.";
2211
+ readonly selectionGuidance: "Use this when the user asks about allowance, budget, spend limit, remaining amount, remaining allowance, remaining budget, daily limit, reset period, what can I spend, or what the agent can still spend.";
2212
+ readonly behavior: "Returns the per-token spend authority for the account: the active budget delegation (remaining = the period budget, which re-arms natively at the period boundary). An over-budget payment is declined before any money moves; nothing queues. Configured amounts from Haven are returned alongside.";
2213
+ readonly nextActionGuidance: "";
2214
+ };
2215
+ readonly listReceipts: {
2216
+ readonly summary: "List recent machine-payment receipts and evidence for bookkeeping.";
2217
+ readonly selectionGuidance: "Use this for transaction history, receipts, payment evidence, or bookkeeping; use the allowance tool instead for remaining allowance, budget, spend-limit, or what-can-I-spend questions.";
2218
+ readonly behavior: "Returns the agent's recent machine-payment receipts ordered by recency. Proof header values are not returned.";
2219
+ readonly nextActionGuidance: "";
2220
+ };
2221
+ readonly verifyReceipt: {
2222
+ readonly summary: "Verify a payment receipt offline — confirm the agent authorised the transfer.";
2223
+ readonly selectionGuidance: "Use this to check a receipt you already hold; it needs no network and does not trust Haven. Use the history tool to fetch receipts in the first place.";
2224
+ readonly behavior: "Recovers the signer from the receipt authorisation and confirms it matches the agent delegate. Returns verified true/false with the recovered signer or a reason. Pure and local — no backend call.";
2225
+ readonly nextActionGuidance: "";
2226
+ };
2227
+ readonly payMcpTool: {
2228
+ readonly summary: "Call a named tool on an MCP merchant that requires an x402 payment, handling the full initialize → pay → retry round trip in one call.";
2229
+ readonly selectionGuidance: string;
2230
+ readonly behavior: string;
2231
+ readonly nextActionGuidance: string;
2232
+ };
2233
+ readonly discoverTools: {
2234
+ readonly summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog — names, prices, and which pay tool to use next.";
2235
+ readonly selectionGuidance: string;
2236
+ readonly behavior: string;
2237
+ readonly nextActionGuidance: "Pick an entry and pay it with the tool named in suggested_tool, passing the entry's resource_url, tool_name, and tool_arguments for MCP merchants. Confirm the price from the live pay-tool result (not the catalog), and pass the user's cap as max_amount_human in whole tokens (\"no more than 1 USDC\" → max_amount_human: \"1\") — never convert it to atomic units by hand.";
2238
+ };
2239
+ readonly submitCatalogEntry: {
2240
+ readonly summary: "Submit a merchant's payable (x402/MCP) endpoint to Haven's Verified Payable Directory for verification and listing.";
2241
+ readonly selectionGuidance: string;
2242
+ readonly behavior: string;
2243
+ readonly nextActionGuidance: "Give the verify_token and the well-known instructions (from getCatalogSubmissionStatus) to the merchant so they can publish the proof line, then poll the submission status until it reaches verified_payable or failed.";
2244
+ };
2245
+ readonly sweep_delegate: {
2246
+ readonly summary: "Sweep stranded USDC and/or ETH from the delegate wallet back to the originating Safe.";
2247
+ readonly selectionGuidance: string;
2248
+ readonly behavior: string;
2249
+ readonly nextActionGuidance: string;
2250
+ };
2251
+ readonly send: {
2252
+ readonly summary: "Send ETH or USDC directly from the agent's Haven wallet to a recipient address.";
2253
+ readonly selectionGuidance: string;
2254
+ readonly behavior: string;
2255
+ readonly nextActionGuidance: string;
2256
+ };
2257
+ };
2258
+ type SharedToolKey = keyof typeof toolDescriptions;
2259
+
2260
+ /**
2261
+ * The generic Haven payment skill — canonical copy.
2262
+ *
2263
+ * This SDK file is the single source of truth for the generic, secret-free
2264
+ * skill content: no wallet address, no budget numbers, no per-agent values.
2265
+ * The agent learns its live budget at runtime via the `haven_get_agent` /
2266
+ * `haven_get_allowances` MCP tools, and can read identity + configured budget
2267
+ * for fast first-turn orientation from the non-secret `agent.json` the
2268
+ * connector writes (see `packages/connect/src/storage.ts`), so the same file
2269
+ * works for every user. `packages/connect` imports this directly to
2270
+ * auto-install the skill into runtime skills folders.
2271
+ *
2272
+ * `packages/frontend/src/lib/agent-skill-bundle.ts` keeps a deliberately
2273
+ * decoupled inline copy (the download fallback): frontend has zero
2274
+ * `@haven_ai/*` dependencies so it can deploy standalone on Vercel without an
2275
+ * unpublished SDK export. A parity test in that package's test suite imports
2276
+ * this canonical string and asserts byte-for-byte equality, so the two copies
2277
+ * cannot drift.
2278
+ */
2279
+ declare const HAVEN_SKILL_MD = "---\nname: haven-pay\ndescription: Pay for things from the user's Haven wallet within their agent rules. Use when the user asks to send, pay, tip, or transfer crypto \u2014 or when a request hits an HTTP 402 (x402) paywall.\n---\n\n# Haven: pay from a Haven wallet\n\nThis skill lets the agent make payments from the user's Haven wallet through\nthe Haven MCP tools. Every payment is checked against the agent's on-chain\nbudget before money moves; a payment above the remaining budget is declined \u2014\nnothing is paid past the rules the user set.\n\nHosted tools run in the `mcp__haven__` namespace. Local signing tools run in\nthe `mcp__haven-signer__` namespace and keep the delegate key on this machine.\nThat namespacing is Claude-family; other runtimes name the servers by their\nown config keys (Codex: `haven`, `haven_signer`). Tool results carry the\nexact next step (`next_action`, `next_tool`, `next_arguments`, plus the\nruntime-neutral `next_tool_server` + `next_tool_name` \u2014 the bare tool name\non that logical server, whatever your runtime calls it).\nFollow those fields first; the prose below is fallback and orientation, not\nthe source of truth.\n\n## When to use this skill\n\n- The user asks to send money, pay someone, tip, donate, or transfer tokens.\n- A request returns HTTP 402 (x402): use the Haven pay tools to settle it,\n then retry the original request.\n\n## Identity and budget\n\nDo not guess the wallet address, network, or budget.\n\nFor instant orientation at the start of a session, read the non-secret\n`agent.json` the connector wrote to your Haven credential directory (typically\n`~/.haven/agents/<agent-id>/agent.json` \u2014 if you don't know the agent id, list\n`~/.haven/agents/` to find the folder). It\nholds your agent id, Haven wallet address, network, and *configured* per-token\nbudget, and contains no keys \u2014 the fastest way to answer \"who am I and what may\nI spend\" with no round trip. If that file is absent (some setups don't write\nit), use the tools below instead.\n\nBefore any payment, confirm the *live remaining* budget with the tools \u2014\n`agent.json` shows the configured budget, not what is left after recent\nspending:\n\n- `mcp__haven__haven_get_agent` \u2014 the recommended first call: identity\n (wallet, network) plus `spend_authority_readiness` (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot. That signal\n covers hosted identity and on-chain spend authority only \u2014 it cannot see the\n local signer; the signer is verified by calling any signer tool.\n- `mcp__haven__haven_get_allowances` \u2014 detailed per-token breakdown\n (configured, spent, reset window) when you need more than the summary.\n\nBudgets reset on a period the user chose. If a payment exceeds the remaining\nbudget it is declined before any money moves \u2014 tell the user; they can raise\nthe budget in the Haven dashboard, or wait for the period reset.\n\n## Paying\n\n**Catalog purchases \u2014 the primary path for MCP merchants:**\n\n1. `mcp__haven__haven_discover_tools` to find a payable service and its\n `catalog_id`.\n2. If the user needs the live price before authorizing a cap, call\n `mcp__haven__haven_quote_catalog_purchase` with `catalog_id`. It is\n read-only and informational only: it never reserves a price or creates a\n payment. Tell the user its `amount` / `amount_atomic`, then choose a cap.\n3. `mcp__haven__haven_prepare_catalog_purchase` with `catalog_id` and a\n spending cap. A cap is REQUIRED on this tool and is best practice on every\n paid call below too \u2014 it caps what the LIVE merchant quote may charge,\n checked before any funding intent is created. Write it the way the user\n said it: `max_amount_human` is whole tokens, so \"no more than 1 USDC\" is\n `max_amount_human: \"1\"`. (`max_amount` is the atomic-unit form, where\n \"1\" means 0.000001 USDC \u2014 do not convert by hand, and never send both.)\n4. Then FOLLOW THE RESPONSE'S GUIDANCE FIELDS: `next_action`, `next_tool`,\n and `next_arguments` name the exact next call \u2014 act on those first; the\n prose in this section is fallback and debugging detail. If the catalog\n entry is missing or degraded, the response instead names\n `mcp__haven__haven_pay_mcp_tool` (merchant URL, tool name, arguments) as\n the manual fallback.\n\n**Signing:** `mcp__haven-signer__haven_sign_x402` with `payment_id` ONLY \u2014\nthe local signer fetches the exact signing bytes AND `payment_required`\nitself, so never relay `typed_data` or the 402 blob yourself. If the signer\nreports its fetched context carried no `payment_required` (older backend),\nre-call with `payment_required` added verbatim. Fallback for an older signer\nor backend: re-run the quote/prepare tool with the SAME `idempotency_key`\nplus `include_signing_payload=true`, then pass `payload_hash`,\n`x402_expected` (the nested `x402.expected` object), and\n`typed_data`/`typed_data_b64` through unchanged.\n\n**Settle:** `mcp__haven__haven_settle_mcp_tool` with `payment_id`,\n`signature`, and `payment_header` ONLY \u2014 Haven rehydrates the merchant call\ncontext (`merchant_url`, `tool_name`, `arguments`, `mcp_transport`)\nserver-side from `payment_id`. Pass those four fields explicitly only as a\nversion-skew fallback when Haven has no stored context for the id \u2014 both or\nnone together, never just one. If the settle result carries `settled: false`,\nfunding has not confirmed \u2014 follow the result's guidance fields and check\nstatus later, do not re-pay.\n\nStep-by-step alternative (also key-safe; for an older signer or backend, or\nwhen you already have a merchant URL and tool name instead of a\n`catalog_id`): if the user needs the live price before choosing a cap, first\ncall `mcp__haven__haven_quote_mcp_tool` with that merchant URL, tool name,\nand arguments. It is informational only; then call\n`mcp__haven__haven_pay_mcp_tool` with the same inputs and the explicit cap.\nThe paid call always obtains a fresh quote before it creates any intent. Then\ncontinue `mcp__haven__haven_pay_mcp_tool` \u2192\n`mcp__haven-signer__haven_sign` \u2192 `mcp__haven__haven_submit` \u2192\n`mcp__haven-signer__haven_x402_sign_header` \u2192\n`mcp__haven__haven_complete_mcp_tool`. Call that last step with\n`payment_id` and the signer's `payment_header` ONLY. It does not take\n`payment_required`: Haven rehydrates the merchant call context\n(`merchant_url`, `tool_name`, `arguments`, `mcp_transport`) and the\n402 server-side from `payment_id`, exactly as at settle. Pass that context\nexplicitly only as a version-skew fallback when Haven has no stored context\nfor the id \u2014 `merchant_url` and `tool_name` both or none together, never\njust one.\nThe returned `expires_at` is the signing window; if a tool returns\n`PAYMENT_WINDOW_EXPIRED`, re-run the same quote/prepare tool with the same\n`idempotency_key`. Do not call the merchant yourself \u2014 Haven completes the\nmerchant leg for you.\n\n**Direct transfer / non-MCP paywall:** `mcp__haven__haven_pay` with\n`to`, `amount`, and `token` for a plain transfer. For an arbitrary,\nnon-MCP x402 paywall: `mcp__haven__haven_quote_x402` to get a quote, then\n`mcp__haven__haven_pay_x402_quote` \u2014 follow the result's guidance fields\nfirst and sign in the local Haven signer. On THIS path Haven does not talk to\nthe merchant: `mcp__haven-signer__haven_sign_x402` returns both\n`signature` and `payment_header`; relay `signature` with\n`mcp__haven__haven_submit`, then retry the paywalled URL yourself with\n`payment_header`. Do not pass that call's `x402_binding` to\n`mcp__haven-signer__haven_x402_sign_header` \u2014 the one-shot already spent it\nbuilding the header, so the call can only refuse. Then tell Haven what the\nmerchant answered: `mcp__haven__haven_report_x402_outcome` with the\n`payment_id`, `outcome` (`\"accepted\"` for a 2xx, else `\"rejected\"`)\nand the `merchant_status` you got. Because Haven never contacted that\nmerchant, this is the only way it can learn the purchase failed \u2014 without it a\nfailed purchase reads as complete for fifteen minutes. (The SDK's own\n`haven_pay_x402` tool does perform the merchant retry itself; that tool is\nnot part of the hosted MCP surface.) If the process\ncrashes after payment, a later `mcp__haven__haven_get_payment_status` call\nmay report `nextAction: 'retry_original_x402_request'` \u2014 only then call\n`mcp__haven__haven_resume_x402_payment` with the preserved resume state or\npayment id, instead of paying again.\n\n**Catalog tool arguments:** when `haven_discover_tools` returns\n`tool_arguments`, pass that object unchanged as the pay tool's\n`arguments` field (for example\n`tool_arguments: { \"tier\": \"50gb\" }` -> `arguments: { \"tier\": \"50gb\" }`).\n\n**Prices:** show the user the live price from a read-only quote or the pay-tool\nresult, never a catalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. A read-only quote is informational\nonly and does not reserve a price; the later paid call re-quotes and enforces\nthe cap. The pay-tool result's `amount` / `amount_atomic` is the merchant's\nown quoted price for that call \u2014 a ceiling the merchant settles at or below \u2014\nso present it as the most the user will pay. It is a price, not an approval:\nthe payment goes through only if it also fits the cap you set and the on-chain\nbudget the user signed, which is enforced on-chain rather than by Haven.\n\n**Status:** `mcp__haven__haven_get_payment_status` with a `payment_id` to\ncheck on in-flight payments. Do not poll in a tight loop.\n\n## Declines and stop signals\n\n- A payment outside the agent's rules \u2014 above the remaining budget, wrong\n recipient, or expired budget \u2014 is declined before any money moves. Nothing\n is queued; tell the user, who can raise the budget in Haven.\n- `safe_to_continue: false` on a guidance block is a stop signal in\n machine-readable form: stop and involve the user before calling anything\n else for this payment.\n- Never ask the user for private keys. Signing happens only in the local Haven\n signer; the hosted Haven tools never receive the signing key. If a tool\n reports a missing or invalid credential, tell the user to re-run the Haven\n setup command.\n\n## Failure handling\n\nHaven tool failures are shaped like `{ success: false, code, message, ... }`\nor older `{ error, status, details? }` responses. Branch on `code` when\npresent and surface `message` or `error` verbatim. Common cases:\n\n- `insufficient_funds`: the Haven wallet doesn't hold enough of that token.\n Suggest the user add funds in the Haven dashboard.\n- `PRICE_EXCEEDS_MAX`: the live merchant price exceeded your cap. No funds\n moved; ask the user before retrying with a higher one.\n- `AMBIGUOUS_MAX_AMOUNT`: you sent both `max_amount` and\n `max_amount_human`. Nothing was contacted or spent \u2014 re-send with exactly\n one (`max_amount_human` for a cap the user stated in tokens).\n- `MAX_AMOUNT_UNCONVERTIBLE`: `max_amount_human` does not fit this quote's\n asset \u2014 unknown decimals, or more decimal places than the asset supports.\n Round the cap, or send an exact atomic `max_amount`.\n- `PAYMENT_WINDOW_EXPIRED`: re-run the quote/prepare tool with the same\n `idempotency_key`, then sign the fresh payload.\n- `MERCHANT_REJECTED_AFTER_FUNDING`: the merchant refused the paid retry.\n Stop-and-sweep \u2014 stop retrying the merchant and use\n `mcp__haven__haven_sweep_delegate` to recover stranded delegate funds.\n- `MERCHANT_UNRESPONSIVE_AFTER_FUNDING`: funding confirmed on-chain, but the\n merchant never answered the paid retry. This is NOT proof of rejection \u2014 the\n merchant may still settle late. Verify-then-sweep, never a blind sweep:\n check `mcp__haven__haven_get_payment_status`, retry\n `mcp__haven__haven_complete_mcp_tool` ONCE, and only sweep with\n `mcp__haven__haven_sweep_delegate` if no settlement appears.\n- Budget exceeded: tell the user how much remains (from\n `mcp__haven__haven_get_allowances`) and that they can raise the budget in\n Haven.\n\n## Reporting after a purchase\n\nA settled `mcp__haven__haven_settle_mcp_tool` response carries\n`agent_summary.purchase_summary` and the remaining post-purchase allowance\nin `allowance` \u2014 report the product, Haven-derived payment/transaction\nfields, and what is left from those fields directly. `result` is optional\nraw merchant evidence; never use it to decide whether the purchase was paid.\nDo not call `haven_get_agent` or `haven_get_allowances` again just to\nreport a purchase you already made.\n\n## Revoke\n\nIf this agent's credential may have leaked, tell the user to pause or revoke\nthe agent in the Haven dashboard under Agents. New requests stop immediately\nfor that credential.\n";
2280
+ /** Directory name for the installed skill folder. */
2281
+ declare const SKILL_FOLDER_NAME = "haven-pay";
2282
+ /**
2283
+ * The skill BODY — HAVEN_SKILL_MD with the YAML front-matter stripped.
2284
+ *
2285
+ * For runtimes whose instruction mechanism is a plain guidance file rather
2286
+ * than a skills folder (Codex's global AGENTS.md, #1332), the front-matter is
2287
+ * skill-registry metadata with no meaning and would render as a stray table.
2288
+ * Derived mechanically from the canonical string above, never maintained by
2289
+ * hand — the substance cannot fork per runtime.
2290
+ */
2291
+ declare const HAVEN_SKILL_BODY_MD: string;
2292
+
2293
+ /**
2294
+ * The npm dist-tag the published Haven packages tell a user to re-run (#2423,
2295
+ * slice 3 of epic #2420).
2296
+ *
2297
+ * ## Why a constant and not a literal
2298
+ *
2299
+ * Roughly a dozen user- and agent-facing strings across `@haven_ai/sdk`,
2300
+ * `@haven_ai/signer`, `@haven_ai/connect` and the hosted MCP server say some
2301
+ * form of "re-run `npx @haven_ai/connect@alpha`". Every one of them was a
2302
+ * hard-coded literal, which is correct only for a build published under the
2303
+ * `alpha` dist-tag. Once `dev`-branch snapshots publish under a `dev` tag
2304
+ * (#2421), a snapshot build telling its tester to re-run `@alpha` would hand
2305
+ * them the production connector — silently replacing the very build they are
2306
+ * testing. So the tag becomes one build-time constant and every hint derives
2307
+ * from it.
2308
+ *
2309
+ * ## Who writes it
2310
+ *
2311
+ * `scripts/release-bump.mjs` rewrites {@link HAVEN_CONNECTOR_CHANNEL} from the
2312
+ * version it is bumping to, using exactly the rule `.github/workflows/publish.yml`
2313
+ * uses to pick the `--tag` for that same version:
2314
+ *
2315
+ * | version | dist-tag / channel |
2316
+ * |---|---|
2317
+ * | `0.1.34-alpha.0` | `alpha` |
2318
+ * | `0.0.0-dev.202609021200.abc1234` | `dev` |
2319
+ * | `0.2.0` | `latest` |
2320
+ *
2321
+ * One rule, two consumers. `scripts/ci/connector-channel-agreement.test.mjs`
2322
+ * executes the workflow's own shell and the bump script's own function over the
2323
+ * same version table and fails if they ever disagree.
2324
+ *
2325
+ * ## Build-time here, run-time there
2326
+ *
2327
+ * A published tarball cannot read a deployment's environment, so for the
2328
+ * published packages the channel is baked in at release time. A surface that is
2329
+ * *deployed* rather than published has no release at which to bake anything in,
2330
+ * so it reads the `HAVEN_CONNECTOR_CHANNEL` environment variable and falls back
2331
+ * to this constant. Two surfaces do that: the hosted MCP server
2332
+ * (`packages/mcp-server/src/connector-channel.ts`) and, since slice 2 (#2422),
2333
+ * the backend's connector handout (`parseConnectorChannel` in
2334
+ * `packages/backend/src/config.ts`). All three readers share one variable name,
2335
+ * one default and one validation pattern, and that agreement is EXECUTED rather
2336
+ * than asserted: `packages/backend/src/__tests__/connector-channel.test.ts`
2337
+ * runs this module's `resolveConnectorChannel` and the backend's
2338
+ * `parseConnectorChannel` over the same input table and fails if they ever
2339
+ * diverge.
2340
+ *
2341
+ * **This says nothing about how any environment is configured.** Setting the
2342
+ * variable anywhere is an operator action (epic #2420, operator step 3); no
2343
+ * code here can observe it and none of this comment asserts it has happened.
2344
+ */
2345
+ /** The published connector package. Never varies; only its tag does. */
2346
+ declare const CONNECTOR_PACKAGE_NAME = "@haven_ai/connect";
2347
+ /**
2348
+ * The npm dist-tag this build's re-run hints name.
2349
+ *
2350
+ * **Do not hand-edit.** `scripts/release-bump.mjs` owns this literal the same
2351
+ * way it owns `CONNECTOR_VERSION` and its siblings, and
2352
+ * `scripts/release-bump.test.mjs` fails if the two drift.
2353
+ */
2354
+ declare const HAVEN_CONNECTOR_CHANNEL = "dev";
2355
+ /** True when `value` is a well-formed dist-tag. */
2356
+ declare function isConnectorChannel(value: string): boolean;
2357
+ /**
2358
+ * Resolve a channel from a deployment's `HAVEN_CONNECTOR_CHANNEL`.
2359
+ *
2360
+ * - unset, empty or whitespace ⇒ `fallback` (dashboards store a cleared
2361
+ * variable as `""`, and that must land on the production-safe value);
2362
+ * - well-formed ⇒ itself;
2363
+ * - anything else ⇒ **throws**. It does not quietly fall back: a typo such as
2364
+ * `dve` would then land on the production channel, and the environment would
2365
+ * look fixed while reproducing the exact defect this slice removes.
2366
+ *
2367
+ * Well-formed-but-wrong (`dve` again) is *not* caught here and cannot be — it
2368
+ * fails later at `npx`, where the error names the package. Stated rather than
2369
+ * implied.
2370
+ */
2371
+ declare function resolveConnectorChannel(raw: string | undefined | null, fallback?: string): string;
2372
+ /** `@haven_ai/connect@<channel>` — the spec an `npx` invocation names. */
2373
+ declare function connectorSpec(channel?: string): string;
2374
+ /**
2375
+ * The re-run command every hint embeds.
2376
+ *
2377
+ * `connectorRerunCommand()` → `npx @haven_ai/connect@alpha`
2378
+ * `connectorRerunCommand('--doctor')` → `npx @haven_ai/connect@alpha --doctor`
2379
+ *
2380
+ * `args` is appended verbatim so each call site keeps its own flags and its own
2381
+ * surrounding sentence. The wording of those sentences is deliberately NOT
2382
+ * moved here: several are inside signer refusal messages that users and agents
2383
+ * pattern-match on, and this change is meant to move the channel token and
2384
+ * nothing else.
2385
+ */
2386
+ declare function connectorRerunCommand(args?: string, options?: {
2387
+ channel?: string;
2388
+ npxFlags?: string;
2389
+ }): string;
2390
+
2391
+ /**
2392
+ * The Node.js floor Haven's published packages support (#1161).
2393
+ *
2394
+ * ## Why this lives in the SDK
2395
+ *
2396
+ * Three packages need to enforce the same floor — `connect` (at setup),
2397
+ * `signer` and `mcp` (at startup) — and `@haven_ai/sdk` is the only dependency
2398
+ * all three already share. A copy per package is how the floor drifted in the
2399
+ * first place: `engines` said `>=24` everywhere while connect's runtime manifest
2400
+ * enforced `20.0.0`, so a connect run on Node v23 passed the guard, installed
2401
+ * the signer, and signed a real payment. Two numbers for one fact is one number
2402
+ * too many.
2403
+ *
2404
+ * Each consumer still owns its own refusal — the error type, the exit code, the
2405
+ * wording of "what to do next" — because a library must never terminate its
2406
+ * host process. This module only answers *is this version supported* and *what
2407
+ * should we tell the user*.
2408
+ *
2409
+ * ## Why a floor is enforced at all
2410
+ *
2411
+ * `engines` is advisory: npm emits `EBADENGINE` and installs anyway unless the
2412
+ * user happens to have `engine-strict` set. For a normal library that is a
2413
+ * reasonable default. For the **signer** it is not — it holds the delegate key
2414
+ * and produces every payment signature, so a subtle runtime incompatibility
2415
+ * shows up as a wrong or missing signature on a money path. "It seemed to work"
2416
+ * is precisely the evidence that cannot be relied on there.
2417
+ */
2418
+ /**
2419
+ * The minimum supported Node.js version, as `major.minor.patch`.
2420
+ *
2421
+ * MUST equal the `engines.node` floor declared by every published Haven
2422
+ * package. A guard test in each package asserts exactly that against its own
2423
+ * `package.json`, so the two cannot drift again silently.
2424
+ */
2425
+ declare const HAVEN_MINIMUM_NODE_VERSION = "22.0.0";
2426
+ /**
2427
+ * Compare two Node versions. Negative when `left` is older.
2428
+ *
2429
+ * An unparseable version parses to `0.0.0` and therefore compares as older than
2430
+ * any real floor — fail-closed. A version string Haven cannot read is not
2431
+ * evidence of a supported runtime, and treating it as one would reopen exactly
2432
+ * the hole this module closes.
2433
+ */
2434
+ declare function compareNodeVersions(left: string, right: string): number;
2435
+ declare function isSupportedNodeVersion(nodeVersion?: string, minimumNodeVersion?: string): boolean;
2436
+ interface UnsupportedNodeVersionMessageOptions {
2437
+ /**
2438
+ * What is being refused, in the user's terms — "Haven setup", "The Haven
2439
+ * signer". Leads the message so the reader knows what just stopped.
2440
+ */
2441
+ subject: string;
2442
+ nodeVersion?: string;
2443
+ minimumNodeVersion?: string;
2444
+ /** Appended verbatim as the closing line. Used for the re-run instruction. */
2445
+ retryHint?: string;
2446
+ }
2447
+ /**
2448
+ * The refusal text.
2449
+ *
2450
+ * Names the detected version, the required version, and **how to fix it** — the
2451
+ * previous message stopped after the two version numbers, which tells a user
2452
+ * they are stuck without telling them how to get unstuck. The version-manager
2453
+ * lines are the fix for nearly everyone; the closing caveat is there because the
2454
+ * runtime that *spawns* the signer is frequently not the shell that was
2455
+ * upgraded, and a desktop app can keep launching the old Node long after
2456
+ * `node -v` in a terminal says otherwise.
2457
+ */
2458
+ declare function unsupportedNodeVersionMessage(options: UnsupportedNodeVersionMessageOptions): string;
2459
+
2460
+ /**
2461
+ * x402 protocol support for the Haven SDK.
2462
+ *
2463
+ * Provides:
2464
+ * - parsePaymentRequired() — extract payment requirements from a 402 response
2465
+ * - parsePaymentRequiredResponse() — async parser with JSON body fallback
2466
+ * - encodePaymentProof() — encode a receipt as a PAYMENT-SIGNATURE header
2467
+ *
2468
+ * The main authorizeX402() and fetchWithPayment() are methods on HavenClient
2469
+ * (see client.ts) since they need API access and signing.
2470
+ */
2471
+
2472
+ /**
2473
+ * Persisted, agent-scoped facts used to preflight a signed standard x402
2474
+ * payment header. This is an integrity comparison only: it never rebuilds,
2475
+ * modifies, persists, or submits the supplied authorization.
2476
+ */
2477
+ interface X402PaymentHeaderContext {
2478
+ merchantTo: string;
2479
+ amountAtomic: string;
2480
+ asset: string;
2481
+ network: string;
2482
+ resourceUrl: string;
2483
+ payer: string;
2484
+ chainId: number;
2485
+ }
2486
+ /** A deliberately value-free refusal for untrusted payment-header input. */
2487
+ declare class X402PaymentHeaderValidationError extends Error {
2488
+ constructor();
2489
+ }
2490
+ /**
2491
+ * Upper bound on the MERCHANT-requested part of the EIP-3009 authorization
2492
+ * window (#715, epic #713). The x402 library sets
2493
+ * `validBefore = now + maxTimeoutSeconds` straight from the MERCHANT's 402
2494
+ * challenge — without a cap, a malicious or sloppy merchant can request a
2495
+ * year-long window and a leaked signed authorization stays spendable that
2496
+ * whole time. 600 s is generous for any facilitator settle (typical is
2497
+ * 30–60 s); we CLAMP rather than reject so payments keep flowing while
2498
+ * exposure stays bounded. `validBefore` is a deadline, not a demand —
2499
+ * settling earlier is always valid.
2500
+ */
2501
+ declare const X402_MAX_AUTHORIZATION_WINDOW_SECONDS = 600;
2502
+ /**
2503
+ * Forward margin ADDED on top of the (clamped) merchant timeout when the
2504
+ * authorization is actually signed (#1256). The x402 verify rule requires
2505
+ * `validBefore ≥ now + maxTimeoutSeconds` AT THE FACILITATOR — but the
2506
+ * upstream library computes `validBefore = now + maxTimeoutSeconds` at
2507
+ * SIGNING time, leaving zero forward margin. Haven's flow guarantees elapsed
2508
+ * time between the two (the funding UserOp confirms before the merchant
2509
+ * retry, ~1 min plus latency), so every purchase against a merchant whose
2510
+ * `maxTimeoutSeconds` exceeded that latency failed structurally — measured
2511
+ * live on Base mainnet: Anchor requires 300 s, and 226 s remained at verify.
2512
+ *
2513
+ * 300 s covers funding + retry latency with room to spare. The #715 exposure
2514
+ * ceiling becomes clamped-timeout + margin ≤ 900 s total forward — a
2515
+ * deliberate widening from 600 s, recorded on #1256: an authorization that
2516
+ * cannot pass verify protects no one, and 900 s is still bounded by the same
2517
+ * clamp discipline.
2518
+ */
2519
+ declare const X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = 300;
2520
+ declare function normalizePaymentRequired(value: unknown): X402PaymentRequired | null;
2521
+ /**
2522
+ * The x402 wire header names, in one place (#2289).
2523
+ *
2524
+ * v2 renamed all three; v1's only name was `X-PAYMENT`, used in BOTH
2525
+ * directions. Haven had adopted the v2 names for everything it *reads* and
2526
+ * kept the v1 name for the one thing it *writes*, which is how a strict v2
2527
+ * merchant came to never see a payment header at all.
2528
+ *
2529
+ * The 2026-08-31 owner decision was to send both outbound names on every
2530
+ * retry rather than switch on `x402Version`: a v1 merchant ignores the name it
2531
+ * does not know, a v2 merchant ignores the legacy one, and no version
2532
+ * heuristic has to be right for a payment to land.
2533
+ *
2534
+ * **That is no longer unconditional (#2341).** It held while the cost of a
2535
+ * spare header was zero, and on the EIP-3009 bridge it still is. On erc7710 it
2536
+ * is not: that header carries a whole delegation chain, and duplicating it
2537
+ * overflowed the merchant's header limit — HTTP 431, every erc7710 settlement
2538
+ * refused. `x402PaymentHeaderNamesFor` below is the live rule; read it rather
2539
+ * than this paragraph, which records why the simpler rule was right first.
2540
+ */
2541
+ /** v2 client→server payment payload. The name a strict v2 merchant reads. */
2542
+ declare const X402_PAYMENT_HEADER_NAME = "PAYMENT-SIGNATURE";
2543
+ /** v1 client→server payment payload; still accepted by most v2 merchants. */
2544
+ declare const X402_LEGACY_PAYMENT_HEADER_NAME = "X-PAYMENT";
2545
+ /** v2 server→client payment requirements. */
2546
+ declare const X402_PAYMENT_REQUIRED_HEADER_NAME = "PAYMENT-REQUIRED";
2547
+ /** v2 server→client settlement receipt. */
2548
+ declare const X402_PAYMENT_RESPONSE_HEADER_NAME = "PAYMENT-RESPONSE";
2549
+ /**
2550
+ * Both wire names, v2 first — the value an EIP-3009 retry actually sends.
2551
+ *
2552
+ * **Not the general answer any more (#2341), and not what a recorder should
2553
+ * reach for.** This was the evidence record's `paymentProofHeaderName` while
2554
+ * both names always went on the wire; erc7710 now sends one, so a recorder
2555
+ * still reading this constant would log a legacy header that was never sent —
2556
+ * exactly the drift the previous wording promised it prevented. Use
2557
+ * `x402PaymentHeaderNamesSent(paymentHeader)`. Kept exported because it is a
2558
+ * published surface and removing it would break consumers.
2559
+ */
2560
+ declare const X402_PAYMENT_HEADER_NAMES_SENT = "PAYMENT-SIGNATURE, X-PAYMENT";
2561
+ /**
2562
+ * The x402 v2 payment envelope: `{x402Version, resource?, accepted, payload,
2563
+ * extensions?}` per the spec's PaymentPayload (§5.2.2).
2564
+ *
2565
+ * The `resource` and `extensions` echoes are the #2361 fix, and they are not
2566
+ * optional politeness: the spec makes the extensions echo a MUST ("the client
2567
+ * must include at least the info received"), and CoinGecko's facilitator was
2568
+ * live-bisected rejecting the echo-less envelope with a bare 400 while
2569
+ * accepting the identical signature and `accepted`/`payload` bytes with the
2570
+ * echoes added (#2360, Base mainnet, 2026-09-01). Both objects are echoed
2571
+ * VERBATIM from the merchant's 402 — never reconstructed — and omitted when
2572
+ * the challenge carries none, which keeps the envelope byte-identical to the
2573
+ * pre-#2361 shape for echo-less merchants (Ampersend and Soundside settled
2574
+ * that shape live, so omission is the proven-compatible default).
2575
+ *
2576
+ * The `accepted` wrap itself is #303's shape and predates this helper — see
2577
+ * the #300/#303 history before "fixing" it: scheme/network live INSIDE
2578
+ * `accepted` in v2, never at the top level.
2579
+ */
2580
+ declare function x402V2PaymentEnvelope(paymentRequired: Pick<X402PaymentRequired, 'x402Version' | 'resource' | 'extensions'>, accepted: X402PaymentOption, payload: unknown): Record<string, unknown>;
2581
+ /**
2582
+ * Parse an HTTP 402 response into x402 PaymentRequired data.
2583
+ *
2584
+ * Supports:
2585
+ * - v2: PAYMENT-REQUIRED header (base64 JSON)
2586
+ * - v1 fallback: X-PAYMENT header or response body
2587
+ */
2588
+ declare function parsePaymentRequired(response: Response): X402PaymentRequired;
2589
+ /**
2590
+ * Parse an HTTP 402 response into x402 PaymentRequired data.
2591
+ *
2592
+ * Soundside and other Bazaar-style MCP endpoints return the PaymentRequired
2593
+ * object in the JSON body, while older Haven demos and many x402 examples use
2594
+ * base64 headers. This keeps the synchronous header parser intact and adds the
2595
+ * body fallback needed for those endpoints.
2596
+ */
2597
+ declare function parsePaymentRequiredResponse(response: Response): Promise<X402PaymentRequired>;
2598
+ /**
2599
+ * Select the best payment option from the x402 accepts array.
2600
+ *
2601
+ * Preference order:
2602
+ * 1. Option on a Haven-supported network with a known token
2603
+ * 2. Any option on a Haven-supported network
2604
+ * 3. null — no compatible option
2605
+ */
2606
+ declare function selectPaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
2607
+ /** The `extra.assetTransferMethod` value that marks an erc7710-settleable entry. */
2608
+ declare const ERC7710_ASSET_TRANSFER_METHOD = "erc7710";
2609
+ /**
2610
+ * Read `extra.assetTransferMethod` defensively. `extra` is the merchant's own
2611
+ * object, so it is untrusted shape: anything that is not the exact string is
2612
+ * treated as "not erc7710" rather than coerced.
2613
+ */
2614
+ declare function x402AssetTransferMethod(option: X402PaymentOption): string | null;
2615
+ /** True when the merchant advertises this entry as erc7710-settleable. */
2616
+ declare function isErc7710Option(option: X402PaymentOption): boolean;
2617
+ /**
2618
+ * The facilitator addresses a merchant advertises for an erc7710 entry, for
2619
+ * the #1058 redeemer pin — or `null` when it pins nothing.
2620
+ *
2621
+ * **An EMPTY array is `null`, not `[]`.** The backend rejects an empty
2622
+ * `redeemers` list with a 400 (`routes/x402.ts`), and the QA scenario already
2623
+ * treats empty as absent. Returning `[]` here would hand callers a value that
2624
+ * means "pin to nobody" — which is not a narrower pin, it is an unbuildable
2625
+ * delegation.
2626
+ *
2627
+ * Malformed entries are DROPPED rather than failing the whole option, and that
2628
+ * asymmetry is deliberate. A pin narrowed by a merchant's typo means the
2629
+ * facilitator that actually tries to redeem is not on the list, so redemption
2630
+ * reverts — and erc7710 has no funding leg, so nothing moved and nothing is
2631
+ * stranded. Refusing the option outright would instead deny a payment the
2632
+ * remaining valid facilitators could have settled. Losing the payment is the
2633
+ * worse outcome, precisely because the failure this issue closes (#1453) is the
2634
+ * one where funds move BEFORE the rejection.
2635
+ */
2636
+ declare function x402FacilitatorAddresses(option: X402PaymentOption): string[] | null;
2637
+ /**
2638
+ * Select an option that can be paid with the official x402 EIP-3009 exact
2639
+ * scheme. Haven's older tx-hash proof path can describe more networks; the
2640
+ * merchant-verified path currently needs Base USDC.
2641
+ *
2642
+ * **Skips erc7710-tagged entries (#1453).** It used to return the first
2643
+ * positional match and never look at `extra.assetTransferMethod`, so a merchant
2644
+ * that listed its erc7710 entry first made a Haven client echo that option
2645
+ * while signing a standard EIP-3009 authorization. The merchant rejects the
2646
+ * mismatch cleanly — but on the legacy two-leg the Safe→delegate funding
2647
+ * transfer has already executed, so the visible result is a stranded delegate
2648
+ * balance for the sweep to reclaim. Only our own demo merchant's ordering was
2649
+ * holding that shut, and that pin binds our merchant, not the ones we do not
2650
+ * control.
2651
+ */
2652
+ declare function selectStandardPaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
2653
+ /**
2654
+ * Select the erc7710-settleable option, if the merchant advertises one.
2655
+ */
2656
+ declare function selectErc7710PaymentOption(accepts: X402PaymentOption[]): X402PaymentOption | null;
2657
+ /** What a settlement-scheme decision resolved to. */
2658
+ interface X402SchemeSelection {
2659
+ scheme: 'erc7710' | 'eip3009';
2660
+ option: X402PaymentOption;
2661
+ /** Redeemer pin for the settlement child; only ever set on erc7710. */
2662
+ facilitatorAddresses: string[] | null;
2663
+ }
2664
+ /**
2665
+ * THE preference rule, in one place (#1450 owner decision, #1453).
2666
+ *
2667
+ * Prefer erc7710 whenever the account is on the delegation rail and the
2668
+ * merchant advertises `extra.assetTransferMethod: "erc7710"`; fall back to
2669
+ * the EIP-3009 bridge otherwise.
2670
+ *
2671
+ * Both halves of that condition are required, and the rail half is the
2672
+ * caller's to supply — the SDK cannot see which rail an account is on from a
2673
+ * 402 response alone. A legacy AllowanceModule account passing
2674
+ * `delegationRail: true` would select a scheme its account cannot settle; the
2675
+ * backend refuses that at authorize with the #1986 retired-rail 410 (#2245 —
2676
+ * previously a scheme-specific 400 that wrongly implied the legacy rail could
2677
+ * still settle via EIP-3009), which is where a rail mismatch SHOULD fail,
2678
+ * on-chain-adjacent rather than in a client that could be lying to itself.
2679
+ *
2680
+ * Returns `null` when neither scheme has a payable entry — the caller decides
2681
+ * whether that is an error or a reason to look elsewhere.
2682
+ */
2683
+ declare function selectX402SettlementScheme(accepts: X402PaymentOption[], opts: {
2684
+ delegationRail: boolean;
2685
+ }): X402SchemeSelection | null;
2686
+ declare function x402AuthorizationAmount(option: X402PaymentOption): string;
2687
+ /**
2688
+ * Canonical Haven-authenticated x402 expected context, recomputed byte-for-byte
2689
+ * by the edge signer before it signs anything.
2690
+ *
2691
+ * **Two versions, and the version is derived — never passed in (#1138).**
2692
+ * `typedDataHash` present ⇒ v2, absent ⇒ v1. A v1 message is byte-identical to
2693
+ * what shipped before, so existing signers keep verifying legacy-rail bindings
2694
+ * unchanged.
2695
+ *
2696
+ * The version lives in both the header line and the payload so neither can be
2697
+ * reinterpreted as the other: a v2 context cannot be replayed as a v1 one that
2698
+ * drops the typed-data commitment, and a v1 context cannot be presented as v2.
2699
+ * That downgrade is exactly the attack the digest exists to stop — see
2700
+ * `assertExpectedBinding` in `@haven_ai/signer`, which refuses to raw-sign a
2701
+ * hash under a v2 binding and refuses to sign typed data without one.
2702
+ */
2703
+ declare function buildX402ExpectedMessage(context: X402ExpectedContext): string;
2704
+ declare function toStandardPaymentRequirements(paymentRequired: X402PaymentRequired, option: X402PaymentOption): PaymentRequirements;
2705
+ /**
2706
+ * Strictly validate an edge-signed EIP-3009 X-PAYMENT header against the
2707
+ * persisted x402 intent context before a hosted relay can submit funding.
2708
+ *
2709
+ * The merchant/facilitator remains the final protocol verifier. This closes a
2710
+ * separate hosted-relay integrity gap: malformed or context-mismatched input
2711
+ * must never cause Haven to relay the funding signature first.
2712
+ */
2713
+ declare function validateStandardX402PaymentHeader(paymentHeader: string, context: X402PaymentHeaderContext): Promise<void>;
2714
+ /**
2715
+ * Encode a payment receipt as a base64 PAYMENT-SIGNATURE header value.
2716
+ *
2717
+ * This follows the x402 v2 protocol — the server's facilitator will
2718
+ * verify the on-chain transaction referenced by tx_hash.
2719
+ */
2720
+ declare function encodePaymentProof(receipt: {
2721
+ txHash: string;
2722
+ paymentId: string;
2723
+ token: string;
2724
+ amount: string;
2725
+ to: string;
2726
+ resourceUrl?: string;
2727
+ accepted?: X402PaymentOption;
2728
+ payer?: string;
2729
+ chainId?: number;
2730
+ }): string;
2731
+ /**
2732
+ * Resolve a token symbol from a contract address.
2733
+ *
2734
+ * Checks all supported chains. For chain-specific resolution,
2735
+ * pass the optional `network` CAIP-2 string (e.g. "eip155:100").
2736
+ */
2737
+ declare function resolveTokenFromAddress(address: string, network?: string): {
2738
+ symbol: string;
2739
+ decimals: number;
2740
+ } | null;
2741
+
2742
+ /**
2743
+ * Runtime-agnostic base64 helpers — the single source of truth for the wire
2744
+ * encoding shared by the SDK and the edge signer (#325).
2745
+ *
2746
+ * Why this module exists: the SDK used `atob`/`btoa` (Web globals) while the
2747
+ * signer used `Buffer` (Node-only). Both worked because both currently run in
2748
+ * Node ≥ 16, but the duplication was a latent wire-incompatibility — and the
2749
+ * signer is headed for non-Node runtimes (browsers, Cloudflare Workers) where
2750
+ * `Buffer` does not exist (#314).
2751
+ *
2752
+ * Encoding contract:
2753
+ * - Output is ALWAYS standard base64 (`+`, `/`, padded). The x402 protocol's
2754
+ * reference implementation validates headers against
2755
+ * `/^[A-Za-z0-9+/]*={0,2}$/` — URL-safe output would be rejected.
2756
+ * - Decoding is tolerant: URL-safe input (`-`, `_`, unpadded) is normalized
2757
+ * before decoding, since third-party merchants are not guaranteed to be as
2758
+ * strict as the reference implementation.
2759
+ * - UTF-8 throughout. Naive `btoa(JSON.stringify(...))` throws on any
2760
+ * non-Latin-1 character (e.g. a merchant description with an emoji or
2761
+ * non-ASCII name); these helpers route through TextEncoder/TextDecoder on
2762
+ * the Web path so multibyte characters round-trip identically on both
2763
+ * runtimes.
2764
+ */
2765
+ /** Encode a UTF-8 string as standard base64. */
2766
+ declare function encodeBase64Utf8(value: string): string;
2767
+ /** Decode standard or URL-safe base64 to a UTF-8 string. */
2768
+ declare function decodeBase64Utf8(value: string): string;
2769
+ /** Encode a JSON-serializable value as a standard-base64 string. */
2770
+ declare function encodeBase64Json(value: unknown): string;
2771
+ /**
2772
+ * Decode a base64 JSON payload.
2773
+ *
2774
+ * Pass a `label` to get a wrapped error message instead of the raw
2775
+ * JSON/base64 error — call sites parsing untrusted merchant headers use this
2776
+ * to produce actionable failures.
2777
+ */
2778
+ declare function decodeBase64Json<T>(value: string, label?: string): T;
2779
+
2780
+ /**
2781
+ * #1271 / #1301: bounded same-origin merchant MCP endpoint discovery.
2782
+ *
2783
+ * An agent handed a BASE merchant URL previously had to hand-probe /, /mcp,
2784
+ * /sse, … until something answered 402. The demo merchant (and the #1266
2785
+ * contract) serves a machine-readable discovery document at
2786
+ * `/.well-known/haven-demo-merchant` (also at `/`) naming `mcp_url`. This
2787
+ * helper fetches ONLY those two fixed same-origin paths — no redirects
2788
+ * (`redirect: 'error'`), a 5 s timeout, a 64 KB read cap — and accepts the
2789
+ * document's `mcp_url` ONLY when it stays on the same origin as the input.
2790
+ * Anything else returns null and the caller reports the original probe
2791
+ * failure. Discovery finds endpoints; it carries no payment authority and an
2792
+ * off-origin `mcp_url` is never even fetched — this must not grow into a
2793
+ * general network scanner (SSRF bound, per the issue).
2794
+ *
2795
+ * Originally hosted-only (mcp-server, #1271). Moved here in #1301 so the
2796
+ * local/self-signed MCP package (`@haven_ai/mcp`) can share the EXACT same
2797
+ * bounded implementation instead of re-deriving discovery semantics —
2798
+ * behavior is byte-identical to the pre-move mcp-server copy; the #1271
2799
+ * contract tests in packages/mcp-server/src/tools.test.ts pass unmodified
2800
+ * against this moved implementation.
2801
+ */
2802
+ declare const MERCHANT_DISCOVERY_PATHS: readonly ["/.well-known/haven-demo-merchant", "/"];
2803
+ declare const DISCOVERY_MAX_BYTES: number;
2804
+ declare function discoverMerchantMcpUrl(inputUrl: string): Promise<string | null>;
2805
+ /** Trailing-slash/percent-case echoes compare equal; unparseable never does. */
2806
+ declare function sameUrl(a: string, b: string): boolean;
2807
+
2808
+ export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, CONNECTOR_PACKAGE_NAME, type CatalogSubmissionAccepted, type ClaudeTool, DEFAULT_CONFIRMATION_TIMEOUT_MS, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_CONNECTOR_CHANNEL, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, type HavenCatalogSubmission, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepConfirmation, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402MerchantOutcome, type X402MerchantOutcomeReport, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_LEGACY_PAYMENT_HEADER_NAME, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_PAYMENT_HEADER_NAME, X402_PAYMENT_HEADER_NAMES_SENT, X402_PAYMENT_REQUIRED_HEADER_NAME, X402_PAYMENT_RESPONSE_HEADER_NAME, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, connectorRerunCommand, connectorSpec, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isConnectorChannel, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveConnectorChannel, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, signerUpdateFallback, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses, x402V2PaymentEnvelope };