@haven_ai/sdk 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { AsyncLocalStorage } from 'async_hooks';
1
2
  import { exact } from 'x402/schemes';
2
3
  import { privateKeyToAccount } from 'viem/accounts';
3
4
  import { ethers } from 'ethers';
@@ -6,6 +7,102 @@ import { createHash } from 'crypto';
6
7
  // src/client.ts
7
8
 
8
9
  // src/types.ts
10
+ var AgentPaymentPhase = {
11
+ /** The agent must sign and submit the prepared payment before Haven can relay it. */
12
+ AgentSignatureRequired: "agent_signature_required",
13
+ /** Haven has received the signed payment and the agent should poll for confirmation. */
14
+ PaymentSubmitted: "payment_submitted",
15
+ /** The direct payment is confirmed; the agent does not need to do more for this payment id. */
16
+ PaymentConfirmed: "payment_confirmed",
17
+ /** The payment needs wallet owner approval in Haven before it can continue. */
18
+ UserApprovalRequired: "user_approval_required",
19
+ /** The wallet owner approved the request and still needs to complete the funding payment. */
20
+ UserExecutionRequired: "user_execution_required",
21
+ /** The funding payment was proposed and is waiting for the remaining account approvals. */
22
+ WaitingForAdditionalApprovals: "waiting_for_additional_approvals",
23
+ /** The Haven funding leg was sent; the agent can continue the merchant/protocol leg. */
24
+ FundingSent: "funding_sent",
25
+ /** The wallet owner rejected the request; the agent should stop and tell the user. */
26
+ Rejected: "rejected",
27
+ /** The payment or approval request expired before completion. */
28
+ Expired: "expired",
29
+ /** Haven could not complete the payment; the agent should stop and surface the failure. */
30
+ Failed: "failed"
31
+ };
32
+ var AgentPaymentNextAction = {
33
+ /** Sign with the delegate key and submit the payment to Haven. */
34
+ SignAndSubmitPayment: "sign_and_submit_payment",
35
+ /** Poll getPaymentStatus later using this payment id. */
36
+ CheckStatusLater: "check_status_later",
37
+ /** No further agent action is required for this payment id. */
38
+ None: "none",
39
+ /** Wait for the wallet owner to approve or reject the request in Haven. */
40
+ WaitForUserApproval: "wait_for_user_approval",
41
+ /** Wait for the wallet owner to finish sending the approved funding payment. */
42
+ WaitForUserToCompletePayment: "wait_for_user_to_complete_payment",
43
+ /** Resume this payment id and retry the original x402 request with the merchant payment header. */
44
+ RetryOriginalX402Request: "retry_original_x402_request",
45
+ /** Stop retrying this payment and tell the user what happened. */
46
+ StopAndTellUser: "stop_and_tell_user",
47
+ /** Ask again only if the user still wants the payment after expiry. */
48
+ RequestAgainIfUserStillWantsIt: "request_again_if_user_still_wants_it"
49
+ };
50
+ var AgentPaymentRail = {
51
+ /** Standard Haven payment from the user's Safe through an approved delegate allowance. */
52
+ Direct: "direct",
53
+ /** x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg. */
54
+ X402: "x402",
55
+ /** Machine Payment Protocol flow. */
56
+ Mpp: "mpp"
57
+ };
58
+ var AGENT_PAYMENT_PHASE_VALUES = Object.values(AgentPaymentPhase);
59
+ var AGENT_PAYMENT_NEXT_ACTION_VALUES = Object.values(AgentPaymentNextAction);
60
+ var AGENT_PAYMENT_RAIL_VALUES = Object.values(AgentPaymentRail);
61
+ var AgentPaymentPhaseDescriptions = {
62
+ [AgentPaymentPhase.AgentSignatureRequired]: "The agent must sign and submit the prepared payment before Haven can relay it.",
63
+ [AgentPaymentPhase.PaymentSubmitted]: "Haven has received the signed payment and the agent should poll for confirmation.",
64
+ [AgentPaymentPhase.PaymentConfirmed]: "The direct payment is confirmed; the agent does not need to do more for this payment id.",
65
+ [AgentPaymentPhase.UserApprovalRequired]: "The payment needs wallet owner approval in Haven before it can continue.",
66
+ [AgentPaymentPhase.UserExecutionRequired]: "The wallet owner approved the request and still needs to complete the funding payment.",
67
+ [AgentPaymentPhase.WaitingForAdditionalApprovals]: "The funding payment was proposed and is waiting for the remaining account approvals.",
68
+ [AgentPaymentPhase.FundingSent]: "The Haven funding leg was sent; the agent can continue the merchant/protocol leg.",
69
+ [AgentPaymentPhase.Rejected]: "The wallet owner rejected the request; the agent should stop and tell the user.",
70
+ [AgentPaymentPhase.Expired]: "The payment or approval request expired before completion.",
71
+ [AgentPaymentPhase.Failed]: "Haven could not complete the payment; the agent should stop and surface the failure."
72
+ };
73
+ var AgentPaymentNextActionDescriptions = {
74
+ [AgentPaymentNextAction.SignAndSubmitPayment]: "Sign with the delegate key and submit the payment to Haven.",
75
+ [AgentPaymentNextAction.CheckStatusLater]: "Poll getPaymentStatus later using this payment id.",
76
+ [AgentPaymentNextAction.None]: "No further agent action is required for this payment id.",
77
+ [AgentPaymentNextAction.WaitForUserApproval]: "Wait for the wallet owner to approve or reject the request in Haven.",
78
+ [AgentPaymentNextAction.WaitForUserToCompletePayment]: "Wait for the wallet owner to finish sending the approved funding payment.",
79
+ [AgentPaymentNextAction.RetryOriginalX402Request]: "Resume this payment id and retry the original x402 request with the merchant payment header.",
80
+ [AgentPaymentNextAction.StopAndTellUser]: "Stop retrying this payment and tell the user what happened.",
81
+ [AgentPaymentNextAction.RequestAgainIfUserStillWantsIt]: "Ask again only if the user still wants the payment after expiry."
82
+ };
83
+ var AgentPaymentRailDescriptions = {
84
+ [AgentPaymentRail.Direct]: "Standard Haven payment from the user-controlled Safe through an approved delegate allowance.",
85
+ [AgentPaymentRail.X402]: "x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg.",
86
+ [AgentPaymentRail.Mpp]: "Machine Payment Protocol flow."
87
+ };
88
+ var AgentPaymentPhaseSchema = {
89
+ type: "string",
90
+ enum: AGENT_PAYMENT_PHASE_VALUES,
91
+ description: "Stable Haven agent payment state phase.",
92
+ "x-enumDescriptions": AgentPaymentPhaseDescriptions
93
+ };
94
+ var AgentPaymentNextActionSchema = {
95
+ type: "string",
96
+ enum: AGENT_PAYMENT_NEXT_ACTION_VALUES,
97
+ description: "Stable next action an agent should take for a Haven payment state.",
98
+ "x-enumDescriptions": AgentPaymentNextActionDescriptions
99
+ };
100
+ var AgentPaymentRailSchema = {
101
+ type: "string",
102
+ enum: AGENT_PAYMENT_RAIL_VALUES,
103
+ description: "Stable rail identifier for Haven agent payment states.",
104
+ "x-enumDescriptions": AgentPaymentRailDescriptions
105
+ };
9
106
  var HavenError = class extends Error {
10
107
  constructor(message, code, statusCode, paymentId) {
11
108
  super(message);
@@ -33,6 +130,7 @@ var HavenPaymentStateError = class extends HavenApiError {
33
130
  this.name = "HavenPaymentStateError";
34
131
  }
35
132
  state;
133
+ resumeState;
36
134
  get status() {
37
135
  return this.state.status;
38
136
  }
@@ -160,6 +258,10 @@ var BASE_TOKENS = {
160
258
  "0x0000000000000000000000000000000000000000": { symbol: "ETH", decimals: 18 },
161
259
  "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913": { symbol: "USDC", decimals: 6 }
162
260
  };
261
+ var ALL_TOKENS = {
262
+ ...GNOSIS_TOKENS,
263
+ ...BASE_TOKENS
264
+ };
163
265
  var NETWORK_TOKENS = {
164
266
  "eip155:100": GNOSIS_TOKENS,
165
267
  "eip155:8453": BASE_TOKENS,
@@ -271,6 +373,13 @@ function encodePaymentProof(receipt) {
271
373
  };
272
374
  return btoa(JSON.stringify(payload));
273
375
  }
376
+ function resolveTokenFromAddress(address, network) {
377
+ const lower = address.toLowerCase();
378
+ if (network && network in NETWORK_TOKENS) {
379
+ return NETWORK_TOKENS[network][lower] ?? null;
380
+ }
381
+ return ALL_TOKENS[lower] ?? null;
382
+ }
274
383
  function decodeBase64Json2(value, label) {
275
384
  try {
276
385
  return JSON.parse(atob(value));
@@ -356,6 +465,9 @@ function buildExplorerUrl(chainId, txHash) {
356
465
  const base = CHAIN_EXPLORER_TX[chainId ?? 8453] ?? CHAIN_EXPLORER_TX[8453];
357
466
  return `${base}/${txHash}`;
358
467
  }
468
+ function explorerUrlOrEmpty(chainId, txHash) {
469
+ return txHash ? buildExplorerUrl(chainId, txHash) : "";
470
+ }
359
471
  var DEFAULT_REQUEST_TIMEOUT = 3e4;
360
472
  var DEFAULT_CONFIRMATION_TIMEOUT = 9e4;
361
473
  var DEFAULT_POLLING_INTERVAL = 3e3;
@@ -377,30 +489,33 @@ function chainIdFromNetwork(network) {
377
489
  const chainId = Number(network.slice("eip155:".length));
378
490
  return Number.isFinite(chainId) ? chainId : void 0;
379
491
  }
492
+ function chainIdOrNull(network) {
493
+ return chainIdFromNetwork(network) ?? null;
494
+ }
380
495
  function phaseForStatus(status) {
381
- if (status === "pending_signature") return "agent_signature_required";
382
- if (status === "submitted") return "payment_submitted";
383
- if (status === "confirmed") return "payment_confirmed";
384
- if (status === "pending" || status === "pending_approval") return "user_approval_required";
385
- if (status === "approved") return "user_execution_required";
386
- if (status === "proposed") return "waiting_for_additional_approvals";
387
- if (status === "executed") return "funding_sent";
388
- if (status === "rejected") return "rejected";
389
- if (status === "expired") return "expired";
390
- if (status === "failed") return "failed";
496
+ if (status === "pending_signature") return AgentPaymentPhase.AgentSignatureRequired;
497
+ if (status === "submitted") return AgentPaymentPhase.PaymentSubmitted;
498
+ if (status === "confirmed") return AgentPaymentPhase.PaymentConfirmed;
499
+ if (status === "pending" || status === "pending_approval") return AgentPaymentPhase.UserApprovalRequired;
500
+ if (status === "approved") return AgentPaymentPhase.UserExecutionRequired;
501
+ if (status === "proposed") return AgentPaymentPhase.WaitingForAdditionalApprovals;
502
+ if (status === "executed") return AgentPaymentPhase.FundingSent;
503
+ if (status === "rejected") return AgentPaymentPhase.Rejected;
504
+ if (status === "expired") return AgentPaymentPhase.Expired;
505
+ if (status === "failed") return AgentPaymentPhase.Failed;
391
506
  return null;
392
507
  }
393
508
  function nextActionForStatus(status) {
394
- if (status === "pending_signature") return "sign_and_submit_payment";
395
- if (status === "submitted") return "check_status_later";
396
- if (status === "confirmed") return "none";
397
- if (status === "pending" || status === "pending_approval") return "wait_for_user_approval";
398
- if (status === "approved") return "wait_for_user_to_complete_payment";
399
- if (status === "proposed") return "wait_for_user_approval";
400
- if (status === "executed") return "retry_original_x402_request";
401
- if (status === "rejected") return "stop_and_tell_user";
402
- if (status === "expired") return "request_again_if_user_still_wants_it";
403
- if (status === "failed") return "stop_and_tell_user";
509
+ if (status === "pending_signature") return AgentPaymentNextAction.SignAndSubmitPayment;
510
+ if (status === "submitted") return AgentPaymentNextAction.CheckStatusLater;
511
+ if (status === "confirmed") return AgentPaymentNextAction.None;
512
+ if (status === "pending" || status === "pending_approval") return AgentPaymentNextAction.WaitForUserApproval;
513
+ if (status === "approved") return AgentPaymentNextAction.WaitForUserToCompletePayment;
514
+ if (status === "proposed") return AgentPaymentNextAction.WaitForUserApproval;
515
+ if (status === "executed") return AgentPaymentNextAction.RetryOriginalX402Request;
516
+ if (status === "rejected") return AgentPaymentNextAction.StopAndTellUser;
517
+ if (status === "expired") return AgentPaymentNextAction.RequestAgainIfUserStillWantsIt;
518
+ if (status === "failed") return AgentPaymentNextAction.StopAndTellUser;
404
519
  return null;
405
520
  }
406
521
  function messageForState(label, status, paymentId, nextAction) {
@@ -418,6 +533,31 @@ function messageForState(label, status, paymentId, nextAction) {
418
533
  }
419
534
  return `${label} is ${status}; next_action=${nextAction} (payment_id: ${paymentId}).`;
420
535
  }
536
+ function sameAddress(a, b) {
537
+ return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
538
+ }
539
+ function isMppRail(rail) {
540
+ return rail === "mpp" || Boolean(rail?.startsWith("mpp_"));
541
+ }
542
+ function decimalFromUsdcAtomic(value) {
543
+ const amount = BigInt(value);
544
+ const whole = amount / 1000000n;
545
+ const fraction = (amount % 1000000n).toString().padStart(6, "0").replace(/0+$/, "");
546
+ return fraction ? `${whole}.${fraction}` : whole.toString();
547
+ }
548
+ function normalizeDecimal(value) {
549
+ if (!value.includes(".")) return value.replace(/^0+(?=\d)/, "") || "0";
550
+ const [whole, fraction = ""] = value.split(".");
551
+ const normalizedWhole = whole.replace(/^0+(?=\d)/, "") || "0";
552
+ const normalizedFraction = fraction.replace(/0+$/, "");
553
+ return normalizedFraction ? `${normalizedWhole}.${normalizedFraction}` : normalizedWhole;
554
+ }
555
+ function parseMerchantSettlement(header) {
556
+ if (!header) return {};
557
+ const parsed = parseProtocolReceiptHeader(header);
558
+ const tx = typeof parsed?.transaction === "string" ? parsed.transaction : typeof parsed?.txHash === "string" ? parsed.txHash : typeof parsed?.tx_hash === "string" ? parsed.tx_hash : null;
559
+ return { settlementTxHash: tx };
560
+ }
421
561
  var HavenClient = class {
422
562
  apiKey;
423
563
  delegateKey;
@@ -429,6 +569,19 @@ var HavenClient = class {
429
569
  inFlightX402 = /* @__PURE__ */ new Map();
430
570
  x402ReceiptCache = /* @__PURE__ */ new Map();
431
571
  inFlightMachinePayments = /* @__PURE__ */ new Map();
572
+ /**
573
+ * Setup-time headers configured via `HavenClientConfig.defaultHeaders`.
574
+ * Read-only after construction — use `withRequestContext` for per-call
575
+ * scoping so concurrent requests don't race on shared mutable state.
576
+ */
577
+ defaultHeaders;
578
+ /**
579
+ * Async-local store for per-request context (currently: extra headers).
580
+ * Each `withRequestContext` invocation produces an isolated store, so
581
+ * overlapping async work — like two MCP tool dispatches in flight at
582
+ * the same time — see their own headers without stepping on each other.
583
+ */
584
+ requestContext = new AsyncLocalStorage();
432
585
  /** Delegate address derived from the private key (if provided) */
433
586
  delegateAddress;
434
587
  constructor(config) {
@@ -439,10 +592,29 @@ var HavenClient = class {
439
592
  this.requestTimeout = config.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
440
593
  this.confirmationTimeout = config.confirmationTimeout ?? DEFAULT_CONFIRMATION_TIMEOUT;
441
594
  this.pollingInterval = config.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
595
+ this.defaultHeaders = { ...config.defaultHeaders ?? {} };
442
596
  if (this.delegateKey) {
443
597
  this.delegateAddress = addressFromKey(this.delegateKey);
444
598
  }
445
599
  }
600
+ /**
601
+ * Run `fn` with extra Haven-API headers scoped to the async work it
602
+ * performs. Used by the MCP server to tag every Haven API request that
603
+ * a single tool dispatch makes with `X-Haven-MCP-Tool: <name>` so the
604
+ * backend can write an audit-log row attributing the call.
605
+ *
606
+ * The headers are held in an `AsyncLocalStorage` so overlapping
607
+ * dispatches do not leak headers into each other's requests. The store
608
+ * inherits across `await` boundaries, so any Haven API call made while
609
+ * `fn` is awaiting will pick up the right headers.
610
+ *
611
+ * Has no effect on outbound merchant requests (x402 / MPP) — those
612
+ * never go through the internal `request<T>` path that reads the
613
+ * context.
614
+ */
615
+ withRequestContext(headers, fn) {
616
+ return this.requestContext.run({ headers: { ...headers } }, fn);
617
+ }
446
618
  // ── High-Level API ───────────────────────────────────────────────
447
619
  /**
448
620
  * Send a payment in one call.
@@ -537,6 +709,66 @@ var HavenClient = class {
537
709
  const raw = await this.get(`/machine-payments/${paymentId}/status`);
538
710
  return this.mapPaymentStatusResult(raw);
539
711
  }
712
+ /**
713
+ * Get the agent identity tied to this API key.
714
+ */
715
+ async getAgent() {
716
+ const raw = await this.get("/machine-payments/agent");
717
+ return {
718
+ id: raw.id,
719
+ name: raw.name,
720
+ status: raw.status,
721
+ safeAddress: raw.safe_address,
722
+ delegateAddress: raw.delegate_address,
723
+ chainId: raw.chain_id
724
+ };
725
+ }
726
+ /**
727
+ * Get configured and on-chain allowances for the authenticated agent.
728
+ */
729
+ async getAllowances() {
730
+ const raw = await this.get("/machine-payments/allowances");
731
+ return {
732
+ agentId: raw.agent_id,
733
+ safeAddress: raw.safe_address,
734
+ delegateAddress: raw.delegate_address,
735
+ chainId: raw.chain_id,
736
+ allowances: raw.allowances.map((allowance) => ({
737
+ id: allowance.id,
738
+ tokenAddress: allowance.token_address,
739
+ tokenSymbol: allowance.token_symbol,
740
+ configuredAmount: allowance.configured_amount,
741
+ resetPeriodMin: allowance.reset_period_min,
742
+ onchain: {
743
+ amount: allowance.onchain.amount,
744
+ spent: allowance.onchain.spent,
745
+ remaining: allowance.onchain.remaining,
746
+ effectiveSpent: allowance.onchain.effective_spent,
747
+ resetTimeMin: allowance.onchain.reset_time_min,
748
+ lastResetMin: allowance.onchain.last_reset_min,
749
+ nonce: allowance.onchain.nonce,
750
+ isResetPending: allowance.onchain.is_reset_pending
751
+ }
752
+ }))
753
+ };
754
+ }
755
+ /**
756
+ * List recent machine-payment receipts/evidence for bookkeeping.
757
+ */
758
+ async listReceipts(options = {}) {
759
+ const query = options.limit ? `?limit=${encodeURIComponent(String(options.limit))}` : "";
760
+ const raw = await this.get(`/machine-payments/receipts${query}`);
761
+ return raw.receipts.map((receipt) => this.mapPaymentReceipt(receipt));
762
+ }
763
+ /**
764
+ * Rehydrate the x402/MPP resume-state bundle for a payment id.
765
+ *
766
+ * The server returns stored protocol context only. The client still signs the
767
+ * merchant proof locally when resumeX402Payment() or resumeMppPayment() runs.
768
+ */
769
+ async getResumeState(paymentId) {
770
+ return this.get(`/payments/${paymentId}/resume_state`);
771
+ }
540
772
  /**
541
773
  * Poll until a payment reaches a terminal status (confirmed, failed, expired).
542
774
  */
@@ -561,7 +793,7 @@ var HavenClient = class {
561
793
  *
562
794
  * Requires `delegateKey` to be set in the client config.
563
795
  */
564
- async authorizeX402(paymentRequired) {
796
+ async authorizeX402(paymentRequired, options = {}) {
565
797
  if (!this.delegateKey) {
566
798
  throw new HavenSigningError(
567
799
  "delegateKey is required for x402 payments. Pass it in the HavenClient config."
@@ -577,7 +809,7 @@ var HavenClient = class {
577
809
  400
578
810
  );
579
811
  }
580
- const idempotencyKey = buildX402IdempotencyKey(paymentRequired, option);
812
+ const idempotencyKey = options.idempotencyKey ?? buildX402IdempotencyKey(paymentRequired, option);
581
813
  const cached = this.x402ReceiptCache.get(idempotencyKey);
582
814
  if (cached && cached.expiresAt > Date.now()) return cached.receipt;
583
815
  const inFlight = this.inFlightX402.get(idempotencyKey);
@@ -586,10 +818,62 @@ var HavenClient = class {
586
818
  this.inFlightX402.set(idempotencyKey, promise);
587
819
  try {
588
820
  return await promise;
821
+ } catch (err) {
822
+ this.attachResumeState(err, {
823
+ rail: "x402",
824
+ paymentRequired,
825
+ accepted: option,
826
+ idempotencyKey
827
+ });
828
+ throw err;
589
829
  } finally {
590
830
  this.inFlightX402.delete(idempotencyKey);
591
831
  }
592
832
  }
833
+ /**
834
+ * Probe a paid endpoint and return its x402 quote without creating a Haven
835
+ * payment or approval request.
836
+ */
837
+ async quoteX402(url, init, options = {}) {
838
+ const initialInit = this.withX402Wallet(init, this.x402PayerAddress());
839
+ const request = this.snapshotX402Request(url, initialInit);
840
+ const response = await globalThis.fetch(url, initialInit);
841
+ if (response.status !== 402) {
842
+ throw new HavenApiError(
843
+ `Expected an x402 quote response with HTTP 402, got HTTP ${response.status}.`,
844
+ response.status || 400
845
+ );
846
+ }
847
+ if (response.headers.get("MACHINE-PAYMENT-CHALLENGE")) {
848
+ throw new HavenApiError("quoteX402 only supports standard x402 Payment Required responses.", 400);
849
+ }
850
+ const paymentRequired = await parsePaymentRequiredResponse(response);
851
+ return this.buildX402Quote(paymentRequired, request, options.idempotencyKey);
852
+ }
853
+ /**
854
+ * Pay a previously inspected x402 quote and retry the exact captured request.
855
+ */
856
+ async payX402Quote(quote, options = {}) {
857
+ const idempotencyKey = options.idempotencyKey ?? quote.idempotencyKey;
858
+ try {
859
+ const receipt = await this.authorizeX402(quote.paymentRequired, { idempotencyKey });
860
+ return this.retryX402Request(
861
+ quote.request.url,
862
+ this.requestInitFromSnapshot(quote.request),
863
+ quote.paymentRequired,
864
+ receipt
865
+ );
866
+ } catch (err) {
867
+ this.attachResumeState(err, {
868
+ rail: "x402",
869
+ paymentRequired: quote.paymentRequired,
870
+ accepted: quote.accepted,
871
+ idempotencyKey,
872
+ request: quote.request
873
+ });
874
+ throw err;
875
+ }
876
+ }
593
877
  async authorizeStandardX402(paymentRequired, option, idempotencyKey) {
594
878
  const paymentHeader = await this.createStandardX402Header(paymentRequired, option);
595
879
  const raw = await this.post("/x402", {
@@ -603,21 +887,13 @@ var HavenClient = class {
603
887
  idempotencyKey
604
888
  });
605
889
  if (raw.success && raw.tx_hash) {
606
- const receipt2 = {
607
- success: true,
608
- paymentId: raw.payment_id,
609
- txHash: raw.tx_hash,
610
- token: raw.token ?? "",
611
- amount: raw.amount ?? "",
612
- to: raw.to ?? "",
613
- resourceUrl: paymentRequired.resource.url,
614
- explorerUrl: raw.explorer_url ?? (raw.tx_hash ? buildExplorerUrl(raw.chain_id, raw.tx_hash) : ""),
615
- accepted: option,
616
- paymentHeader,
617
- merchantTo: raw.merchant_to ?? option.payTo,
618
- payer: raw.payer ?? raw.safe_address,
619
- chainId: raw.chain_id ?? chainIdFromNetwork(option.network)
620
- };
890
+ const receipt2 = this.mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw);
891
+ this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt2);
892
+ return receipt2;
893
+ }
894
+ const state = this.paymentStateFromRaw("x402 payment", raw);
895
+ if (state?.nextAction === AgentPaymentNextAction.RetryOriginalX402Request) {
896
+ const receipt2 = this.mapX402ReceiptFromStatus(paymentRequired, option, paymentHeader, state);
621
897
  this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt2);
622
898
  return receipt2;
623
899
  }
@@ -633,24 +909,61 @@ var HavenClient = class {
633
909
  if (execResult.status !== "confirmed") {
634
910
  this.throwPaymentStateError("x402 payment", execResult);
635
911
  }
636
- const receipt = {
637
- success: true,
638
- paymentId: raw.payment_id,
639
- txHash: execResult.tx_hash ?? "",
640
- token: execResult.token ?? raw.token ?? "",
641
- amount: execResult.amount ?? raw.amount ?? "",
642
- to: execResult.to ?? raw.to ?? "",
643
- resourceUrl: paymentRequired.resource.url,
644
- explorerUrl: execResult.explorer_url ?? (execResult.tx_hash ? buildExplorerUrl(execResult.chain_id, execResult.tx_hash) : ""),
645
- accepted: option,
646
- paymentHeader,
647
- merchantTo: option.payTo,
648
- payer: raw.payer ?? raw.safe_address ?? raw.sign_data?.components.safe,
649
- chainId: execResult.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network)
650
- };
912
+ const receipt = this.mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw, execResult);
651
913
  this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt);
652
914
  return receipt;
653
915
  }
916
+ async resumeAuthorizedX402(input) {
917
+ if (!this.delegateKey) {
918
+ throw new HavenSigningError(
919
+ "delegateKey is required for x402 payments. Pass it in the HavenClient config."
920
+ );
921
+ }
922
+ if (!this.delegateAddress) {
923
+ throw new HavenSigningError("delegateAddress could not be derived from delegateKey.");
924
+ }
925
+ const option = selectStandardPaymentOption(input.paymentRequired.accepts);
926
+ if (!option) {
927
+ throw new HavenApiError(
928
+ "No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC.",
929
+ 400
930
+ );
931
+ }
932
+ const idempotencyKey = input.idempotencyKey ?? buildX402IdempotencyKey(input.paymentRequired, option);
933
+ const cached = this.x402ReceiptCache.get(idempotencyKey);
934
+ if (cached && cached.expiresAt > Date.now()) return cached.receipt;
935
+ const status = await this.getPaymentStatus(input.paymentId);
936
+ this.assertCanResumeX402(status, input.paymentRequired, option);
937
+ const paymentHeader = await this.createStandardX402Header(input.paymentRequired, option);
938
+ const receipt = this.mapX402ReceiptFromStatus(input.paymentRequired, option, paymentHeader, status);
939
+ this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt);
940
+ return receipt;
941
+ }
942
+ async resumeX402Payment(input) {
943
+ const inputInit = "init" in input ? input.init : void 0;
944
+ const initialInit = this.withX402Wallet(
945
+ inputInit ?? (input.request ? this.requestInitFromSnapshot(input.request) : void 0),
946
+ this.x402PayerAddress()
947
+ );
948
+ let paymentRequired = input.paymentRequired;
949
+ const url = input.url ?? input.request?.url;
950
+ if (!paymentRequired) {
951
+ if (!url) {
952
+ throw new HavenApiError("x402 resume requires the original URL or a captured request snapshot.", 400);
953
+ }
954
+ const response = await globalThis.fetch(url, initialInit);
955
+ if (response.status !== 402) {
956
+ throw new HavenApiError("Expected the original x402 request to return HTTP 402 before resuming.", 400);
957
+ }
958
+ paymentRequired = await parsePaymentRequiredResponse(response);
959
+ }
960
+ const receipt = await this.resumeAuthorizedX402({
961
+ paymentId: input.paymentId,
962
+ paymentRequired,
963
+ idempotencyKey: input.idempotencyKey
964
+ });
965
+ return this.retryX402Request(url ?? paymentRequired.resource.url, initialInit, paymentRequired, receipt);
966
+ }
654
967
  /**
655
968
  * Fetch wrapper that automatically handles HTTP 402 responses.
656
969
  *
@@ -664,7 +977,7 @@ var HavenClient = class {
664
977
  *
665
978
  * Requires `delegateKey` to be set in the client config.
666
979
  */
667
- async fetch(url, init) {
980
+ async fetch(url, init, options = {}) {
668
981
  const initialInit = this.withX402Wallet(init, this.x402PayerAddress());
669
982
  const response = await globalThis.fetch(url, initialInit);
670
983
  if (response.status !== 402) return response;
@@ -685,7 +998,70 @@ var HavenClient = class {
685
998
  }
686
999
  return this.fetchWithMachinePayment(url, initialInit, challenge);
687
1000
  }
688
- const receipt = await this.authorizeX402(paymentRequired);
1001
+ const request = this.snapshotX402Request(url, initialInit);
1002
+ const option = selectStandardPaymentOption(paymentRequired.accepts);
1003
+ const idempotencyKey = options.idempotencyKey ?? (option ? buildX402IdempotencyKey(paymentRequired, option) : void 0);
1004
+ let receipt;
1005
+ try {
1006
+ receipt = await this.authorizeX402(paymentRequired, options);
1007
+ } catch (err) {
1008
+ if (option && idempotencyKey) {
1009
+ this.attachResumeState(err, {
1010
+ rail: "x402",
1011
+ paymentRequired,
1012
+ accepted: option,
1013
+ idempotencyKey,
1014
+ request
1015
+ });
1016
+ }
1017
+ throw err;
1018
+ }
1019
+ return this.retryX402Request(url, initialInit, paymentRequired, receipt);
1020
+ }
1021
+ /**
1022
+ * Probe a paid MPP endpoint or inspect an existing challenge without creating
1023
+ * a Haven payment or approval request.
1024
+ */
1025
+ async quoteMpp(challengeOrUrl, init, options = {}) {
1026
+ if (typeof challengeOrUrl !== "string") {
1027
+ const request2 = this.snapshotX402Request(challengeOrUrl.resource, init);
1028
+ return this.buildMppQuote(challengeOrUrl, request2, options.idempotencyKey);
1029
+ }
1030
+ const request = this.snapshotX402Request(challengeOrUrl, init);
1031
+ const response = await globalThis.fetch(challengeOrUrl, init);
1032
+ if (response.status !== 402) {
1033
+ throw new HavenApiError(
1034
+ `Expected an MPP quote response with HTTP 402, got HTTP ${response.status}.`,
1035
+ response.status || 400
1036
+ );
1037
+ }
1038
+ const challenge = await parseMachinePaymentChallengeResponse(response);
1039
+ return this.buildMppQuote(challenge, request, options.idempotencyKey);
1040
+ }
1041
+ /**
1042
+ * Pay a previously inspected MPP quote and retry the exact captured request.
1043
+ */
1044
+ async payMppChallenge(quote, options = {}) {
1045
+ const idempotencyKey = options.idempotencyKey ?? quote.idempotencyKey;
1046
+ try {
1047
+ const receipt = await this.authorizeMachinePayment(quote.challenge, { idempotencyKey });
1048
+ return this.retryMppRequest(
1049
+ quote.request.url,
1050
+ this.requestInitFromSnapshot(quote.request),
1051
+ quote.challenge,
1052
+ receipt
1053
+ );
1054
+ } catch (err) {
1055
+ this.attachResumeState(err, {
1056
+ rail: "mpp",
1057
+ challenge: quote.challenge,
1058
+ idempotencyKey,
1059
+ request: quote.request
1060
+ });
1061
+ throw err;
1062
+ }
1063
+ }
1064
+ async retryX402Request(url, initialInit, paymentRequired, receipt) {
689
1065
  if (!receipt.accepted) {
690
1066
  throw new HavenApiError("No accepted x402 option was recorded for payment retry", 500);
691
1067
  }
@@ -723,6 +1099,14 @@ var HavenClient = class {
723
1099
  }
724
1100
  );
725
1101
  }
1102
+ const merchantSettlement = parseMerchantSettlement(retryResponse.headers.get("PAYMENT-RESPONSE"));
1103
+ if (receipt.merchant && merchantSettlement.settlementTxHash) {
1104
+ receipt.merchant.settlementTxHash = merchantSettlement.settlementTxHash;
1105
+ receipt.merchant.settlementExplorerUrl = buildExplorerUrl(
1106
+ receipt.chainId,
1107
+ merchantSettlement.settlementTxHash
1108
+ );
1109
+ }
726
1110
  await this.reportMachinePaymentEvidence({
727
1111
  paymentId: receipt.paymentId,
728
1112
  rail: "x402",
@@ -738,7 +1122,7 @@ var HavenClient = class {
738
1122
  });
739
1123
  return retryResponse;
740
1124
  }
741
- async authorizeMachinePayment(challenge) {
1125
+ async authorizeMachinePayment(challenge, options = {}) {
742
1126
  if (!this.delegateKey) {
743
1127
  throw new HavenSigningError(
744
1128
  "delegateKey is required for machine payments. Pass it in the HavenClient config."
@@ -747,13 +1131,20 @@ var HavenClient = class {
747
1131
  if (challenge.rail !== "mpp_demo") {
748
1132
  throw new HavenApiError(`Unsupported machine payment rail: ${challenge.rail}`, 400);
749
1133
  }
750
- const idempotencyKey = buildMachinePaymentIdempotencyKey(challenge);
1134
+ const idempotencyKey = options.idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge);
751
1135
  const inFlight = this.inFlightMachinePayments.get(idempotencyKey);
752
1136
  if (inFlight) return inFlight;
753
1137
  const promise = this.authorizeMppDemoPayment(challenge, idempotencyKey);
754
1138
  this.inFlightMachinePayments.set(idempotencyKey, promise);
755
1139
  try {
756
1140
  return await promise;
1141
+ } catch (err) {
1142
+ this.attachResumeState(err, {
1143
+ rail: "mpp",
1144
+ challenge,
1145
+ idempotencyKey
1146
+ });
1147
+ throw err;
757
1148
  } finally {
758
1149
  this.inFlightMachinePayments.delete(idempotencyKey);
759
1150
  }
@@ -780,8 +1171,56 @@ var HavenClient = class {
780
1171
  }
781
1172
  return this.mapMachinePaymentReceipt(challenge, raw, execResult.tx_hash, execResult);
782
1173
  }
1174
+ async resumeAuthorizedMpp(input) {
1175
+ if (!this.delegateKey) {
1176
+ throw new HavenSigningError(
1177
+ "delegateKey is required for machine payments. Pass it in the HavenClient config."
1178
+ );
1179
+ }
1180
+ const status = await this.getPaymentStatus(input.paymentId);
1181
+ this.assertCanResumeMpp(status, input.challenge);
1182
+ return this.mapMachinePaymentReceiptFromStatus(input.challenge, status);
1183
+ }
1184
+ async resumeMppPayment(input) {
1185
+ const inputInit = "init" in input ? input.init : void 0;
1186
+ const initialInit = inputInit ?? (input.request ? this.requestInitFromSnapshot(input.request) : void 0);
1187
+ let challenge = input.challenge;
1188
+ const url = input.url ?? input.request?.url;
1189
+ if (!challenge) {
1190
+ if (!url) {
1191
+ throw new HavenApiError("MPP resume requires the original URL or a captured request snapshot.", 400);
1192
+ }
1193
+ const response = await globalThis.fetch(url, initialInit);
1194
+ if (response.status !== 402) {
1195
+ throw new HavenApiError("Expected the original MPP request to return HTTP 402 before resuming.", 400);
1196
+ }
1197
+ challenge = await parseMachinePaymentChallengeResponse(response);
1198
+ }
1199
+ const receipt = await this.resumeAuthorizedMpp({
1200
+ paymentId: input.paymentId,
1201
+ challenge,
1202
+ idempotencyKey: input.idempotencyKey
1203
+ });
1204
+ return this.retryMppRequest(url ?? challenge.resource, initialInit, challenge, receipt);
1205
+ }
783
1206
  async fetchWithMachinePayment(url, initialInit, challenge) {
784
- const receipt = await this.authorizeMachinePayment(challenge);
1207
+ const request = this.snapshotX402Request(url, initialInit);
1208
+ const idempotencyKey = buildMachinePaymentIdempotencyKey(challenge);
1209
+ let receipt;
1210
+ try {
1211
+ receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
1212
+ } catch (err) {
1213
+ this.attachResumeState(err, {
1214
+ rail: "mpp",
1215
+ challenge,
1216
+ idempotencyKey,
1217
+ request
1218
+ });
1219
+ throw err;
1220
+ }
1221
+ return this.retryMppRequest(url, initialInit, challenge, receipt);
1222
+ }
1223
+ async retryMppRequest(url, initialInit, challenge, receipt) {
785
1224
  const retryHeaders = new Headers(initialInit?.headers);
786
1225
  retryHeaders.set("MACHINE-PAYMENT-PROOF", receipt.proofHeader);
787
1226
  const retryResponse = await globalThis.fetch(url, {
@@ -825,6 +1264,212 @@ var HavenClient = class {
825
1264
  });
826
1265
  return retryResponse;
827
1266
  }
1267
+ assertCanResumeX402(status, paymentRequired, option) {
1268
+ if (status.rail !== "x402") {
1269
+ throw new HavenPaymentStateError(
1270
+ `Payment ${status.paymentId} is ${status.rail}, not x402.`,
1271
+ 409,
1272
+ status
1273
+ );
1274
+ }
1275
+ if (status.nextAction !== AgentPaymentNextAction.RetryOriginalX402Request) {
1276
+ throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
1277
+ }
1278
+ if (!status.txHash) {
1279
+ throw new HavenApiError(
1280
+ `x402 payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1281
+ 502,
1282
+ status,
1283
+ status.paymentId
1284
+ );
1285
+ }
1286
+ if (status.resourceUrl && status.resourceUrl !== paymentRequired.resource.url) {
1287
+ throw new HavenApiError(
1288
+ "x402 resume request does not match the approved resource URL.",
1289
+ 409,
1290
+ { status, paymentRequired },
1291
+ status.paymentId
1292
+ );
1293
+ }
1294
+ if (status.merchantAddress && !sameAddress(status.merchantAddress, option.payTo)) {
1295
+ throw new HavenApiError(
1296
+ "x402 resume request does not match the approved merchant.",
1297
+ 409,
1298
+ { status, selectedPayment: option },
1299
+ status.paymentId
1300
+ );
1301
+ }
1302
+ const optionChainId = chainIdFromNetwork(option.network);
1303
+ if (status.chainId && optionChainId && status.chainId !== optionChainId) {
1304
+ throw new HavenApiError(
1305
+ "x402 resume request does not match the approved network.",
1306
+ 409,
1307
+ { status, selectedPayment: option },
1308
+ status.paymentId
1309
+ );
1310
+ }
1311
+ if (status.token && status.token !== "USDC") {
1312
+ throw new HavenApiError(
1313
+ "x402 resume request does not match the approved token.",
1314
+ 409,
1315
+ { status, selectedPayment: option },
1316
+ status.paymentId
1317
+ );
1318
+ }
1319
+ const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
1320
+ const requestedAmount = normalizeDecimal(decimalFromUsdcAtomic(option.amount));
1321
+ if (approvedAmount && approvedAmount !== requestedAmount) {
1322
+ throw new HavenApiError(
1323
+ "x402 resume request does not match the approved amount.",
1324
+ 409,
1325
+ { status, selectedPayment: option },
1326
+ status.paymentId
1327
+ );
1328
+ }
1329
+ }
1330
+ assertCanResumeMpp(status, challenge) {
1331
+ if (!isMppRail(status.rail)) {
1332
+ throw new HavenPaymentStateError(
1333
+ `Payment ${status.paymentId} is ${status.rail}, not MPP.`,
1334
+ 409,
1335
+ status
1336
+ );
1337
+ }
1338
+ if (status.nextAction !== AgentPaymentNextAction.RetryOriginalX402Request) {
1339
+ throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
1340
+ }
1341
+ if (!status.txHash) {
1342
+ throw new HavenApiError(
1343
+ `MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1344
+ 502,
1345
+ status,
1346
+ status.paymentId
1347
+ );
1348
+ }
1349
+ if (status.resourceUrl && status.resourceUrl !== challenge.resource) {
1350
+ throw new HavenApiError(
1351
+ "MPP resume request does not match the approved resource URL.",
1352
+ 409,
1353
+ { status, challenge },
1354
+ status.paymentId
1355
+ );
1356
+ }
1357
+ if (status.merchantAddress && !sameAddress(status.merchantAddress, challenge.recipient)) {
1358
+ throw new HavenApiError(
1359
+ "MPP resume request does not match the approved merchant.",
1360
+ 409,
1361
+ { status, challenge },
1362
+ status.paymentId
1363
+ );
1364
+ }
1365
+ if (status.chainId && status.chainId !== challenge.network.chainId) {
1366
+ throw new HavenApiError(
1367
+ "MPP resume request does not match the approved network.",
1368
+ 409,
1369
+ { status, challenge },
1370
+ status.paymentId
1371
+ );
1372
+ }
1373
+ if (status.token && status.token !== challenge.asset.symbol) {
1374
+ throw new HavenApiError(
1375
+ "MPP resume request does not match the approved token.",
1376
+ 409,
1377
+ { status, challenge },
1378
+ status.paymentId
1379
+ );
1380
+ }
1381
+ const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
1382
+ const requestedAmount = normalizeDecimal(challenge.amount.display);
1383
+ if (approvedAmount && approvedAmount !== requestedAmount) {
1384
+ throw new HavenApiError(
1385
+ "MPP resume request does not match the approved amount.",
1386
+ 409,
1387
+ { status, challenge },
1388
+ status.paymentId
1389
+ );
1390
+ }
1391
+ }
1392
+ mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw, execResult) {
1393
+ const txHash = execResult?.tx_hash ?? raw.tx_hash ?? "";
1394
+ const chainId = execResult?.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network);
1395
+ const token = execResult?.token ?? raw.token ?? "USDC";
1396
+ const amount = execResult?.amount ?? raw.amount ?? decimalFromUsdcAtomic(option.amount);
1397
+ const to = execResult?.to ?? raw.to ?? this.delegateAddress ?? "";
1398
+ const explorerUrl = execResult?.explorer_url ?? raw.explorer_url ?? explorerUrlOrEmpty(chainId, txHash);
1399
+ const merchantTo = execResult?.merchant_to ?? raw.merchant_to ?? option.payTo;
1400
+ const payer = raw.payer ?? raw.safe_address ?? raw.sign_data?.components.safe;
1401
+ return this.buildX402Receipt({
1402
+ paymentId: raw.payment_id,
1403
+ txHash,
1404
+ token,
1405
+ amount,
1406
+ to,
1407
+ resourceUrl: paymentRequired.resource.url,
1408
+ explorerUrl,
1409
+ accepted: option,
1410
+ paymentHeader,
1411
+ merchantTo,
1412
+ payer,
1413
+ chainId
1414
+ });
1415
+ }
1416
+ mapX402ReceiptFromStatus(paymentRequired, option, paymentHeader, status) {
1417
+ if (!status.txHash) {
1418
+ throw new HavenApiError(
1419
+ `x402 payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1420
+ 502,
1421
+ status,
1422
+ status.paymentId
1423
+ );
1424
+ }
1425
+ return this.buildX402Receipt({
1426
+ paymentId: status.paymentId,
1427
+ txHash: status.txHash,
1428
+ token: status.token || "USDC",
1429
+ amount: status.amount || decimalFromUsdcAtomic(option.amount),
1430
+ to: this.delegateAddress ?? "",
1431
+ resourceUrl: paymentRequired.resource.url,
1432
+ explorerUrl: explorerUrlOrEmpty(status.chainId, status.txHash),
1433
+ accepted: option,
1434
+ paymentHeader,
1435
+ merchantTo: status.merchantAddress ?? option.payTo,
1436
+ payer: this.x402Wallet,
1437
+ chainId: status.chainId || chainIdFromNetwork(option.network)
1438
+ });
1439
+ }
1440
+ buildX402Receipt(input) {
1441
+ const fundingExplorerUrl = input.explorerUrl || explorerUrlOrEmpty(input.chainId, input.txHash);
1442
+ return {
1443
+ success: true,
1444
+ paymentId: input.paymentId,
1445
+ txHash: input.txHash,
1446
+ token: input.token,
1447
+ amount: input.amount,
1448
+ to: input.to,
1449
+ resourceUrl: input.resourceUrl,
1450
+ explorerUrl: input.explorerUrl,
1451
+ accepted: input.accepted,
1452
+ paymentHeader: input.paymentHeader,
1453
+ merchantTo: input.merchantTo ?? input.accepted.payTo,
1454
+ payer: input.payer,
1455
+ chainId: input.chainId,
1456
+ haven: {
1457
+ paymentId: input.paymentId,
1458
+ fundingTxHash: input.txHash,
1459
+ fundingExplorerUrl
1460
+ },
1461
+ merchant: {
1462
+ payTo: input.merchantTo ?? input.accepted.payTo
1463
+ },
1464
+ x402: {
1465
+ amount: input.accepted.amount,
1466
+ token: input.token,
1467
+ network: input.accepted.network,
1468
+ asset: input.accepted.asset,
1469
+ resource: input.accepted.resource ?? input.resourceUrl
1470
+ }
1471
+ };
1472
+ }
828
1473
  async createStandardX402Header(paymentRequired, option) {
829
1474
  if (!this.delegateKey) {
830
1475
  throw new HavenSigningError("delegateKey is required to sign x402 payment headers.");
@@ -870,6 +1515,33 @@ var HavenClient = class {
870
1515
  proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
871
1516
  };
872
1517
  }
1518
+ mapMachinePaymentReceiptFromStatus(challenge, status) {
1519
+ if (!status.txHash) {
1520
+ throw new HavenApiError(
1521
+ `MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1522
+ 502,
1523
+ status,
1524
+ status.paymentId
1525
+ );
1526
+ }
1527
+ const receiptWithoutHeader = {
1528
+ success: true,
1529
+ rail: challenge.rail,
1530
+ paymentId: status.paymentId,
1531
+ challengeId: challenge.challengeId,
1532
+ txHash: status.txHash,
1533
+ token: status.token || challenge.asset.symbol,
1534
+ amount: status.amount || challenge.amount.display,
1535
+ to: status.merchantAddress ?? challenge.recipient,
1536
+ resourceUrl: status.resourceUrl ?? challenge.resource,
1537
+ explorerUrl: explorerUrlOrEmpty(status.chainId || challenge.network.chainId, status.txHash),
1538
+ chainId: status.chainId || challenge.network.chainId
1539
+ };
1540
+ return {
1541
+ ...receiptWithoutHeader,
1542
+ proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
1543
+ };
1544
+ }
873
1545
  async recordMerchantRetryRejected(input) {
874
1546
  try {
875
1547
  await this.post("/machine-payments/reconciliation-events", {
@@ -953,16 +1625,64 @@ var HavenClient = class {
953
1625
  amount,
954
1626
  token,
955
1627
  resourceUrl: raw.resource_url ?? null,
956
- merchantAddress: raw.merchant_to ?? null,
1628
+ merchantAddress: raw.merchant_address ?? raw.merchant_to ?? null,
957
1629
  txHash: raw.tx_hash ?? null,
958
1630
  expiresAt: raw.expires_at ?? "",
959
1631
  chainId: raw.chain_id ?? 0,
960
- message
1632
+ message,
1633
+ amountAtomic: raw.amount_atomic ?? raw.x402?.amount_atomic ?? raw.mpp?.amount_atomic ?? null,
1634
+ asset: raw.asset ?? raw.x402?.asset ?? raw.mpp?.asset ?? null,
1635
+ network: raw.network ?? raw.x402?.network ?? raw.mpp?.network ?? null,
1636
+ description: raw.description ?? raw.x402?.description ?? raw.mpp?.description ?? null,
1637
+ idempotencyKey: raw.idempotency_key ?? raw.x402?.idempotency_key ?? raw.mpp?.idempotency_key ?? null,
1638
+ x402: raw.x402 ? {
1639
+ amountAtomic: raw.x402.amount_atomic ?? raw.amount_atomic ?? null,
1640
+ asset: raw.x402.asset ?? raw.asset ?? null,
1641
+ network: raw.x402.network ?? raw.network ?? null,
1642
+ resourceUrl: raw.x402.resource_url ?? raw.resource_url ?? null,
1643
+ merchantAddress: raw.x402.merchant_address ?? raw.merchant_address ?? raw.merchant_to ?? null,
1644
+ description: raw.x402.description ?? raw.description ?? null,
1645
+ idempotencyKey: raw.x402.idempotency_key ?? raw.idempotency_key ?? null
1646
+ } : void 0,
1647
+ mpp: raw.mpp ? {
1648
+ amountAtomic: raw.mpp.amount_atomic ?? raw.amount_atomic ?? null,
1649
+ asset: raw.mpp.asset ?? raw.asset ?? null,
1650
+ network: raw.mpp.network ?? raw.network ?? null,
1651
+ resourceUrl: raw.mpp.resource_url ?? raw.resource_url ?? null,
1652
+ merchantAddress: raw.mpp.merchant_address ?? raw.merchant_address ?? raw.merchant_to ?? null,
1653
+ description: raw.mpp.description ?? raw.description ?? null,
1654
+ idempotencyKey: raw.mpp.idempotency_key ?? raw.idempotency_key ?? null,
1655
+ challengeId: raw.mpp.challenge_id ?? raw.challenge_id ?? null
1656
+ } : void 0
961
1657
  };
962
1658
  }
963
1659
  x402PayerAddress() {
964
1660
  return this.delegateAddress ?? this.x402Wallet;
965
1661
  }
1662
+ snapshotX402Request(url, init) {
1663
+ return {
1664
+ url,
1665
+ method: init?.method ?? "GET",
1666
+ headers: Array.from(new Headers(init?.headers).entries()),
1667
+ body: this.snapshotRequestBody(init?.body)
1668
+ };
1669
+ }
1670
+ snapshotRequestBody(body) {
1671
+ if (body == null) return void 0;
1672
+ if (typeof body === "string") return body;
1673
+ if (body instanceof URLSearchParams) return body.toString();
1674
+ throw new HavenApiError(
1675
+ "Quote helpers can only capture resumable request bodies that are strings or URLSearchParams. For streams, blobs, or binary bodies, preserve the original request yourself and call the matching resume method with fresh init.",
1676
+ 400
1677
+ );
1678
+ }
1679
+ requestInitFromSnapshot(request) {
1680
+ return {
1681
+ method: request.method,
1682
+ headers: request.headers,
1683
+ body: request.body
1684
+ };
1685
+ }
966
1686
  withX402Wallet(init, wallet = this.x402PayerAddress()) {
967
1687
  if (!wallet) return init;
968
1688
  const headers = new Headers(init?.headers);
@@ -974,6 +1694,134 @@ var HavenClient = class {
974
1694
  headers
975
1695
  };
976
1696
  }
1697
+ buildX402Quote(paymentRequired, request, idempotencyKey) {
1698
+ const option = selectStandardPaymentOption(paymentRequired.accepts);
1699
+ if (!option) {
1700
+ throw new HavenApiError(
1701
+ "No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC.",
1702
+ 400
1703
+ );
1704
+ }
1705
+ const token = resolveTokenFromAddress(option.asset, option.network);
1706
+ return {
1707
+ rail: "x402",
1708
+ idempotencyKey: idempotencyKey ?? buildX402IdempotencyKey(paymentRequired, option),
1709
+ paymentRequired,
1710
+ accepted: option,
1711
+ request,
1712
+ resourceUrl: paymentRequired.resource.url,
1713
+ description: paymentRequired.resource.description ?? option.description ?? null,
1714
+ mimeType: paymentRequired.resource.mimeType ?? option.mimeType ?? null,
1715
+ amountAtomic: option.amount,
1716
+ amount: decimalFromUsdcAtomic(option.amount),
1717
+ token: token?.symbol ?? "USDC",
1718
+ asset: option.asset,
1719
+ network: option.network,
1720
+ chainId: chainIdOrNull(option.network),
1721
+ merchantAddress: option.payTo,
1722
+ maxTimeoutSeconds: option.maxTimeoutSeconds
1723
+ };
1724
+ }
1725
+ buildX402ResumeState(input) {
1726
+ const token = resolveTokenFromAddress(input.accepted.asset, input.accepted.network);
1727
+ return {
1728
+ rail: "x402",
1729
+ paymentId: input.paymentId,
1730
+ idempotencyKey: input.idempotencyKey,
1731
+ paymentRequired: input.paymentRequired,
1732
+ accepted: input.accepted,
1733
+ url: input.request?.url ?? input.paymentRequired.resource.url,
1734
+ request: input.request,
1735
+ resourceUrl: input.paymentRequired.resource.url,
1736
+ description: input.paymentRequired.resource.description ?? input.accepted.description ?? null,
1737
+ amountAtomic: input.accepted.amount,
1738
+ amount: decimalFromUsdcAtomic(input.accepted.amount),
1739
+ token: token?.symbol ?? "USDC",
1740
+ asset: input.accepted.asset,
1741
+ network: input.accepted.network,
1742
+ chainId: chainIdOrNull(input.accepted.network),
1743
+ merchantAddress: input.accepted.payTo
1744
+ };
1745
+ }
1746
+ buildMppQuote(challenge, request, idempotencyKey) {
1747
+ return {
1748
+ rail: "mpp",
1749
+ paymentRail: challenge.rail,
1750
+ idempotencyKey: idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge),
1751
+ challenge,
1752
+ request,
1753
+ resourceUrl: challenge.resource,
1754
+ description: challenge.description ?? null,
1755
+ amountAtomic: challenge.amount.atomic,
1756
+ amount: challenge.amount.display,
1757
+ token: challenge.asset.symbol,
1758
+ asset: challenge.asset.address,
1759
+ network: challenge.network.name,
1760
+ chainId: challenge.network.chainId,
1761
+ merchantAddress: challenge.recipient,
1762
+ expiresAt: challenge.expiresAt
1763
+ };
1764
+ }
1765
+ buildMppResumeState(input) {
1766
+ const quote = this.buildMppQuote(
1767
+ input.challenge,
1768
+ input.request ?? this.snapshotX402Request(input.challenge.resource),
1769
+ input.idempotencyKey
1770
+ );
1771
+ return {
1772
+ rail: "mpp",
1773
+ paymentRail: quote.paymentRail,
1774
+ paymentId: input.paymentId,
1775
+ idempotencyKey: quote.idempotencyKey,
1776
+ challenge: input.challenge,
1777
+ url: input.request?.url ?? input.challenge.resource,
1778
+ request: input.request,
1779
+ resourceUrl: quote.resourceUrl,
1780
+ description: quote.description,
1781
+ amountAtomic: quote.amountAtomic,
1782
+ amount: quote.amount,
1783
+ token: quote.token,
1784
+ asset: quote.asset,
1785
+ network: quote.network,
1786
+ chainId: quote.chainId,
1787
+ merchantAddress: quote.merchantAddress,
1788
+ expiresAt: quote.expiresAt
1789
+ };
1790
+ }
1791
+ attachResumeState(err, input) {
1792
+ if (input.rail === "x402") {
1793
+ this.attachX402ResumeState(
1794
+ err,
1795
+ input.paymentRequired,
1796
+ input.accepted,
1797
+ input.idempotencyKey,
1798
+ input.request
1799
+ );
1800
+ return;
1801
+ }
1802
+ this.attachMppResumeState(err, input.challenge, input.idempotencyKey, input.request);
1803
+ }
1804
+ attachX402ResumeState(err, paymentRequired, accepted, idempotencyKey, request) {
1805
+ if (!(err instanceof HavenPaymentStateError)) return;
1806
+ if (err.state.rail !== "x402") return;
1807
+ err.resumeState = this.buildX402ResumeState({
1808
+ paymentId: err.state.paymentId,
1809
+ paymentRequired,
1810
+ accepted,
1811
+ idempotencyKey,
1812
+ request
1813
+ });
1814
+ }
1815
+ attachMppResumeState(err, challenge, idempotencyKey, request) {
1816
+ if (!(err instanceof HavenPaymentStateError)) return;
1817
+ if (!isMppRail(err.state.rail)) return;
1818
+ err.resumeState = this.buildMppResumeState({
1819
+ paymentId: err.state.paymentId,
1820
+ challenge,
1821
+ idempotencyKey,
1822
+ request
1823
+ });
1824
+ }
977
1825
  // ── Tool Execution (for agent frameworks) ────────────────────────
978
1826
  /**
979
1827
  * Execute a tool call by name and input.
@@ -1008,44 +1856,34 @@ var HavenClient = class {
1008
1856
  }
1009
1857
  }
1010
1858
  if (toolName === "authorize_x402_payment") {
1011
- const { url, payTo, amount, asset, network, description } = input;
1859
+ const { url, payTo, amount, asset, network, description, idempotencyKey } = input;
1012
1860
  try {
1013
- const receipt = await this.authorizeX402({
1014
- x402Version: 2,
1015
- resource: { url, description },
1016
- accepts: [
1017
- {
1018
- scheme: "exact",
1019
- network,
1020
- amount,
1021
- asset,
1022
- payTo,
1023
- maxTimeoutSeconds: 30
1024
- }
1025
- ]
1861
+ const receipt = await this.authorizeX402(
1862
+ this.toolX402PaymentRequired({ url, payTo, amount, asset, network, description }),
1863
+ { idempotencyKey }
1864
+ );
1865
+ return this.x402ToolReceipt(receipt);
1866
+ } catch (err) {
1867
+ return this.toolError(err);
1868
+ }
1869
+ }
1870
+ if (toolName === "resume_x402_payment") {
1871
+ const { payment_id, url, payTo, amount, asset, network, description, idempotencyKey } = input;
1872
+ try {
1873
+ const receipt = await this.resumeAuthorizedX402({
1874
+ paymentId: payment_id,
1875
+ paymentRequired: this.toolX402PaymentRequired({ url, payTo, amount, asset, network, description }),
1876
+ idempotencyKey
1026
1877
  });
1027
- return {
1028
- success: true,
1029
- payment_id: receipt.paymentId,
1030
- tx_hash: receipt.txHash,
1031
- token: receipt.token,
1032
- amount: receipt.amount,
1033
- to: receipt.to,
1034
- resource_url: receipt.resourceUrl,
1035
- explorer_url: receipt.explorerUrl,
1036
- payment_header: receipt.paymentHeader,
1037
- merchant_to: receipt.merchantTo,
1038
- payer: receipt.payer,
1039
- chain_id: receipt.chainId
1040
- };
1878
+ return this.x402ToolReceipt(receipt);
1041
1879
  } catch (err) {
1042
1880
  return this.toolError(err);
1043
1881
  }
1044
1882
  }
1045
1883
  if (toolName === "authorize_machine_payment") {
1046
- const { challenge } = input;
1884
+ const { challenge, idempotencyKey } = input;
1047
1885
  try {
1048
- const receipt = await this.authorizeMachinePayment(challenge);
1886
+ const receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
1049
1887
  return {
1050
1888
  success: true,
1051
1889
  payment_id: receipt.paymentId,
@@ -1080,6 +1918,13 @@ var HavenClient = class {
1080
1918
  amount: result.amount,
1081
1919
  resource_url: result.resourceUrl,
1082
1920
  merchant_address: result.merchantAddress,
1921
+ amount_atomic: result.amountAtomic,
1922
+ asset: result.asset,
1923
+ network: result.network,
1924
+ description: result.description,
1925
+ idempotency_key: result.idempotencyKey,
1926
+ x402: result.x402,
1927
+ mpp: result.mpp,
1083
1928
  expires_at: result.expiresAt,
1084
1929
  chain_id: result.chainId,
1085
1930
  message: result.message
@@ -1087,6 +1932,41 @@ var HavenClient = class {
1087
1932
  }
1088
1933
  throw new Error(`Unknown tool: ${toolName}`);
1089
1934
  }
1935
+ toolX402PaymentRequired(input) {
1936
+ return {
1937
+ x402Version: 2,
1938
+ resource: { url: input.url, description: input.description },
1939
+ accepts: [
1940
+ {
1941
+ scheme: "exact",
1942
+ network: input.network,
1943
+ amount: input.amount,
1944
+ asset: input.asset,
1945
+ payTo: input.payTo,
1946
+ maxTimeoutSeconds: 30
1947
+ }
1948
+ ]
1949
+ };
1950
+ }
1951
+ x402ToolReceipt(receipt) {
1952
+ return {
1953
+ success: true,
1954
+ payment_id: receipt.paymentId,
1955
+ tx_hash: receipt.txHash,
1956
+ token: receipt.token,
1957
+ amount: receipt.amount,
1958
+ to: receipt.to,
1959
+ resource_url: receipt.resourceUrl,
1960
+ explorer_url: receipt.explorerUrl,
1961
+ payment_header: receipt.paymentHeader,
1962
+ merchant_to: receipt.merchantTo,
1963
+ payer: receipt.payer,
1964
+ chain_id: receipt.chainId,
1965
+ haven: receipt.haven,
1966
+ merchant: receipt.merchant,
1967
+ x402: receipt.x402
1968
+ };
1969
+ }
1090
1970
  toolError(err) {
1091
1971
  if (err instanceof HavenPaymentStateError) {
1092
1972
  return {
@@ -1102,6 +1982,31 @@ var HavenClient = class {
1102
1982
  amount: err.state.amount,
1103
1983
  resource_url: err.state.resourceUrl,
1104
1984
  merchant_address: err.state.merchantAddress,
1985
+ amount_atomic: err.state.amountAtomic,
1986
+ asset: err.state.asset,
1987
+ network: err.state.network,
1988
+ description: err.state.description,
1989
+ idempotency_key: err.state.idempotencyKey,
1990
+ x402: err.state.x402 ? {
1991
+ amount_atomic: err.state.x402.amountAtomic,
1992
+ asset: err.state.x402.asset,
1993
+ network: err.state.x402.network,
1994
+ resource_url: err.state.x402.resourceUrl,
1995
+ merchant_address: err.state.x402.merchantAddress,
1996
+ description: err.state.x402.description,
1997
+ idempotency_key: err.state.x402.idempotencyKey
1998
+ } : void 0,
1999
+ mpp: err.state.mpp ? {
2000
+ amount_atomic: err.state.mpp.amountAtomic,
2001
+ asset: err.state.mpp.asset,
2002
+ network: err.state.mpp.network,
2003
+ resource_url: err.state.mpp.resourceUrl,
2004
+ merchant_address: err.state.mpp.merchantAddress,
2005
+ description: err.state.mpp.description,
2006
+ idempotency_key: err.state.mpp.idempotencyKey,
2007
+ challenge_id: err.state.mpp.challengeId
2008
+ } : void 0,
2009
+ resume_state: err.resumeState,
1105
2010
  expires_at: err.state.expiresAt,
1106
2011
  chain_id: err.state.chainId,
1107
2012
  message: err.state.message,
@@ -1133,11 +2038,14 @@ var HavenClient = class {
1133
2038
  const controller = new AbortController();
1134
2039
  const timeout = setTimeout(() => controller.abort(), this.requestTimeout);
1135
2040
  try {
2041
+ const contextHeaders = this.requestContext.getStore()?.headers ?? {};
1136
2042
  const res = await fetch(url, {
1137
2043
  method,
1138
2044
  headers: {
1139
2045
  "Content-Type": "application/json",
1140
- "Authorization": `Bearer ${this.apiKey}`
2046
+ "Authorization": `Bearer ${this.apiKey}`,
2047
+ ...this.defaultHeaders,
2048
+ ...contextHeaders
1141
2049
  },
1142
2050
  body: body ? JSON.stringify(body) : void 0,
1143
2051
  signal: controller.signal
@@ -1194,7 +2102,50 @@ var HavenClient = class {
1194
2102
  txHash: raw.tx_hash,
1195
2103
  expiresAt: raw.expires_at,
1196
2104
  chainId: raw.chain_id,
1197
- message: raw.message
2105
+ message: raw.message,
2106
+ amountAtomic: raw.amount_atomic ?? raw.x402?.amount_atomic ?? null,
2107
+ asset: raw.asset ?? raw.x402?.asset ?? null,
2108
+ network: raw.network ?? raw.x402?.network ?? null,
2109
+ description: raw.description ?? raw.x402?.description ?? null,
2110
+ idempotencyKey: raw.idempotency_key ?? raw.x402?.idempotency_key ?? null,
2111
+ x402: raw.x402 ? {
2112
+ amountAtomic: raw.x402.amount_atomic ?? raw.amount_atomic ?? null,
2113
+ asset: raw.x402.asset ?? raw.asset ?? null,
2114
+ network: raw.x402.network ?? raw.network ?? null,
2115
+ resourceUrl: raw.x402.resource_url ?? raw.resource_url,
2116
+ merchantAddress: raw.x402.merchant_address ?? raw.merchant_address,
2117
+ description: raw.x402.description ?? raw.description ?? null,
2118
+ idempotencyKey: raw.x402.idempotency_key ?? raw.idempotency_key ?? null
2119
+ } : void 0
2120
+ };
2121
+ }
2122
+ mapPaymentReceipt(raw) {
2123
+ return {
2124
+ id: raw.id,
2125
+ paymentId: raw.payment_id,
2126
+ rail: raw.rail,
2127
+ proofStatus: raw.proof_status,
2128
+ txHash: raw.tx_hash,
2129
+ chainId: raw.chain_id,
2130
+ resourceUrl: raw.resource_url,
2131
+ merchantAddress: raw.merchant_address,
2132
+ payerAddress: raw.payer_address,
2133
+ settlementAddress: raw.settlement_address,
2134
+ tokenSymbol: raw.token_symbol,
2135
+ tokenAddress: raw.token_address,
2136
+ amountRaw: raw.amount_raw,
2137
+ amount: raw.amount_human,
2138
+ challengeId: raw.challenge_id,
2139
+ idempotencyKey: raw.idempotency_key,
2140
+ challengePayload: raw.challenge_payload,
2141
+ selectedPayment: raw.selected_payment,
2142
+ paymentProofHeaderName: raw.payment_proof_header_name,
2143
+ protocolReceiptHeaderName: raw.protocol_receipt_header_name,
2144
+ protocolReceiptPayload: raw.protocol_receipt_payload,
2145
+ merchantStatus: raw.merchant_status,
2146
+ confirmedAt: raw.confirmed_at,
2147
+ createdAt: raw.created_at,
2148
+ updatedAt: raw.updated_at
1198
2149
  };
1199
2150
  }
1200
2151
  };
@@ -1295,10 +2246,52 @@ var authorizeX402Schema = {
1295
2246
  description: {
1296
2247
  type: "string",
1297
2248
  description: "Description of the resource being paid for"
2249
+ },
2250
+ idempotencyKey: {
2251
+ type: "string",
2252
+ description: "Stable caller-supplied key for this user intent. Reuse it when resuming after user approval."
1298
2253
  }
1299
2254
  },
1300
2255
  required: ["url", "payTo", "amount", "asset", "network"]
1301
2256
  };
2257
+ var resumeX402Schema = {
2258
+ type: "object",
2259
+ properties: {
2260
+ payment_id: {
2261
+ type: "string",
2262
+ description: "The payment or approval request ID returned by authorize_x402_payment."
2263
+ },
2264
+ url: {
2265
+ type: "string",
2266
+ description: "The original URL that returned HTTP 402."
2267
+ },
2268
+ payTo: {
2269
+ type: "string",
2270
+ description: "Payment recipient address from the original 402 response."
2271
+ },
2272
+ amount: {
2273
+ type: "string",
2274
+ description: "Payment amount in atomic units from the original 402 response."
2275
+ },
2276
+ asset: {
2277
+ type: "string",
2278
+ description: "Token contract address from the original 402 response."
2279
+ },
2280
+ network: {
2281
+ type: "string",
2282
+ description: "CAIP-2 chain ID or x402 network from the original 402 response."
2283
+ },
2284
+ description: {
2285
+ type: "string",
2286
+ description: "Description of the resource being paid for."
2287
+ },
2288
+ idempotencyKey: {
2289
+ type: "string",
2290
+ description: "Stable caller-supplied key used for the original authorization."
2291
+ }
2292
+ },
2293
+ required: ["payment_id", "url", "payTo", "amount", "asset", "network"]
2294
+ };
1302
2295
  var authorizeMachinePaymentSchema = {
1303
2296
  type: "object",
1304
2297
  properties: {
@@ -1311,7 +2304,8 @@ var authorizeMachinePaymentSchema = {
1311
2304
  };
1312
2305
  var MAKE_PAYMENT_DESCRIPTION = "Request and sign a payment from the user-controlled Safe within approved on-chain limits. Haven authenticates the agent, validates the signed intent, and relays the Safe AllowanceModule transaction; it does not hold keys or control funds. Gnosis Chain tokens: EURe, USDC.e, xDAI. Base tokens: USDC, ETH.";
1313
2306
  var GET_STATUS_DESCRIPTION = "Check the status of a previously initiated payment. Accepts payment intent IDs and approval request IDs. Returns the current status, phase, next_action, transaction hash if available, and payment details.";
1314
- var AUTHORIZE_X402_DESCRIPTION = "Authorize payment for an HTTP 402 (Payment Required) response. When a paid API returns x402 payment requirements, use this tool to sign with the agent-owned delegate key and request a policy-limited Safe AllowanceModule top-up when needed. Haven relays signed transactions only; the agent key authorizes payment and on-chain limits enforce spend. If this returns pending_approval, tell the user it is waiting in Haven, call get_payment_status later, and retry the original x402 request only when next_action is retry_original_x402_request. Do not rewrite the SDK or loop retries while approval is pending. Use the returned payment_header as the X-PAYMENT header on the retry request.";
2307
+ var AUTHORIZE_X402_DESCRIPTION = "Authorize payment for an HTTP 402 (Payment Required) response. When a paid API returns x402 payment requirements, use this tool to sign with the agent-owned delegate key and request a policy-limited Safe AllowanceModule top-up when needed. Haven relays signed transactions only; the agent key authorizes payment and on-chain limits enforce spend. If this returns pending_approval, tell the user it is waiting in Haven, preserve the original merchant/MCP session and x402 details, call get_payment_status later, and use resume_x402_payment only when next_action is retry_original_x402_request. Do not start a new merchant session or loop retries while approval is pending. Use the returned payment_header as the X-PAYMENT header on the retry request when doing a manual HTTP retry.";
2308
+ var RESUME_X402_DESCRIPTION = "Resume an x402 payment after the user approved it in Haven. Use this only after get_payment_status returns next_action=retry_original_x402_request. It checks the approved payment, validates the original x402 details, and returns a merchant X-PAYMENT header without creating a new approval request or merchant session.";
1315
2309
  var AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION = "Authorize a Haven machine-payment challenge, currently for the internal MPP demo rail. The agent signs the payment, Haven relays it within the on-chain allowance, and the tool returns a proof header for the retry request.";
1316
2310
  function claudeTools() {
1317
2311
  return [
@@ -1330,6 +2324,11 @@ function claudeTools() {
1330
2324
  description: AUTHORIZE_X402_DESCRIPTION,
1331
2325
  input_schema: authorizeX402Schema
1332
2326
  },
2327
+ {
2328
+ name: "resume_x402_payment",
2329
+ description: RESUME_X402_DESCRIPTION,
2330
+ input_schema: resumeX402Schema
2331
+ },
1333
2332
  {
1334
2333
  name: "authorize_machine_payment",
1335
2334
  description: AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION,
@@ -1363,6 +2362,14 @@ function openaiTools() {
1363
2362
  parameters: authorizeX402Schema
1364
2363
  }
1365
2364
  },
2365
+ {
2366
+ type: "function",
2367
+ function: {
2368
+ name: "resume_x402_payment",
2369
+ description: RESUME_X402_DESCRIPTION,
2370
+ parameters: resumeX402Schema
2371
+ }
2372
+ },
1366
2373
  {
1367
2374
  type: "function",
1368
2375
  function: {
@@ -1380,6 +2387,6 @@ var havenTools = {
1380
2387
  openai: openaiTools
1381
2388
  };
1382
2389
 
1383
- export { HavenApiError, HavenClient, HavenError, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, addressFromKey, buildMachinePaymentIdempotencyKey, encodeMachinePaymentProof, encodePaymentProof, havenTools, parseMachinePaymentChallenge, parseMachinePaymentChallengeResponse, parsePaymentRequired, parsePaymentRequiredResponse, selectPaymentOption, signHash, verifySignature };
2390
+ export { AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, HavenApiError, HavenClient, HavenError, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, addressFromKey, buildMachinePaymentIdempotencyKey, encodeMachinePaymentProof, encodePaymentProof, havenTools, parseMachinePaymentChallenge, parseMachinePaymentChallengeResponse, parsePaymentRequired, parsePaymentRequiredResponse, selectPaymentOption, signHash, verifySignature };
1384
2391
  //# sourceMappingURL=index.js.map
1385
2392
  //# sourceMappingURL=index.js.map