@haven_ai/sdk 0.1.3 → 0.1.5

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.cjs CHANGED
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var async_hooks = require('async_hooks');
3
4
  var schemes = require('x402/schemes');
4
5
  var accounts = require('viem/accounts');
5
6
  var ethers = require('ethers');
@@ -8,6 +9,114 @@ var crypto = require('crypto');
8
9
  // src/client.ts
9
10
 
10
11
  // src/types.ts
12
+ var AgentPaymentPhase = {
13
+ /** The agent must sign and submit the prepared payment before Haven can relay it. */
14
+ AgentSignatureRequired: "agent_signature_required",
15
+ /** Haven has received the signed payment and the agent should poll for confirmation. */
16
+ PaymentSubmitted: "payment_submitted",
17
+ /** The direct payment is confirmed; the agent does not need to do more for this payment id. */
18
+ PaymentConfirmed: "payment_confirmed",
19
+ /** The payment needs wallet owner approval in Haven before it can continue. */
20
+ UserApprovalRequired: "user_approval_required",
21
+ /** The wallet owner approved the request and still needs to complete the funding payment. */
22
+ UserExecutionRequired: "user_execution_required",
23
+ /** The funding payment was proposed and is waiting for the remaining account approvals. */
24
+ WaitingForAdditionalApprovals: "waiting_for_additional_approvals",
25
+ /** The Haven funding leg was sent; the agent can continue the merchant/protocol leg. */
26
+ FundingSent: "funding_sent",
27
+ /** The wallet owner rejected the request; the agent should stop and tell the user. */
28
+ Rejected: "rejected",
29
+ /** The payment or approval request expired before completion. */
30
+ Expired: "expired",
31
+ /** Haven could not complete the payment; the agent should stop and surface the failure. */
32
+ Failed: "failed"
33
+ };
34
+ var AgentPaymentNextAction = {
35
+ /** Sign with the delegate key and submit the payment to Haven. */
36
+ SignAndSubmitPayment: "sign_and_submit_payment",
37
+ /** Poll getPaymentStatus later using this payment id. */
38
+ CheckStatusLater: "check_status_later",
39
+ /** No further agent action is required for this payment id. */
40
+ None: "none",
41
+ /** Wait for the wallet owner to approve or reject the request in Haven. */
42
+ WaitForUserApproval: "wait_for_user_approval",
43
+ /** Wait for the wallet owner to finish sending the approved funding payment. */
44
+ WaitForUserToCompletePayment: "wait_for_user_to_complete_payment",
45
+ /** Resume this payment id and retry the original x402 request with the merchant payment header. */
46
+ RetryOriginalX402Request: "retry_original_x402_request",
47
+ /** Stop retrying this payment and tell the user what happened. */
48
+ StopAndTellUser: "stop_and_tell_user",
49
+ /** Ask again only if the user still wants the payment after expiry. */
50
+ RequestAgainIfUserStillWantsIt: "request_again_if_user_still_wants_it"
51
+ };
52
+ var AgentPaymentRail = {
53
+ /** Standard Haven payment from the user's Safe through an approved delegate allowance. */
54
+ Direct: "direct",
55
+ /** x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg. */
56
+ X402: "x402",
57
+ /** Machine Payment Protocol family — categorical value used as a resume-state discriminator. */
58
+ Mpp: "mpp",
59
+ /** Haven internal MPP demo rail. Not for production traffic. */
60
+ MppDemo: "mpp_demo",
61
+ /** Crypto-settled MPP rail. */
62
+ MppCrypto: "mpp_crypto",
63
+ /** Stripe-deposit-backed MPP rail. */
64
+ StripeDeposit: "stripe_deposit",
65
+ /** Stripe Payment Token MPP rail. */
66
+ Spt: "spt"
67
+ };
68
+ var AGENT_PAYMENT_PHASE_VALUES = Object.values(AgentPaymentPhase);
69
+ var AGENT_PAYMENT_NEXT_ACTION_VALUES = Object.values(AgentPaymentNextAction);
70
+ var AGENT_PAYMENT_RAIL_VALUES = Object.values(AgentPaymentRail);
71
+ var AgentPaymentPhaseDescriptions = {
72
+ [AgentPaymentPhase.AgentSignatureRequired]: "The agent must sign and submit the prepared payment before Haven can relay it.",
73
+ [AgentPaymentPhase.PaymentSubmitted]: "Haven has received the signed payment and the agent should poll for confirmation.",
74
+ [AgentPaymentPhase.PaymentConfirmed]: "The direct payment is confirmed; the agent does not need to do more for this payment id.",
75
+ [AgentPaymentPhase.UserApprovalRequired]: "The payment needs wallet owner approval in Haven before it can continue.",
76
+ [AgentPaymentPhase.UserExecutionRequired]: "The wallet owner approved the request and still needs to complete the funding payment.",
77
+ [AgentPaymentPhase.WaitingForAdditionalApprovals]: "The funding payment was proposed and is waiting for the remaining account approvals.",
78
+ [AgentPaymentPhase.FundingSent]: "The Haven funding leg was sent; the agent can continue the merchant/protocol leg.",
79
+ [AgentPaymentPhase.Rejected]: "The wallet owner rejected the request; the agent should stop and tell the user.",
80
+ [AgentPaymentPhase.Expired]: "The payment or approval request expired before completion.",
81
+ [AgentPaymentPhase.Failed]: "Haven could not complete the payment; the agent should stop and surface the failure."
82
+ };
83
+ var AgentPaymentNextActionDescriptions = {
84
+ [AgentPaymentNextAction.SignAndSubmitPayment]: "Sign with the delegate key and submit the payment to Haven.",
85
+ [AgentPaymentNextAction.CheckStatusLater]: "Poll getPaymentStatus later using this payment id.",
86
+ [AgentPaymentNextAction.None]: "No further agent action is required for this payment id.",
87
+ [AgentPaymentNextAction.WaitForUserApproval]: "Wait for the wallet owner to approve or reject the request in Haven.",
88
+ [AgentPaymentNextAction.WaitForUserToCompletePayment]: "Wait for the wallet owner to finish sending the approved funding payment.",
89
+ [AgentPaymentNextAction.RetryOriginalX402Request]: "Resume this payment id and retry the original x402 request with the merchant payment header.",
90
+ [AgentPaymentNextAction.StopAndTellUser]: "Stop retrying this payment and tell the user what happened.",
91
+ [AgentPaymentNextAction.RequestAgainIfUserStillWantsIt]: "Ask again only if the user still wants the payment after expiry."
92
+ };
93
+ var AgentPaymentRailDescriptions = {
94
+ [AgentPaymentRail.Direct]: "Standard Haven payment from the user-controlled Safe through an approved delegate allowance.",
95
+ [AgentPaymentRail.X402]: "x402 HTTP 402 payment flow with a Haven funding leg and merchant retry leg.",
96
+ [AgentPaymentRail.Mpp]: "Categorical MPP rail value used as a resume-state discriminator. Response bodies carry a granular mpp_* value instead.",
97
+ [AgentPaymentRail.MppDemo]: "Haven internal MPP demo rail. Not for production traffic.",
98
+ [AgentPaymentRail.MppCrypto]: "Crypto-settled MPP rail.",
99
+ [AgentPaymentRail.StripeDeposit]: "Stripe-deposit-backed MPP rail.",
100
+ [AgentPaymentRail.Spt]: "Stripe Payment Token MPP rail."
101
+ };
102
+ var AgentPaymentPhaseSchema = {
103
+ type: "string",
104
+ enum: AGENT_PAYMENT_PHASE_VALUES,
105
+ description: "Stable Haven agent payment state phase.",
106
+ "x-enumDescriptions": AgentPaymentPhaseDescriptions
107
+ };
108
+ var AgentPaymentNextActionSchema = {
109
+ type: "string",
110
+ enum: AGENT_PAYMENT_NEXT_ACTION_VALUES,
111
+ description: "Stable next action an agent should take for a Haven payment state.",
112
+ "x-enumDescriptions": AgentPaymentNextActionDescriptions
113
+ };
114
+ var AgentPaymentRailSchema = {
115
+ type: "string",
116
+ enum: AGENT_PAYMENT_RAIL_VALUES,
117
+ description: "Stable rail identifier for Haven agent payment states.",
118
+ "x-enumDescriptions": AgentPaymentRailDescriptions
119
+ };
11
120
  var HavenError = class extends Error {
12
121
  constructor(message, code, statusCode, paymentId) {
13
122
  super(message);
@@ -35,6 +144,7 @@ var HavenPaymentStateError = class extends HavenApiError {
35
144
  this.name = "HavenPaymentStateError";
36
145
  }
37
146
  state;
147
+ resumeState;
38
148
  get status() {
39
149
  return this.state.status;
40
150
  }
@@ -162,6 +272,10 @@ var BASE_TOKENS = {
162
272
  "0x0000000000000000000000000000000000000000": { symbol: "ETH", decimals: 18 },
163
273
  "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913": { symbol: "USDC", decimals: 6 }
164
274
  };
275
+ var ALL_TOKENS = {
276
+ ...GNOSIS_TOKENS,
277
+ ...BASE_TOKENS
278
+ };
165
279
  var NETWORK_TOKENS = {
166
280
  "eip155:100": GNOSIS_TOKENS,
167
281
  "eip155:8453": BASE_TOKENS,
@@ -223,6 +337,23 @@ function selectStandardPaymentOption(accepts) {
223
337
  }
224
338
  return null;
225
339
  }
340
+ function x402AuthorizationAmount(option) {
341
+ return option.maxAmountRequired ?? option.amount;
342
+ }
343
+ function buildX402ExpectedMessage(context) {
344
+ return `Haven x402 expected context v1
345
+ ${stableStringify({
346
+ version: 1,
347
+ kind: "haven.x402.expected",
348
+ paymentId: context.paymentId,
349
+ payloadHash: context.payloadHash.toLowerCase(),
350
+ resourceUrl: context.resourceUrl,
351
+ merchantTo: context.merchantTo.toLowerCase(),
352
+ amount: context.amount,
353
+ asset: context.asset.toLowerCase(),
354
+ network: context.network
355
+ })}`;
356
+ }
226
357
  function toStandardPaymentRequirements(paymentRequired, option) {
227
358
  const network = STANDARD_X402_NETWORKS[option.network];
228
359
  if (!network) {
@@ -234,7 +365,7 @@ function toStandardPaymentRequirements(paymentRequired, option) {
234
365
  return {
235
366
  scheme: "exact",
236
367
  network,
237
- maxAmountRequired: option.maxAmountRequired ?? option.amount,
368
+ maxAmountRequired: x402AuthorizationAmount(option),
238
369
  resource: option.resource ?? paymentRequired.resource.url,
239
370
  description: option.description ?? paymentRequired.resource.description ?? "Haven x402 payment",
240
371
  mimeType: option.mimeType ?? paymentRequired.resource.mimeType ?? "application/octet-stream",
@@ -251,7 +382,7 @@ function buildX402IdempotencyKey(paymentRequired, option, now = Date.now()) {
251
382
  paymentRequired.resource.description ?? "",
252
383
  option.payTo.toLowerCase(),
253
384
  option.asset.toLowerCase(),
254
- option.amount,
385
+ x402AuthorizationAmount(option),
255
386
  option.network,
256
387
  bucket
257
388
  ].join("|");
@@ -273,6 +404,22 @@ function encodePaymentProof(receipt) {
273
404
  };
274
405
  return btoa(JSON.stringify(payload));
275
406
  }
407
+ function resolveTokenFromAddress(address, network) {
408
+ const lower = address.toLowerCase();
409
+ if (network && network in NETWORK_TOKENS) {
410
+ return NETWORK_TOKENS[network][lower] ?? null;
411
+ }
412
+ return ALL_TOKENS[lower] ?? null;
413
+ }
414
+ function stableStringify(value) {
415
+ if (value === null || typeof value !== "object") {
416
+ const primitive = JSON.stringify(value);
417
+ return primitive === void 0 ? "undefined" : primitive;
418
+ }
419
+ if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
420
+ const object = value;
421
+ return `{${Object.keys(object).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(object[key])}`).join(",")}}`;
422
+ }
276
423
  function decodeBase64Json2(value, label) {
277
424
  try {
278
425
  return JSON.parse(atob(value));
@@ -382,30 +529,33 @@ function chainIdFromNetwork(network) {
382
529
  const chainId = Number(network.slice("eip155:".length));
383
530
  return Number.isFinite(chainId) ? chainId : void 0;
384
531
  }
532
+ function chainIdOrNull(network) {
533
+ return chainIdFromNetwork(network) ?? null;
534
+ }
385
535
  function phaseForStatus(status) {
386
- if (status === "pending_signature") return "agent_signature_required";
387
- if (status === "submitted") return "payment_submitted";
388
- if (status === "confirmed") return "payment_confirmed";
389
- if (status === "pending" || status === "pending_approval") return "user_approval_required";
390
- if (status === "approved") return "user_execution_required";
391
- if (status === "proposed") return "waiting_for_additional_approvals";
392
- if (status === "executed") return "funding_sent";
393
- if (status === "rejected") return "rejected";
394
- if (status === "expired") return "expired";
395
- if (status === "failed") return "failed";
536
+ if (status === "pending_signature") return AgentPaymentPhase.AgentSignatureRequired;
537
+ if (status === "submitted") return AgentPaymentPhase.PaymentSubmitted;
538
+ if (status === "confirmed") return AgentPaymentPhase.PaymentConfirmed;
539
+ if (status === "pending" || status === "pending_approval") return AgentPaymentPhase.UserApprovalRequired;
540
+ if (status === "approved") return AgentPaymentPhase.UserExecutionRequired;
541
+ if (status === "proposed") return AgentPaymentPhase.WaitingForAdditionalApprovals;
542
+ if (status === "executed") return AgentPaymentPhase.FundingSent;
543
+ if (status === "rejected") return AgentPaymentPhase.Rejected;
544
+ if (status === "expired") return AgentPaymentPhase.Expired;
545
+ if (status === "failed") return AgentPaymentPhase.Failed;
396
546
  return null;
397
547
  }
398
548
  function nextActionForStatus(status) {
399
- if (status === "pending_signature") return "sign_and_submit_payment";
400
- if (status === "submitted") return "check_status_later";
401
- if (status === "confirmed") return "none";
402
- if (status === "pending" || status === "pending_approval") return "wait_for_user_approval";
403
- if (status === "approved") return "wait_for_user_to_complete_payment";
404
- if (status === "proposed") return "wait_for_user_approval";
405
- if (status === "executed") return "retry_original_x402_request";
406
- if (status === "rejected") return "stop_and_tell_user";
407
- if (status === "expired") return "request_again_if_user_still_wants_it";
408
- if (status === "failed") return "stop_and_tell_user";
549
+ if (status === "pending_signature") return AgentPaymentNextAction.SignAndSubmitPayment;
550
+ if (status === "submitted") return AgentPaymentNextAction.CheckStatusLater;
551
+ if (status === "confirmed") return AgentPaymentNextAction.None;
552
+ if (status === "pending" || status === "pending_approval") return AgentPaymentNextAction.WaitForUserApproval;
553
+ if (status === "approved") return AgentPaymentNextAction.WaitForUserToCompletePayment;
554
+ if (status === "proposed") return AgentPaymentNextAction.WaitForUserApproval;
555
+ if (status === "executed") return AgentPaymentNextAction.RetryOriginalX402Request;
556
+ if (status === "rejected") return AgentPaymentNextAction.StopAndTellUser;
557
+ if (status === "expired") return AgentPaymentNextAction.RequestAgainIfUserStillWantsIt;
558
+ if (status === "failed") return AgentPaymentNextAction.StopAndTellUser;
409
559
  return null;
410
560
  }
411
561
  function messageForState(label, status, paymentId, nextAction) {
@@ -426,6 +576,9 @@ function messageForState(label, status, paymentId, nextAction) {
426
576
  function sameAddress(a, b) {
427
577
  return Boolean(a && b && a.toLowerCase() === b.toLowerCase());
428
578
  }
579
+ function isMppRail(rail) {
580
+ return rail === "mpp" || Boolean(rail?.startsWith("mpp_"));
581
+ }
429
582
  function decimalFromUsdcAtomic(value) {
430
583
  const amount = BigInt(value);
431
584
  const whole = amount / 1000000n;
@@ -456,6 +609,19 @@ var HavenClient = class {
456
609
  inFlightX402 = /* @__PURE__ */ new Map();
457
610
  x402ReceiptCache = /* @__PURE__ */ new Map();
458
611
  inFlightMachinePayments = /* @__PURE__ */ new Map();
612
+ /**
613
+ * Setup-time headers configured via `HavenClientConfig.defaultHeaders`.
614
+ * Read-only after construction — use `withRequestContext` for per-call
615
+ * scoping so concurrent requests don't race on shared mutable state.
616
+ */
617
+ defaultHeaders;
618
+ /**
619
+ * Async-local store for per-request context (currently: extra headers).
620
+ * Each `withRequestContext` invocation produces an isolated store, so
621
+ * overlapping async work — like two MCP tool dispatches in flight at
622
+ * the same time — see their own headers without stepping on each other.
623
+ */
624
+ requestContext = new async_hooks.AsyncLocalStorage();
459
625
  /** Delegate address derived from the private key (if provided) */
460
626
  delegateAddress;
461
627
  constructor(config) {
@@ -466,10 +632,29 @@ var HavenClient = class {
466
632
  this.requestTimeout = config.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
467
633
  this.confirmationTimeout = config.confirmationTimeout ?? DEFAULT_CONFIRMATION_TIMEOUT;
468
634
  this.pollingInterval = config.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
635
+ this.defaultHeaders = { ...config.defaultHeaders ?? {} };
469
636
  if (this.delegateKey) {
470
637
  this.delegateAddress = addressFromKey(this.delegateKey);
471
638
  }
472
639
  }
640
+ /**
641
+ * Run `fn` with extra Haven-API headers scoped to the async work it
642
+ * performs. Used by the MCP server to tag every Haven API request that
643
+ * a single tool dispatch makes with `X-Haven-MCP-Tool: <name>` so the
644
+ * backend can write an audit-log row attributing the call.
645
+ *
646
+ * The headers are held in an `AsyncLocalStorage` so overlapping
647
+ * dispatches do not leak headers into each other's requests. The store
648
+ * inherits across `await` boundaries, so any Haven API call made while
649
+ * `fn` is awaiting will pick up the right headers.
650
+ *
651
+ * Has no effect on outbound merchant requests (x402 / MPP) — those
652
+ * never go through the internal `request<T>` path that reads the
653
+ * context.
654
+ */
655
+ withRequestContext(headers, fn) {
656
+ return this.requestContext.run({ headers: { ...headers } }, fn);
657
+ }
473
658
  // ── High-Level API ───────────────────────────────────────────────
474
659
  /**
475
660
  * Send a payment in one call.
@@ -512,6 +697,70 @@ var HavenClient = class {
512
697
  signData: raw.sign_data
513
698
  };
514
699
  }
700
+ /**
701
+ * Keyless x402 construct.
702
+ *
703
+ * The non-custodial half of an x402 payment: posts the funding request to
704
+ * `/x402` and returns the unsigned funding hash plus the data the caller
705
+ * needs to build and sign the EIP-3009 merchant header itself. Crucially it
706
+ * does **not** sign — neither the funding hash nor the merchant header — so
707
+ * it works without a `delegateKey`. Both delegate signatures happen on the
708
+ * machine that holds the key (the edge); the hosted MCP server relays only.
709
+ *
710
+ * Use this from the hosted, keyless server. The all-in-one `authorizeX402`
711
+ * remains for local clients that hold the key.
712
+ *
713
+ * Throws (via the shared payment-state path) when the amount exceeds the
714
+ * on-chain allowance — there is nothing to sign until the user approves.
715
+ */
716
+ async createX402Intent(paymentRequired, options = {}) {
717
+ const option = selectStandardPaymentOption(paymentRequired.accepts);
718
+ if (!option) {
719
+ throw new HavenApiError(
720
+ "No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC.",
721
+ 400
722
+ );
723
+ }
724
+ const agent = await this.getAgent();
725
+ const fundingTo = agent.delegateAddress;
726
+ if (!fundingTo) {
727
+ throw new HavenApiError("Authenticated agent has no delegate address registered.", 502);
728
+ }
729
+ const idempotencyKey = options.idempotencyKey ?? buildX402IdempotencyKey(paymentRequired, option);
730
+ const raw = await this.post("/x402", {
731
+ url: paymentRequired.resource.url,
732
+ payTo: fundingTo,
733
+ merchantPayTo: option.payTo,
734
+ amount: x402AuthorizationAmount(option),
735
+ asset: option.asset,
736
+ network: option.network,
737
+ description: paymentRequired.resource.description,
738
+ idempotencyKey
739
+ });
740
+ if (raw.status !== "pending_signature") {
741
+ this.throwPaymentStateError("x402 payment", raw);
742
+ }
743
+ if (!raw.sign_data?.hash) {
744
+ throw new HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
745
+ }
746
+ if (!raw.x402_expected_auth) {
747
+ throw new HavenApiError("No x402 expected-context binding returned from x402/authorize", 500, raw);
748
+ }
749
+ return {
750
+ paymentId: raw.payment_id,
751
+ status: "pending_signature",
752
+ expiresAt: raw.expires_at,
753
+ signData: raw.sign_data,
754
+ accepted: option,
755
+ resourceUrl: paymentRequired.resource.url,
756
+ merchantTo: raw.merchant_to ?? option.payTo,
757
+ amountAtomic: x402AuthorizationAmount(option),
758
+ asset: option.asset,
759
+ network: option.network,
760
+ expectedAuth: raw.x402_expected_auth,
761
+ fundingTo
762
+ };
763
+ }
515
764
  /**
516
765
  * Step 2: Sign a hash with the delegate key.
517
766
  *
@@ -564,6 +813,66 @@ var HavenClient = class {
564
813
  const raw = await this.get(`/machine-payments/${paymentId}/status`);
565
814
  return this.mapPaymentStatusResult(raw);
566
815
  }
816
+ /**
817
+ * Get the agent identity tied to this API key.
818
+ */
819
+ async getAgent() {
820
+ const raw = await this.get("/machine-payments/agent");
821
+ return {
822
+ id: raw.id,
823
+ name: raw.name,
824
+ status: raw.status,
825
+ safeAddress: raw.safe_address,
826
+ delegateAddress: raw.delegate_address,
827
+ chainId: raw.chain_id
828
+ };
829
+ }
830
+ /**
831
+ * Get configured and on-chain allowances for the authenticated agent.
832
+ */
833
+ async getAllowances() {
834
+ const raw = await this.get("/machine-payments/allowances");
835
+ return {
836
+ agentId: raw.agent_id,
837
+ safeAddress: raw.safe_address,
838
+ delegateAddress: raw.delegate_address,
839
+ chainId: raw.chain_id,
840
+ allowances: raw.allowances.map((allowance) => ({
841
+ id: allowance.id,
842
+ tokenAddress: allowance.token_address,
843
+ tokenSymbol: allowance.token_symbol,
844
+ configuredAmount: allowance.configured_amount,
845
+ resetPeriodMin: allowance.reset_period_min,
846
+ onchain: {
847
+ amount: allowance.onchain.amount,
848
+ spent: allowance.onchain.spent,
849
+ remaining: allowance.onchain.remaining,
850
+ effectiveSpent: allowance.onchain.effective_spent,
851
+ resetTimeMin: allowance.onchain.reset_time_min,
852
+ lastResetMin: allowance.onchain.last_reset_min,
853
+ nonce: allowance.onchain.nonce,
854
+ isResetPending: allowance.onchain.is_reset_pending
855
+ }
856
+ }))
857
+ };
858
+ }
859
+ /**
860
+ * List recent machine-payment receipts/evidence for bookkeeping.
861
+ */
862
+ async listReceipts(options = {}) {
863
+ const query = options.limit ? `?limit=${encodeURIComponent(String(options.limit))}` : "";
864
+ const raw = await this.get(`/machine-payments/receipts${query}`);
865
+ return raw.receipts.map((receipt) => this.mapPaymentReceipt(receipt));
866
+ }
867
+ /**
868
+ * Rehydrate the x402/MPP resume-state bundle for a payment id.
869
+ *
870
+ * The server returns stored protocol context only. The client still signs the
871
+ * merchant proof locally when resumeX402Payment() or resumeMppPayment() runs.
872
+ */
873
+ async getResumeState(paymentId) {
874
+ return this.get(`/payments/${paymentId}/resume_state`);
875
+ }
567
876
  /**
568
877
  * Poll until a payment reaches a terminal status (confirmed, failed, expired).
569
878
  */
@@ -613,17 +922,69 @@ var HavenClient = class {
613
922
  this.inFlightX402.set(idempotencyKey, promise);
614
923
  try {
615
924
  return await promise;
925
+ } catch (err) {
926
+ this.attachResumeState(err, {
927
+ rail: "x402",
928
+ paymentRequired,
929
+ accepted: option,
930
+ idempotencyKey
931
+ });
932
+ throw err;
616
933
  } finally {
617
934
  this.inFlightX402.delete(idempotencyKey);
618
935
  }
619
936
  }
937
+ /**
938
+ * Probe a paid endpoint and return its x402 quote without creating a Haven
939
+ * payment or approval request.
940
+ */
941
+ async quoteX402(url, init, options = {}) {
942
+ const initialInit = this.withX402Wallet(init, this.x402PayerAddress());
943
+ const request = this.snapshotX402Request(url, initialInit);
944
+ const response = await globalThis.fetch(url, initialInit);
945
+ if (response.status !== 402) {
946
+ throw new HavenApiError(
947
+ `Expected an x402 quote response with HTTP 402, got HTTP ${response.status}.`,
948
+ response.status || 400
949
+ );
950
+ }
951
+ if (response.headers.get("MACHINE-PAYMENT-CHALLENGE")) {
952
+ throw new HavenApiError("quoteX402 only supports standard x402 Payment Required responses.", 400);
953
+ }
954
+ const paymentRequired = await parsePaymentRequiredResponse(response);
955
+ return this.buildX402Quote(paymentRequired, request, options.idempotencyKey);
956
+ }
957
+ /**
958
+ * Pay a previously inspected x402 quote and retry the exact captured request.
959
+ */
960
+ async payX402Quote(quote, options = {}) {
961
+ const idempotencyKey = options.idempotencyKey ?? quote.idempotencyKey;
962
+ try {
963
+ const receipt = await this.authorizeX402(quote.paymentRequired, { idempotencyKey });
964
+ return this.retryX402Request(
965
+ quote.request.url,
966
+ this.requestInitFromSnapshot(quote.request),
967
+ quote.paymentRequired,
968
+ receipt
969
+ );
970
+ } catch (err) {
971
+ this.attachResumeState(err, {
972
+ rail: "x402",
973
+ paymentRequired: quote.paymentRequired,
974
+ accepted: quote.accepted,
975
+ idempotencyKey,
976
+ request: quote.request
977
+ });
978
+ throw err;
979
+ }
980
+ }
620
981
  async authorizeStandardX402(paymentRequired, option, idempotencyKey) {
621
982
  const paymentHeader = await this.createStandardX402Header(paymentRequired, option);
622
983
  const raw = await this.post("/x402", {
623
984
  url: paymentRequired.resource.url,
624
985
  payTo: this.delegateAddress,
625
986
  merchantPayTo: option.payTo,
626
- amount: option.amount,
987
+ amount: x402AuthorizationAmount(option),
627
988
  asset: option.asset,
628
989
  network: option.network,
629
990
  description: paymentRequired.resource.description,
@@ -635,7 +996,7 @@ var HavenClient = class {
635
996
  return receipt2;
636
997
  }
637
998
  const state = this.paymentStateFromRaw("x402 payment", raw);
638
- if (state?.nextAction === "retry_original_x402_request") {
999
+ if (state?.nextAction === AgentPaymentNextAction.RetryOriginalX402Request) {
639
1000
  const receipt2 = this.mapX402ReceiptFromStatus(paymentRequired, option, paymentHeader, state);
640
1001
  this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt2);
641
1002
  return receipt2;
@@ -683,10 +1044,18 @@ var HavenClient = class {
683
1044
  return receipt;
684
1045
  }
685
1046
  async resumeX402Payment(input) {
686
- const initialInit = this.withX402Wallet(input.init, this.x402PayerAddress());
1047
+ const inputInit = "init" in input ? input.init : void 0;
1048
+ const initialInit = this.withX402Wallet(
1049
+ inputInit ?? (input.request ? this.requestInitFromSnapshot(input.request) : void 0),
1050
+ this.x402PayerAddress()
1051
+ );
687
1052
  let paymentRequired = input.paymentRequired;
1053
+ const url = input.url ?? input.request?.url;
688
1054
  if (!paymentRequired) {
689
- const response = await globalThis.fetch(input.url, initialInit);
1055
+ if (!url) {
1056
+ throw new HavenApiError("x402 resume requires the original URL or a captured request snapshot.", 400);
1057
+ }
1058
+ const response = await globalThis.fetch(url, initialInit);
690
1059
  if (response.status !== 402) {
691
1060
  throw new HavenApiError("Expected the original x402 request to return HTTP 402 before resuming.", 400);
692
1061
  }
@@ -697,7 +1066,7 @@ var HavenClient = class {
697
1066
  paymentRequired,
698
1067
  idempotencyKey: input.idempotencyKey
699
1068
  });
700
- return this.retryX402Request(input.url, initialInit, paymentRequired, receipt);
1069
+ return this.retryX402Request(url ?? paymentRequired.resource.url, initialInit, paymentRequired, receipt);
701
1070
  }
702
1071
  /**
703
1072
  * Fetch wrapper that automatically handles HTTP 402 responses.
@@ -733,9 +1102,69 @@ var HavenClient = class {
733
1102
  }
734
1103
  return this.fetchWithMachinePayment(url, initialInit, challenge);
735
1104
  }
736
- const receipt = await this.authorizeX402(paymentRequired, options);
1105
+ const request = this.snapshotX402Request(url, initialInit);
1106
+ const option = selectStandardPaymentOption(paymentRequired.accepts);
1107
+ const idempotencyKey = options.idempotencyKey ?? (option ? buildX402IdempotencyKey(paymentRequired, option) : void 0);
1108
+ let receipt;
1109
+ try {
1110
+ receipt = await this.authorizeX402(paymentRequired, options);
1111
+ } catch (err) {
1112
+ if (option && idempotencyKey) {
1113
+ this.attachResumeState(err, {
1114
+ rail: "x402",
1115
+ paymentRequired,
1116
+ accepted: option,
1117
+ idempotencyKey,
1118
+ request
1119
+ });
1120
+ }
1121
+ throw err;
1122
+ }
737
1123
  return this.retryX402Request(url, initialInit, paymentRequired, receipt);
738
1124
  }
1125
+ /**
1126
+ * Probe a paid MPP endpoint or inspect an existing challenge without creating
1127
+ * a Haven payment or approval request.
1128
+ */
1129
+ async quoteMpp(challengeOrUrl, init, options = {}) {
1130
+ if (typeof challengeOrUrl !== "string") {
1131
+ const request2 = this.snapshotX402Request(challengeOrUrl.resource, init);
1132
+ return this.buildMppQuote(challengeOrUrl, request2, options.idempotencyKey);
1133
+ }
1134
+ const request = this.snapshotX402Request(challengeOrUrl, init);
1135
+ const response = await globalThis.fetch(challengeOrUrl, init);
1136
+ if (response.status !== 402) {
1137
+ throw new HavenApiError(
1138
+ `Expected an MPP quote response with HTTP 402, got HTTP ${response.status}.`,
1139
+ response.status || 400
1140
+ );
1141
+ }
1142
+ const challenge = await parseMachinePaymentChallengeResponse(response);
1143
+ return this.buildMppQuote(challenge, request, options.idempotencyKey);
1144
+ }
1145
+ /**
1146
+ * Pay a previously inspected MPP quote and retry the exact captured request.
1147
+ */
1148
+ async payMppChallenge(quote, options = {}) {
1149
+ const idempotencyKey = options.idempotencyKey ?? quote.idempotencyKey;
1150
+ try {
1151
+ const receipt = await this.authorizeMachinePayment(quote.challenge, { idempotencyKey });
1152
+ return this.retryMppRequest(
1153
+ quote.request.url,
1154
+ this.requestInitFromSnapshot(quote.request),
1155
+ quote.challenge,
1156
+ receipt
1157
+ );
1158
+ } catch (err) {
1159
+ this.attachResumeState(err, {
1160
+ rail: "mpp",
1161
+ challenge: quote.challenge,
1162
+ idempotencyKey,
1163
+ request: quote.request
1164
+ });
1165
+ throw err;
1166
+ }
1167
+ }
739
1168
  async retryX402Request(url, initialInit, paymentRequired, receipt) {
740
1169
  if (!receipt.accepted) {
741
1170
  throw new HavenApiError("No accepted x402 option was recorded for payment retry", 500);
@@ -797,7 +1226,7 @@ var HavenClient = class {
797
1226
  });
798
1227
  return retryResponse;
799
1228
  }
800
- async authorizeMachinePayment(challenge) {
1229
+ async authorizeMachinePayment(challenge, options = {}) {
801
1230
  if (!this.delegateKey) {
802
1231
  throw new HavenSigningError(
803
1232
  "delegateKey is required for machine payments. Pass it in the HavenClient config."
@@ -806,13 +1235,20 @@ var HavenClient = class {
806
1235
  if (challenge.rail !== "mpp_demo") {
807
1236
  throw new HavenApiError(`Unsupported machine payment rail: ${challenge.rail}`, 400);
808
1237
  }
809
- const idempotencyKey = buildMachinePaymentIdempotencyKey(challenge);
1238
+ const idempotencyKey = options.idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge);
810
1239
  const inFlight = this.inFlightMachinePayments.get(idempotencyKey);
811
1240
  if (inFlight) return inFlight;
812
1241
  const promise = this.authorizeMppDemoPayment(challenge, idempotencyKey);
813
1242
  this.inFlightMachinePayments.set(idempotencyKey, promise);
814
1243
  try {
815
1244
  return await promise;
1245
+ } catch (err) {
1246
+ this.attachResumeState(err, {
1247
+ rail: "mpp",
1248
+ challenge,
1249
+ idempotencyKey
1250
+ });
1251
+ throw err;
816
1252
  } finally {
817
1253
  this.inFlightMachinePayments.delete(idempotencyKey);
818
1254
  }
@@ -839,8 +1275,56 @@ var HavenClient = class {
839
1275
  }
840
1276
  return this.mapMachinePaymentReceipt(challenge, raw, execResult.tx_hash, execResult);
841
1277
  }
1278
+ async resumeAuthorizedMpp(input) {
1279
+ if (!this.delegateKey) {
1280
+ throw new HavenSigningError(
1281
+ "delegateKey is required for machine payments. Pass it in the HavenClient config."
1282
+ );
1283
+ }
1284
+ const status = await this.getPaymentStatus(input.paymentId);
1285
+ this.assertCanResumeMpp(status, input.challenge);
1286
+ return this.mapMachinePaymentReceiptFromStatus(input.challenge, status);
1287
+ }
1288
+ async resumeMppPayment(input) {
1289
+ const inputInit = "init" in input ? input.init : void 0;
1290
+ const initialInit = inputInit ?? (input.request ? this.requestInitFromSnapshot(input.request) : void 0);
1291
+ let challenge = input.challenge;
1292
+ const url = input.url ?? input.request?.url;
1293
+ if (!challenge) {
1294
+ if (!url) {
1295
+ throw new HavenApiError("MPP resume requires the original URL or a captured request snapshot.", 400);
1296
+ }
1297
+ const response = await globalThis.fetch(url, initialInit);
1298
+ if (response.status !== 402) {
1299
+ throw new HavenApiError("Expected the original MPP request to return HTTP 402 before resuming.", 400);
1300
+ }
1301
+ challenge = await parseMachinePaymentChallengeResponse(response);
1302
+ }
1303
+ const receipt = await this.resumeAuthorizedMpp({
1304
+ paymentId: input.paymentId,
1305
+ challenge,
1306
+ idempotencyKey: input.idempotencyKey
1307
+ });
1308
+ return this.retryMppRequest(url ?? challenge.resource, initialInit, challenge, receipt);
1309
+ }
842
1310
  async fetchWithMachinePayment(url, initialInit, challenge) {
843
- const receipt = await this.authorizeMachinePayment(challenge);
1311
+ const request = this.snapshotX402Request(url, initialInit);
1312
+ const idempotencyKey = buildMachinePaymentIdempotencyKey(challenge);
1313
+ let receipt;
1314
+ try {
1315
+ receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
1316
+ } catch (err) {
1317
+ this.attachResumeState(err, {
1318
+ rail: "mpp",
1319
+ challenge,
1320
+ idempotencyKey,
1321
+ request
1322
+ });
1323
+ throw err;
1324
+ }
1325
+ return this.retryMppRequest(url, initialInit, challenge, receipt);
1326
+ }
1327
+ async retryMppRequest(url, initialInit, challenge, receipt) {
844
1328
  const retryHeaders = new Headers(initialInit?.headers);
845
1329
  retryHeaders.set("MACHINE-PAYMENT-PROOF", receipt.proofHeader);
846
1330
  const retryResponse = await globalThis.fetch(url, {
@@ -892,7 +1376,7 @@ var HavenClient = class {
892
1376
  status
893
1377
  );
894
1378
  }
895
- if (status.nextAction !== "retry_original_x402_request") {
1379
+ if (status.nextAction !== AgentPaymentNextAction.RetryOriginalX402Request) {
896
1380
  throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
897
1381
  }
898
1382
  if (!status.txHash) {
@@ -937,7 +1421,7 @@ var HavenClient = class {
937
1421
  );
938
1422
  }
939
1423
  const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
940
- const requestedAmount = normalizeDecimal(decimalFromUsdcAtomic(option.amount));
1424
+ const requestedAmount = normalizeDecimal(decimalFromUsdcAtomic(x402AuthorizationAmount(option)));
941
1425
  if (approvedAmount && approvedAmount !== requestedAmount) {
942
1426
  throw new HavenApiError(
943
1427
  "x402 resume request does not match the approved amount.",
@@ -947,11 +1431,73 @@ var HavenClient = class {
947
1431
  );
948
1432
  }
949
1433
  }
1434
+ assertCanResumeMpp(status, challenge) {
1435
+ if (!isMppRail(status.rail)) {
1436
+ throw new HavenPaymentStateError(
1437
+ `Payment ${status.paymentId} is ${status.rail}, not MPP.`,
1438
+ 409,
1439
+ status
1440
+ );
1441
+ }
1442
+ if (status.nextAction !== AgentPaymentNextAction.RetryOriginalX402Request) {
1443
+ throw new HavenPaymentStateError(status.message, PAYMENT_STATE_STATUS_CODES[status.status] ?? 409, status);
1444
+ }
1445
+ if (!status.txHash) {
1446
+ throw new HavenApiError(
1447
+ `MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1448
+ 502,
1449
+ status,
1450
+ status.paymentId
1451
+ );
1452
+ }
1453
+ if (status.resourceUrl && status.resourceUrl !== challenge.resource) {
1454
+ throw new HavenApiError(
1455
+ "MPP resume request does not match the approved resource URL.",
1456
+ 409,
1457
+ { status, challenge },
1458
+ status.paymentId
1459
+ );
1460
+ }
1461
+ if (status.merchantAddress && !sameAddress(status.merchantAddress, challenge.recipient)) {
1462
+ throw new HavenApiError(
1463
+ "MPP resume request does not match the approved merchant.",
1464
+ 409,
1465
+ { status, challenge },
1466
+ status.paymentId
1467
+ );
1468
+ }
1469
+ if (status.chainId && status.chainId !== challenge.network.chainId) {
1470
+ throw new HavenApiError(
1471
+ "MPP resume request does not match the approved network.",
1472
+ 409,
1473
+ { status, challenge },
1474
+ status.paymentId
1475
+ );
1476
+ }
1477
+ if (status.token && status.token !== challenge.asset.symbol) {
1478
+ throw new HavenApiError(
1479
+ "MPP resume request does not match the approved token.",
1480
+ 409,
1481
+ { status, challenge },
1482
+ status.paymentId
1483
+ );
1484
+ }
1485
+ const approvedAmount = status.amount ? normalizeDecimal(status.amount) : "";
1486
+ const requestedAmount = normalizeDecimal(challenge.amount.display);
1487
+ if (approvedAmount && approvedAmount !== requestedAmount) {
1488
+ throw new HavenApiError(
1489
+ "MPP resume request does not match the approved amount.",
1490
+ 409,
1491
+ { status, challenge },
1492
+ status.paymentId
1493
+ );
1494
+ }
1495
+ }
950
1496
  mapX402ReceiptFromAuthorization(paymentRequired, option, paymentHeader, raw, execResult) {
951
1497
  const txHash = execResult?.tx_hash ?? raw.tx_hash ?? "";
952
1498
  const chainId = execResult?.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network);
953
1499
  const token = execResult?.token ?? raw.token ?? "USDC";
954
- const amount = execResult?.amount ?? raw.amount ?? decimalFromUsdcAtomic(option.amount);
1500
+ const amount = execResult?.amount ?? raw.amount ?? decimalFromUsdcAtomic(x402AuthorizationAmount(option));
955
1501
  const to = execResult?.to ?? raw.to ?? this.delegateAddress ?? "";
956
1502
  const explorerUrl = execResult?.explorer_url ?? raw.explorer_url ?? explorerUrlOrEmpty(chainId, txHash);
957
1503
  const merchantTo = execResult?.merchant_to ?? raw.merchant_to ?? option.payTo;
@@ -984,7 +1530,7 @@ var HavenClient = class {
984
1530
  paymentId: status.paymentId,
985
1531
  txHash: status.txHash,
986
1532
  token: status.token || "USDC",
987
- amount: status.amount || decimalFromUsdcAtomic(option.amount),
1533
+ amount: status.amount || decimalFromUsdcAtomic(x402AuthorizationAmount(option)),
988
1534
  to: this.delegateAddress ?? "",
989
1535
  resourceUrl: paymentRequired.resource.url,
990
1536
  explorerUrl: explorerUrlOrEmpty(status.chainId, status.txHash),
@@ -1020,7 +1566,7 @@ var HavenClient = class {
1020
1566
  payTo: input.merchantTo ?? input.accepted.payTo
1021
1567
  },
1022
1568
  x402: {
1023
- amount: input.accepted.amount,
1569
+ amount: x402AuthorizationAmount(input.accepted),
1024
1570
  token: input.token,
1025
1571
  network: input.accepted.network,
1026
1572
  asset: input.accepted.asset,
@@ -1073,6 +1619,33 @@ var HavenClient = class {
1073
1619
  proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
1074
1620
  };
1075
1621
  }
1622
+ mapMachinePaymentReceiptFromStatus(challenge, status) {
1623
+ if (!status.txHash) {
1624
+ throw new HavenApiError(
1625
+ `MPP payment ${status.paymentId} is ready to retry but has no Haven transaction hash.`,
1626
+ 502,
1627
+ status,
1628
+ status.paymentId
1629
+ );
1630
+ }
1631
+ const receiptWithoutHeader = {
1632
+ success: true,
1633
+ rail: challenge.rail,
1634
+ paymentId: status.paymentId,
1635
+ challengeId: challenge.challengeId,
1636
+ txHash: status.txHash,
1637
+ token: status.token || challenge.asset.symbol,
1638
+ amount: status.amount || challenge.amount.display,
1639
+ to: status.merchantAddress ?? challenge.recipient,
1640
+ resourceUrl: status.resourceUrl ?? challenge.resource,
1641
+ explorerUrl: explorerUrlOrEmpty(status.chainId || challenge.network.chainId, status.txHash),
1642
+ chainId: status.chainId || challenge.network.chainId
1643
+ };
1644
+ return {
1645
+ ...receiptWithoutHeader,
1646
+ proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
1647
+ };
1648
+ }
1076
1649
  async recordMerchantRetryRejected(input) {
1077
1650
  try {
1078
1651
  await this.post("/machine-payments/reconciliation-events", {
@@ -1156,16 +1729,64 @@ var HavenClient = class {
1156
1729
  amount,
1157
1730
  token,
1158
1731
  resourceUrl: raw.resource_url ?? null,
1159
- merchantAddress: raw.merchant_to ?? null,
1732
+ merchantAddress: raw.merchant_address ?? raw.merchant_to ?? null,
1160
1733
  txHash: raw.tx_hash ?? null,
1161
1734
  expiresAt: raw.expires_at ?? "",
1162
1735
  chainId: raw.chain_id ?? 0,
1163
- message
1736
+ message,
1737
+ amountAtomic: raw.amount_atomic ?? raw.x402?.amount_atomic ?? raw.mpp?.amount_atomic ?? null,
1738
+ asset: raw.asset ?? raw.x402?.asset ?? raw.mpp?.asset ?? null,
1739
+ network: raw.network ?? raw.x402?.network ?? raw.mpp?.network ?? null,
1740
+ description: raw.description ?? raw.x402?.description ?? raw.mpp?.description ?? null,
1741
+ idempotencyKey: raw.idempotency_key ?? raw.x402?.idempotency_key ?? raw.mpp?.idempotency_key ?? null,
1742
+ x402: raw.x402 ? {
1743
+ amountAtomic: raw.x402.amount_atomic ?? raw.amount_atomic ?? null,
1744
+ asset: raw.x402.asset ?? raw.asset ?? null,
1745
+ network: raw.x402.network ?? raw.network ?? null,
1746
+ resourceUrl: raw.x402.resource_url ?? raw.resource_url ?? null,
1747
+ merchantAddress: raw.x402.merchant_address ?? raw.merchant_address ?? raw.merchant_to ?? null,
1748
+ description: raw.x402.description ?? raw.description ?? null,
1749
+ idempotencyKey: raw.x402.idempotency_key ?? raw.idempotency_key ?? null
1750
+ } : void 0,
1751
+ mpp: raw.mpp ? {
1752
+ amountAtomic: raw.mpp.amount_atomic ?? raw.amount_atomic ?? null,
1753
+ asset: raw.mpp.asset ?? raw.asset ?? null,
1754
+ network: raw.mpp.network ?? raw.network ?? null,
1755
+ resourceUrl: raw.mpp.resource_url ?? raw.resource_url ?? null,
1756
+ merchantAddress: raw.mpp.merchant_address ?? raw.merchant_address ?? raw.merchant_to ?? null,
1757
+ description: raw.mpp.description ?? raw.description ?? null,
1758
+ idempotencyKey: raw.mpp.idempotency_key ?? raw.idempotency_key ?? null,
1759
+ challengeId: raw.mpp.challenge_id ?? raw.challenge_id ?? null
1760
+ } : void 0
1164
1761
  };
1165
1762
  }
1166
1763
  x402PayerAddress() {
1167
1764
  return this.delegateAddress ?? this.x402Wallet;
1168
1765
  }
1766
+ snapshotX402Request(url, init) {
1767
+ return {
1768
+ url,
1769
+ method: init?.method ?? "GET",
1770
+ headers: Array.from(new Headers(init?.headers).entries()),
1771
+ body: this.snapshotRequestBody(init?.body)
1772
+ };
1773
+ }
1774
+ snapshotRequestBody(body) {
1775
+ if (body == null) return void 0;
1776
+ if (typeof body === "string") return body;
1777
+ if (body instanceof URLSearchParams) return body.toString();
1778
+ throw new HavenApiError(
1779
+ "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.",
1780
+ 400
1781
+ );
1782
+ }
1783
+ requestInitFromSnapshot(request) {
1784
+ return {
1785
+ method: request.method,
1786
+ headers: request.headers,
1787
+ body: request.body
1788
+ };
1789
+ }
1169
1790
  withX402Wallet(init, wallet = this.x402PayerAddress()) {
1170
1791
  if (!wallet) return init;
1171
1792
  const headers = new Headers(init?.headers);
@@ -1177,6 +1798,134 @@ var HavenClient = class {
1177
1798
  headers
1178
1799
  };
1179
1800
  }
1801
+ buildX402Quote(paymentRequired, request, idempotencyKey) {
1802
+ const option = selectStandardPaymentOption(paymentRequired.accepts);
1803
+ if (!option) {
1804
+ throw new HavenApiError(
1805
+ "No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC.",
1806
+ 400
1807
+ );
1808
+ }
1809
+ const token = resolveTokenFromAddress(option.asset, option.network);
1810
+ return {
1811
+ rail: "x402",
1812
+ idempotencyKey: idempotencyKey ?? buildX402IdempotencyKey(paymentRequired, option),
1813
+ paymentRequired,
1814
+ accepted: option,
1815
+ request,
1816
+ resourceUrl: paymentRequired.resource.url,
1817
+ description: paymentRequired.resource.description ?? option.description ?? null,
1818
+ mimeType: paymentRequired.resource.mimeType ?? option.mimeType ?? null,
1819
+ amountAtomic: x402AuthorizationAmount(option),
1820
+ amount: decimalFromUsdcAtomic(x402AuthorizationAmount(option)),
1821
+ token: token?.symbol ?? "USDC",
1822
+ asset: option.asset,
1823
+ network: option.network,
1824
+ chainId: chainIdOrNull(option.network),
1825
+ merchantAddress: option.payTo,
1826
+ maxTimeoutSeconds: option.maxTimeoutSeconds
1827
+ };
1828
+ }
1829
+ buildX402ResumeState(input) {
1830
+ const token = resolveTokenFromAddress(input.accepted.asset, input.accepted.network);
1831
+ return {
1832
+ rail: "x402",
1833
+ paymentId: input.paymentId,
1834
+ idempotencyKey: input.idempotencyKey,
1835
+ paymentRequired: input.paymentRequired,
1836
+ accepted: input.accepted,
1837
+ url: input.request?.url ?? input.paymentRequired.resource.url,
1838
+ request: input.request,
1839
+ resourceUrl: input.paymentRequired.resource.url,
1840
+ description: input.paymentRequired.resource.description ?? input.accepted.description ?? null,
1841
+ amountAtomic: x402AuthorizationAmount(input.accepted),
1842
+ amount: decimalFromUsdcAtomic(x402AuthorizationAmount(input.accepted)),
1843
+ token: token?.symbol ?? "USDC",
1844
+ asset: input.accepted.asset,
1845
+ network: input.accepted.network,
1846
+ chainId: chainIdOrNull(input.accepted.network),
1847
+ merchantAddress: input.accepted.payTo
1848
+ };
1849
+ }
1850
+ buildMppQuote(challenge, request, idempotencyKey) {
1851
+ return {
1852
+ rail: "mpp",
1853
+ paymentRail: challenge.rail,
1854
+ idempotencyKey: idempotencyKey ?? buildMachinePaymentIdempotencyKey(challenge),
1855
+ challenge,
1856
+ request,
1857
+ resourceUrl: challenge.resource,
1858
+ description: challenge.description ?? null,
1859
+ amountAtomic: challenge.amount.atomic,
1860
+ amount: challenge.amount.display,
1861
+ token: challenge.asset.symbol,
1862
+ asset: challenge.asset.address,
1863
+ network: challenge.network.name,
1864
+ chainId: challenge.network.chainId,
1865
+ merchantAddress: challenge.recipient,
1866
+ expiresAt: challenge.expiresAt
1867
+ };
1868
+ }
1869
+ buildMppResumeState(input) {
1870
+ const quote = this.buildMppQuote(
1871
+ input.challenge,
1872
+ input.request ?? this.snapshotX402Request(input.challenge.resource),
1873
+ input.idempotencyKey
1874
+ );
1875
+ return {
1876
+ rail: "mpp",
1877
+ paymentRail: quote.paymentRail,
1878
+ paymentId: input.paymentId,
1879
+ idempotencyKey: quote.idempotencyKey,
1880
+ challenge: input.challenge,
1881
+ url: input.request?.url ?? input.challenge.resource,
1882
+ request: input.request,
1883
+ resourceUrl: quote.resourceUrl,
1884
+ description: quote.description,
1885
+ amountAtomic: quote.amountAtomic,
1886
+ amount: quote.amount,
1887
+ token: quote.token,
1888
+ asset: quote.asset,
1889
+ network: quote.network,
1890
+ chainId: quote.chainId,
1891
+ merchantAddress: quote.merchantAddress,
1892
+ expiresAt: quote.expiresAt
1893
+ };
1894
+ }
1895
+ attachResumeState(err, input) {
1896
+ if (input.rail === "x402") {
1897
+ this.attachX402ResumeState(
1898
+ err,
1899
+ input.paymentRequired,
1900
+ input.accepted,
1901
+ input.idempotencyKey,
1902
+ input.request
1903
+ );
1904
+ return;
1905
+ }
1906
+ this.attachMppResumeState(err, input.challenge, input.idempotencyKey, input.request);
1907
+ }
1908
+ attachX402ResumeState(err, paymentRequired, accepted, idempotencyKey, request) {
1909
+ if (!(err instanceof HavenPaymentStateError)) return;
1910
+ if (err.state.rail !== "x402") return;
1911
+ err.resumeState = this.buildX402ResumeState({
1912
+ paymentId: err.state.paymentId,
1913
+ paymentRequired,
1914
+ accepted,
1915
+ idempotencyKey,
1916
+ request
1917
+ });
1918
+ }
1919
+ attachMppResumeState(err, challenge, idempotencyKey, request) {
1920
+ if (!(err instanceof HavenPaymentStateError)) return;
1921
+ if (!isMppRail(err.state.rail)) return;
1922
+ err.resumeState = this.buildMppResumeState({
1923
+ paymentId: err.state.paymentId,
1924
+ challenge,
1925
+ idempotencyKey,
1926
+ request
1927
+ });
1928
+ }
1180
1929
  // ── Tool Execution (for agent frameworks) ────────────────────────
1181
1930
  /**
1182
1931
  * Execute a tool call by name and input.
@@ -1236,9 +1985,9 @@ var HavenClient = class {
1236
1985
  }
1237
1986
  }
1238
1987
  if (toolName === "authorize_machine_payment") {
1239
- const { challenge } = input;
1988
+ const { challenge, idempotencyKey } = input;
1240
1989
  try {
1241
- const receipt = await this.authorizeMachinePayment(challenge);
1990
+ const receipt = await this.authorizeMachinePayment(challenge, { idempotencyKey });
1242
1991
  return {
1243
1992
  success: true,
1244
1993
  payment_id: receipt.paymentId,
@@ -1273,11 +2022,21 @@ var HavenClient = class {
1273
2022
  amount: result.amount,
1274
2023
  resource_url: result.resourceUrl,
1275
2024
  merchant_address: result.merchantAddress,
2025
+ amount_atomic: result.amountAtomic,
2026
+ asset: result.asset,
2027
+ network: result.network,
2028
+ description: result.description,
2029
+ idempotency_key: result.idempotencyKey,
2030
+ x402: result.x402,
2031
+ mpp: result.mpp,
1276
2032
  expires_at: result.expiresAt,
1277
2033
  chain_id: result.chainId,
1278
2034
  message: result.message
1279
2035
  };
1280
2036
  }
2037
+ if (toolName === "get_allowances") {
2038
+ return { ...await this.getAllowances() };
2039
+ }
1281
2040
  throw new Error(`Unknown tool: ${toolName}`);
1282
2041
  }
1283
2042
  toolX402PaymentRequired(input) {
@@ -1330,6 +2089,31 @@ var HavenClient = class {
1330
2089
  amount: err.state.amount,
1331
2090
  resource_url: err.state.resourceUrl,
1332
2091
  merchant_address: err.state.merchantAddress,
2092
+ amount_atomic: err.state.amountAtomic,
2093
+ asset: err.state.asset,
2094
+ network: err.state.network,
2095
+ description: err.state.description,
2096
+ idempotency_key: err.state.idempotencyKey,
2097
+ x402: err.state.x402 ? {
2098
+ amount_atomic: err.state.x402.amountAtomic,
2099
+ asset: err.state.x402.asset,
2100
+ network: err.state.x402.network,
2101
+ resource_url: err.state.x402.resourceUrl,
2102
+ merchant_address: err.state.x402.merchantAddress,
2103
+ description: err.state.x402.description,
2104
+ idempotency_key: err.state.x402.idempotencyKey
2105
+ } : void 0,
2106
+ mpp: err.state.mpp ? {
2107
+ amount_atomic: err.state.mpp.amountAtomic,
2108
+ asset: err.state.mpp.asset,
2109
+ network: err.state.mpp.network,
2110
+ resource_url: err.state.mpp.resourceUrl,
2111
+ merchant_address: err.state.mpp.merchantAddress,
2112
+ description: err.state.mpp.description,
2113
+ idempotency_key: err.state.mpp.idempotencyKey,
2114
+ challenge_id: err.state.mpp.challengeId
2115
+ } : void 0,
2116
+ resume_state: err.resumeState,
1333
2117
  expires_at: err.state.expiresAt,
1334
2118
  chain_id: err.state.chainId,
1335
2119
  message: err.state.message,
@@ -1361,11 +2145,14 @@ var HavenClient = class {
1361
2145
  const controller = new AbortController();
1362
2146
  const timeout = setTimeout(() => controller.abort(), this.requestTimeout);
1363
2147
  try {
2148
+ const contextHeaders = this.requestContext.getStore()?.headers ?? {};
1364
2149
  const res = await fetch(url, {
1365
2150
  method,
1366
2151
  headers: {
1367
2152
  "Content-Type": "application/json",
1368
- "Authorization": `Bearer ${this.apiKey}`
2153
+ "Authorization": `Bearer ${this.apiKey}`,
2154
+ ...this.defaultHeaders,
2155
+ ...contextHeaders
1369
2156
  },
1370
2157
  body: body ? JSON.stringify(body) : void 0,
1371
2158
  signal: controller.signal
@@ -1422,7 +2209,50 @@ var HavenClient = class {
1422
2209
  txHash: raw.tx_hash,
1423
2210
  expiresAt: raw.expires_at,
1424
2211
  chainId: raw.chain_id,
1425
- message: raw.message
2212
+ message: raw.message,
2213
+ amountAtomic: raw.amount_atomic ?? raw.x402?.amount_atomic ?? null,
2214
+ asset: raw.asset ?? raw.x402?.asset ?? null,
2215
+ network: raw.network ?? raw.x402?.network ?? null,
2216
+ description: raw.description ?? raw.x402?.description ?? null,
2217
+ idempotencyKey: raw.idempotency_key ?? raw.x402?.idempotency_key ?? null,
2218
+ x402: raw.x402 ? {
2219
+ amountAtomic: raw.x402.amount_atomic ?? raw.amount_atomic ?? null,
2220
+ asset: raw.x402.asset ?? raw.asset ?? null,
2221
+ network: raw.x402.network ?? raw.network ?? null,
2222
+ resourceUrl: raw.x402.resource_url ?? raw.resource_url,
2223
+ merchantAddress: raw.x402.merchant_address ?? raw.merchant_address,
2224
+ description: raw.x402.description ?? raw.description ?? null,
2225
+ idempotencyKey: raw.x402.idempotency_key ?? raw.idempotency_key ?? null
2226
+ } : void 0
2227
+ };
2228
+ }
2229
+ mapPaymentReceipt(raw) {
2230
+ return {
2231
+ id: raw.id,
2232
+ paymentId: raw.payment_id,
2233
+ rail: raw.rail,
2234
+ proofStatus: raw.proof_status,
2235
+ txHash: raw.tx_hash,
2236
+ chainId: raw.chain_id,
2237
+ resourceUrl: raw.resource_url,
2238
+ merchantAddress: raw.merchant_address,
2239
+ payerAddress: raw.payer_address,
2240
+ settlementAddress: raw.settlement_address,
2241
+ tokenSymbol: raw.token_symbol,
2242
+ tokenAddress: raw.token_address,
2243
+ amountRaw: raw.amount_raw,
2244
+ amount: raw.amount_human,
2245
+ challengeId: raw.challenge_id,
2246
+ idempotencyKey: raw.idempotency_key,
2247
+ challengePayload: raw.challenge_payload,
2248
+ selectedPayment: raw.selected_payment,
2249
+ paymentProofHeaderName: raw.payment_proof_header_name,
2250
+ protocolReceiptHeaderName: raw.protocol_receipt_header_name,
2251
+ protocolReceiptPayload: raw.protocol_receipt_payload,
2252
+ merchantStatus: raw.merchant_status,
2253
+ confirmedAt: raw.confirmed_at,
2254
+ createdAt: raw.created_at,
2255
+ updatedAt: raw.updated_at
1426
2256
  };
1427
2257
  }
1428
2258
  };
@@ -1464,6 +2294,72 @@ async function responseSnippet(response) {
1464
2294
  }
1465
2295
  }
1466
2296
 
2297
+ // src/tool-descriptions.ts
2298
+ function composeDescription(d) {
2299
+ return [d.summary, d.selectionGuidance, d.behavior, d.nextActionGuidance].filter(Boolean).join(" ");
2300
+ }
2301
+ var toolDescriptions = {
2302
+ quoteX402: {
2303
+ summary: "Inspect an HTTP 402 x402 paid resource without creating a Haven payment, signature, approval, or on-chain transaction.",
2304
+ behavior: "Probes the merchant directly and parses the 402 response. Pure read-only client behavior \u2014 Haven is not contacted.",
2305
+ nextActionGuidance: ""
2306
+ },
2307
+ payX402: {
2308
+ summary: "Pay an inspected x402 quote. The delegate key signs locally; Haven only validates and relays signed, on-chain-constrained payment transactions.",
2309
+ 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.",
2310
+ behavior: "Signs the EIP-3009 payment from the delegate wallet, asks Haven for a Safe AllowanceModule top-up if needed, and returns the merchant response or a pending-approval state.",
2311
+ nextActionGuidance: "If approval is needed, preserve the returned resume_state and wait for nextAction=retry_original_x402_request before resuming."
2312
+ },
2313
+ resumeX402: {
2314
+ summary: "Resume an x402 payment after the Haven wallet owner approved the funding step.",
2315
+ behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the approved Haven funding, and retries the merchant request with the X-PAYMENT header. No new Haven approval is created.",
2316
+ nextActionGuidance: "Only use when get_payment_status returns nextAction=retry_original_x402_request; do not start a new merchant session."
2317
+ },
2318
+ quoteMpp: {
2319
+ summary: "Inspect a Haven MPP challenge or paid MPP URL without creating a Haven payment, signature, approval, or on-chain transaction.",
2320
+ behavior: "Parses an MPP challenge envelope and returns a typed quote with rail tag, amount, asset, and merchant context. Pure read-only \u2014 Haven is not contacted.",
2321
+ nextActionGuidance: ""
2322
+ },
2323
+ payMpp: {
2324
+ summary: "Pay an inspected MPP challenge. The delegate key signs locally; Haven only validates and relays signed, on-chain-constrained payment transactions.",
2325
+ 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.",
2326
+ behavior: "Authorizes the payment through Haven within the on-chain allowance, signs the challenge proof, and returns the proof header for retrying the original paid resource.",
2327
+ nextActionGuidance: "If approval is needed, preserve resume_state or payment_id and wait for nextAction=retry_original_x402_request before resuming."
2328
+ },
2329
+ resumeMpp: {
2330
+ summary: "Resume an MPP payment after the Haven wallet owner approved the funding step.",
2331
+ behavior: "Accepts either resume_state or payment_id and retries the original paid resource with the MPP proof header. No new Haven approval is created.",
2332
+ nextActionGuidance: ""
2333
+ },
2334
+ getPaymentStatus: {
2335
+ summary: "Fetch structured Haven payment status, including phase and nextAction taxonomy for agent recovery.",
2336
+ behavior: "Accepts a payment intent or approval request id and returns the full state taxonomy (phase, nextAction, rail, amount, merchant, resource url, idempotency key, message).",
2337
+ nextActionGuidance: ""
2338
+ },
2339
+ getResumeState: {
2340
+ summary: "Rehydrate stored x402 or MPP resume_state by payment_id.",
2341
+ behavior: "Returns the context that the agent originally received in a pending-approval response, reconstructed from Haven's database. This is context only; signing still happens locally when a resume tool is called.",
2342
+ nextActionGuidance: ""
2343
+ },
2344
+ getAgent: {
2345
+ summary: "Return the authenticated agent identity, Haven wallet, delegate address, chain, and status.",
2346
+ behavior: "Read-only identity lookup. Useful for verifying which on-chain Safe and delegate the credential is bound to.",
2347
+ nextActionGuidance: ""
2348
+ },
2349
+ getAllowances: {
2350
+ summary: "Return configured and on-chain allowance state for the authenticated agent. On-chain allowance is the real spend gate.",
2351
+ 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.",
2352
+ behavior: "Reads the Safe AllowanceModule snapshot per token (allowance, spent, remaining, reset window). Configured amounts from Haven are returned alongside the on-chain truth.",
2353
+ nextActionGuidance: ""
2354
+ },
2355
+ listReceipts: {
2356
+ summary: "List recent machine-payment receipts and evidence for bookkeeping.",
2357
+ 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.",
2358
+ behavior: "Returns the agent's recent machine-payment receipts ordered by recency. Proof header values are not returned.",
2359
+ nextActionGuidance: ""
2360
+ }
2361
+ };
2362
+
1467
2363
  // src/tools.ts
1468
2364
  var makePaymentSchema = {
1469
2365
  type: "object",
@@ -1497,6 +2393,11 @@ var getPaymentStatusSchema = {
1497
2393
  },
1498
2394
  required: ["payment_id"]
1499
2395
  };
2396
+ var getAllowancesSchema = {
2397
+ type: "object",
2398
+ properties: {},
2399
+ required: []
2400
+ };
1500
2401
  var authorizeX402Schema = {
1501
2402
  type: "object",
1502
2403
  properties: {
@@ -1579,11 +2480,12 @@ var authorizeMachinePaymentSchema = {
1579
2480
  },
1580
2481
  required: ["challenge"]
1581
2482
  };
1582
- 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.";
1583
- 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.";
1584
- 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 use resume_x402_payment only when next_action is retry_original_x402_request. Do not 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.";
1585
- 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.";
1586
- 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.";
2483
+ var MAKE_PAYMENT_DESCRIPTION = "Request and sign a payment from the user-controlled Safe within approved on-chain limits. For read-only allowance, budget, spend-limit, remaining-amount, or reset-period questions, use get_allowances instead of making a payment. 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.";
2484
+ var GET_STATUS_DESCRIPTION = toolDescriptions.getPaymentStatus.summary + " Accepts payment intent IDs and approval request IDs. Returns the current status, phase, next_action, transaction hash if available, and payment details.";
2485
+ var GET_ALLOWANCES_DESCRIPTION = composeDescription(toolDescriptions.getAllowances);
2486
+ var AUTHORIZE_X402_DESCRIPTION = composeDescription(toolDescriptions.payX402) + " In this SDK tool set, the allowance lookup tool is get_allowances. 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.";
2487
+ var RESUME_X402_DESCRIPTION = toolDescriptions.resumeX402.summary + " 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.";
2488
+ var AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION = composeDescription(toolDescriptions.payMpp) + " In this SDK tool set, the allowance lookup tool is get_allowances. Currently scoped to 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.";
1587
2489
  function claudeTools() {
1588
2490
  return [
1589
2491
  {
@@ -1596,6 +2498,11 @@ function claudeTools() {
1596
2498
  description: GET_STATUS_DESCRIPTION,
1597
2499
  input_schema: getPaymentStatusSchema
1598
2500
  },
2501
+ {
2502
+ name: "get_allowances",
2503
+ description: GET_ALLOWANCES_DESCRIPTION,
2504
+ input_schema: getAllowancesSchema
2505
+ },
1599
2506
  {
1600
2507
  name: "authorize_x402_payment",
1601
2508
  description: AUTHORIZE_X402_DESCRIPTION,
@@ -1631,6 +2538,14 @@ function openaiTools() {
1631
2538
  parameters: getPaymentStatusSchema
1632
2539
  }
1633
2540
  },
2541
+ {
2542
+ type: "function",
2543
+ function: {
2544
+ name: "get_allowances",
2545
+ description: GET_ALLOWANCES_DESCRIPTION,
2546
+ parameters: getAllowancesSchema
2547
+ }
2548
+ },
1634
2549
  {
1635
2550
  type: "function",
1636
2551
  function: {
@@ -1664,6 +2579,18 @@ var havenTools = {
1664
2579
  openai: openaiTools
1665
2580
  };
1666
2581
 
2582
+ exports.AGENT_PAYMENT_NEXT_ACTION_VALUES = AGENT_PAYMENT_NEXT_ACTION_VALUES;
2583
+ exports.AGENT_PAYMENT_PHASE_VALUES = AGENT_PAYMENT_PHASE_VALUES;
2584
+ exports.AGENT_PAYMENT_RAIL_VALUES = AGENT_PAYMENT_RAIL_VALUES;
2585
+ exports.AgentPaymentNextAction = AgentPaymentNextAction;
2586
+ exports.AgentPaymentNextActionDescriptions = AgentPaymentNextActionDescriptions;
2587
+ exports.AgentPaymentNextActionSchema = AgentPaymentNextActionSchema;
2588
+ exports.AgentPaymentPhase = AgentPaymentPhase;
2589
+ exports.AgentPaymentPhaseDescriptions = AgentPaymentPhaseDescriptions;
2590
+ exports.AgentPaymentPhaseSchema = AgentPaymentPhaseSchema;
2591
+ exports.AgentPaymentRail = AgentPaymentRail;
2592
+ exports.AgentPaymentRailDescriptions = AgentPaymentRailDescriptions;
2593
+ exports.AgentPaymentRailSchema = AgentPaymentRailSchema;
1667
2594
  exports.HavenApiError = HavenApiError;
1668
2595
  exports.HavenClient = HavenClient;
1669
2596
  exports.HavenError = HavenError;
@@ -1672,6 +2599,8 @@ exports.HavenSigningError = HavenSigningError;
1672
2599
  exports.HavenTimeoutError = HavenTimeoutError;
1673
2600
  exports.addressFromKey = addressFromKey;
1674
2601
  exports.buildMachinePaymentIdempotencyKey = buildMachinePaymentIdempotencyKey;
2602
+ exports.buildX402ExpectedMessage = buildX402ExpectedMessage;
2603
+ exports.composeDescription = composeDescription;
1675
2604
  exports.encodeMachinePaymentProof = encodeMachinePaymentProof;
1676
2605
  exports.encodePaymentProof = encodePaymentProof;
1677
2606
  exports.havenTools = havenTools;
@@ -1680,7 +2609,11 @@ exports.parseMachinePaymentChallengeResponse = parseMachinePaymentChallengeRespo
1680
2609
  exports.parsePaymentRequired = parsePaymentRequired;
1681
2610
  exports.parsePaymentRequiredResponse = parsePaymentRequiredResponse;
1682
2611
  exports.selectPaymentOption = selectPaymentOption;
2612
+ exports.selectStandardPaymentOption = selectStandardPaymentOption;
1683
2613
  exports.signHash = signHash;
2614
+ exports.toStandardPaymentRequirements = toStandardPaymentRequirements;
2615
+ exports.toolDescriptions = toolDescriptions;
1684
2616
  exports.verifySignature = verifySignature;
2617
+ exports.x402AuthorizationAmount = x402AuthorizationAmount;
1685
2618
  //# sourceMappingURL=index.cjs.map
1686
2619
  //# sourceMappingURL=index.cjs.map