@haven_ai/sdk 0.1.0 → 0.1.2

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,8 +1,11 @@
1
1
  'use strict';
2
2
 
3
+ var schemes = require('x402/schemes');
4
+ var accounts = require('viem/accounts');
3
5
  var ethers = require('ethers');
6
+ var crypto = require('crypto');
4
7
 
5
- // src/signer.ts
8
+ // src/client.ts
6
9
 
7
10
  // src/types.ts
8
11
  var HavenError = class extends Error {
@@ -18,13 +21,30 @@ var HavenError = class extends Error {
18
21
  paymentId;
19
22
  };
20
23
  var HavenApiError = class extends HavenError {
21
- constructor(message, statusCode, body) {
22
- super(message, "API_ERROR", statusCode);
24
+ constructor(message, statusCode, body, paymentId) {
25
+ super(message, "API_ERROR", statusCode, paymentId);
23
26
  this.body = body;
24
27
  this.name = "HavenApiError";
25
28
  }
26
29
  body;
27
30
  };
31
+ var HavenPaymentStateError = class extends HavenApiError {
32
+ constructor(message, statusCode, state, body) {
33
+ super(message, statusCode, body, state.paymentId);
34
+ this.state = state;
35
+ this.name = "HavenPaymentStateError";
36
+ }
37
+ state;
38
+ get status() {
39
+ return this.state.status;
40
+ }
41
+ get phase() {
42
+ return this.state.phase;
43
+ }
44
+ get nextAction() {
45
+ return this.state.nextAction;
46
+ }
47
+ };
28
48
  var HavenSigningError = class extends HavenError {
29
49
  constructor(message) {
30
50
  super(message, "SIGNING_ERROR");
@@ -72,11 +92,66 @@ function verifySignature(hash, signature, expectedAddress) {
72
92
  return false;
73
93
  }
74
94
  }
75
-
76
- // src/x402.ts
95
+ var BASE_USDC_ADDRESS = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913";
96
+ var X402_IDEMPOTENCY_BUCKET_MS = 3e5;
97
+ function decodeBase64Json(value, label) {
98
+ try {
99
+ return JSON.parse(atob(value));
100
+ } catch {
101
+ throw new Error(`Failed to decode ${label}`);
102
+ }
103
+ }
104
+ function normalizePaymentOption(value) {
105
+ const candidate = value;
106
+ if (!candidate || typeof candidate !== "object" || typeof candidate.scheme !== "string" || typeof candidate.network !== "string" || typeof candidate.asset !== "string" || typeof candidate.payTo !== "string") {
107
+ return null;
108
+ }
109
+ const amount = typeof candidate.amount === "string" ? candidate.amount : typeof candidate.maxAmountRequired === "string" ? candidate.maxAmountRequired : null;
110
+ if (!amount) return null;
111
+ return {
112
+ scheme: candidate.scheme,
113
+ network: candidate.network,
114
+ amount,
115
+ maxAmountRequired: candidate.maxAmountRequired,
116
+ resource: candidate.resource,
117
+ description: candidate.description,
118
+ mimeType: candidate.mimeType,
119
+ asset: candidate.asset,
120
+ payTo: candidate.payTo,
121
+ maxTimeoutSeconds: candidate.maxTimeoutSeconds ?? 30,
122
+ extra: candidate.extra
123
+ };
124
+ }
125
+ function normalizePaymentRequired(value) {
126
+ const candidate = value;
127
+ if (!candidate || typeof candidate !== "object" || typeof candidate.x402Version !== "number" || !Array.isArray(candidate.accepts)) {
128
+ return null;
129
+ }
130
+ const accepts = candidate.accepts.map((option) => normalizePaymentOption(option)).filter((option) => !!option);
131
+ if (accepts.length === 0) return null;
132
+ const first = accepts[0];
133
+ const resourceUrl = candidate.resource?.url ?? first.resource;
134
+ if (!resourceUrl) return null;
135
+ const resource = {
136
+ url: resourceUrl,
137
+ description: candidate.resource?.description ?? first.description,
138
+ mimeType: candidate.resource?.mimeType ?? first.mimeType
139
+ };
140
+ return {
141
+ x402Version: candidate.x402Version,
142
+ resource,
143
+ accepts,
144
+ error: candidate.error
145
+ };
146
+ }
77
147
  var SUPPORTED_X402_NETWORKS = {
78
148
  "eip155:100": "Gnosis Chain",
79
- "eip155:8453": "Base"
149
+ "eip155:8453": "Base",
150
+ "base": "Base"
151
+ };
152
+ var STANDARD_X402_NETWORKS = {
153
+ "eip155:8453": "base",
154
+ "base": "base"
80
155
  };
81
156
  var GNOSIS_TOKENS = {
82
157
  "0x0000000000000000000000000000000000000000": { symbol: "xDAI", decimals: 18 },
@@ -89,29 +164,41 @@ var BASE_TOKENS = {
89
164
  };
90
165
  var NETWORK_TOKENS = {
91
166
  "eip155:100": GNOSIS_TOKENS,
92
- "eip155:8453": BASE_TOKENS
167
+ "eip155:8453": BASE_TOKENS,
168
+ "base": BASE_TOKENS
93
169
  };
94
170
  function parsePaymentRequired(response) {
95
171
  const v2Header = response.headers.get("PAYMENT-REQUIRED");
96
172
  if (v2Header) {
97
- try {
98
- return JSON.parse(atob(v2Header));
99
- } catch {
100
- throw new Error("Failed to decode PAYMENT-REQUIRED header");
101
- }
173
+ const parsed = normalizePaymentRequired(
174
+ decodeBase64Json(v2Header, "PAYMENT-REQUIRED header")
175
+ );
176
+ if (parsed) return parsed;
102
177
  }
103
178
  const v1Header = response.headers.get("X-PAYMENT");
104
179
  if (v1Header) {
105
- try {
106
- return JSON.parse(atob(v1Header));
107
- } catch {
108
- throw new Error("Failed to decode X-PAYMENT header");
109
- }
180
+ const parsed = normalizePaymentRequired(
181
+ decodeBase64Json(v1Header, "X-PAYMENT header")
182
+ );
183
+ if (parsed) return parsed;
110
184
  }
111
185
  throw new Error(
112
186
  "No x402 payment headers found in 402 response. Expected PAYMENT-REQUIRED (v2) or X-PAYMENT (v1) header."
113
187
  );
114
188
  }
189
+ async function parsePaymentRequiredResponse(response) {
190
+ try {
191
+ return parsePaymentRequired(response);
192
+ } catch (headerErr) {
193
+ try {
194
+ const body = await response.clone().json();
195
+ const parsed = normalizePaymentRequired(body);
196
+ if (parsed) return parsed;
197
+ } catch {
198
+ }
199
+ throw headerErr;
200
+ }
201
+ }
115
202
  function selectPaymentOption(accepts) {
116
203
  if (!accepts || accepts.length === 0) return null;
117
204
  for (const opt of accepts) {
@@ -127,17 +214,139 @@ function selectPaymentOption(accepts) {
127
214
  }
128
215
  return null;
129
216
  }
217
+ function selectStandardPaymentOption(accepts) {
218
+ if (!accepts || accepts.length === 0) return null;
219
+ for (const opt of accepts) {
220
+ if (opt.scheme === "exact" && opt.network in STANDARD_X402_NETWORKS && opt.asset.toLowerCase() === BASE_USDC_ADDRESS) {
221
+ return opt;
222
+ }
223
+ }
224
+ return null;
225
+ }
226
+ function toStandardPaymentRequirements(paymentRequired, option) {
227
+ const network = STANDARD_X402_NETWORKS[option.network];
228
+ if (!network) {
229
+ throw new Error(`x402 exact payments are not supported on ${option.network}`);
230
+ }
231
+ if (option.scheme !== "exact") {
232
+ throw new Error(`Unsupported x402 scheme: ${option.scheme}`);
233
+ }
234
+ return {
235
+ scheme: "exact",
236
+ network,
237
+ maxAmountRequired: option.maxAmountRequired ?? option.amount,
238
+ resource: option.resource ?? paymentRequired.resource.url,
239
+ description: option.description ?? paymentRequired.resource.description ?? "Haven x402 payment",
240
+ mimeType: option.mimeType ?? paymentRequired.resource.mimeType ?? "application/octet-stream",
241
+ payTo: option.payTo,
242
+ asset: option.asset,
243
+ maxTimeoutSeconds: option.maxTimeoutSeconds,
244
+ extra: option.extra
245
+ };
246
+ }
247
+ function buildX402IdempotencyKey(paymentRequired, option, now = Date.now()) {
248
+ const bucket = Math.floor(now / X402_IDEMPOTENCY_BUCKET_MS);
249
+ const material = [
250
+ paymentRequired.resource.url,
251
+ paymentRequired.resource.description ?? "",
252
+ option.payTo.toLowerCase(),
253
+ option.asset.toLowerCase(),
254
+ option.amount,
255
+ option.network,
256
+ bucket
257
+ ].join("|");
258
+ return `x402:${crypto.createHash("sha256").update(material).digest("hex").slice(0, 16)}`;
259
+ }
130
260
  function encodePaymentProof(receipt) {
131
261
  const payload = {
132
262
  x402Version: 2,
263
+ resource: receipt.resourceUrl ? { url: receipt.resourceUrl } : void 0,
264
+ accepted: receipt.accepted,
133
265
  payload: {
266
+ type: "haven_tx_hash",
134
267
  txHash: receipt.txHash,
135
268
  paymentId: receipt.paymentId,
136
- settledVia: "haven"
269
+ settledVia: "haven",
270
+ payer: receipt.payer,
271
+ chainId: receipt.chainId
137
272
  }
138
273
  };
139
274
  return btoa(JSON.stringify(payload));
140
275
  }
276
+ function decodeBase64Json2(value, label) {
277
+ try {
278
+ return JSON.parse(atob(value));
279
+ } catch {
280
+ throw new Error(`Failed to decode ${label}`);
281
+ }
282
+ }
283
+ function normalizeChallenge(value) {
284
+ const candidate = value;
285
+ if (!candidate || typeof candidate !== "object" || candidate.rail !== "mpp_demo" || typeof candidate.version !== "string" || typeof candidate.challengeId !== "string" || typeof candidate.resource !== "string" || typeof candidate.description !== "string" || // TODO: relax these checks when non-demo machine payment rails are added.
286
+ candidate.network?.chainId !== 8453 || candidate.network?.name !== "base" || candidate.asset?.symbol !== "USDC" || typeof candidate.asset?.address !== "string" || candidate.asset.decimals !== 6 || typeof candidate.amount?.display !== "string" || typeof candidate.amount?.atomic !== "string" || typeof candidate.recipient !== "string" || typeof candidate.expiresAt !== "string") {
287
+ return null;
288
+ }
289
+ return {
290
+ rail: candidate.rail,
291
+ version: candidate.version,
292
+ challengeId: candidate.challengeId,
293
+ resource: candidate.resource,
294
+ description: candidate.description,
295
+ network: candidate.network,
296
+ asset: candidate.asset,
297
+ amount: candidate.amount,
298
+ recipient: candidate.recipient,
299
+ expiresAt: candidate.expiresAt,
300
+ metadata: candidate.metadata
301
+ };
302
+ }
303
+ function parseMachinePaymentChallenge(response) {
304
+ const header = response.headers.get("MACHINE-PAYMENT-CHALLENGE");
305
+ if (!header) {
306
+ throw new Error("No MACHINE-PAYMENT-CHALLENGE header found in 402 response.");
307
+ }
308
+ const parsed = normalizeChallenge(
309
+ decodeBase64Json2(header, "MACHINE-PAYMENT-CHALLENGE header")
310
+ );
311
+ if (!parsed) throw new Error("Invalid machine payment challenge");
312
+ return parsed;
313
+ }
314
+ async function parseMachinePaymentChallengeResponse(response) {
315
+ try {
316
+ return parseMachinePaymentChallenge(response);
317
+ } catch (headerErr) {
318
+ try {
319
+ const body = await response.clone().json();
320
+ const parsed = normalizeChallenge(body.challenge);
321
+ if (parsed) return parsed;
322
+ } catch {
323
+ }
324
+ throw headerErr;
325
+ }
326
+ }
327
+ function buildMachinePaymentIdempotencyKey(challenge) {
328
+ const material = [
329
+ challenge.rail,
330
+ challenge.challengeId,
331
+ challenge.resource,
332
+ challenge.recipient.toLowerCase(),
333
+ challenge.asset.address.toLowerCase(),
334
+ challenge.amount.atomic,
335
+ challenge.network.chainId
336
+ ].join("|");
337
+ return `${challenge.rail}:${crypto.createHash("sha256").update(material).digest("hex").slice(0, 16)}`;
338
+ }
339
+ function encodeMachinePaymentProof(receipt) {
340
+ return btoa(JSON.stringify({
341
+ rail: receipt.rail,
342
+ challengeId: receipt.challengeId,
343
+ paymentId: receipt.paymentId,
344
+ txHash: receipt.txHash,
345
+ settledVia: "haven",
346
+ payer: receipt.payer,
347
+ chainId: receipt.chainId
348
+ }));
349
+ }
141
350
 
142
351
  // src/client.ts
143
352
  var DEFAULT_BASE_URL = "http://localhost:3001";
@@ -146,25 +355,89 @@ var CHAIN_EXPLORER_TX = {
146
355
  8453: "https://basescan.org/tx"
147
356
  };
148
357
  function buildExplorerUrl(chainId, txHash) {
149
- const base = CHAIN_EXPLORER_TX[chainId ?? 100] ?? CHAIN_EXPLORER_TX[100];
358
+ const base = CHAIN_EXPLORER_TX[chainId ?? 8453] ?? CHAIN_EXPLORER_TX[8453];
150
359
  return `${base}/${txHash}`;
151
360
  }
152
361
  var DEFAULT_REQUEST_TIMEOUT = 3e4;
153
362
  var DEFAULT_CONFIRMATION_TIMEOUT = 9e4;
154
363
  var DEFAULT_POLLING_INTERVAL = 3e3;
364
+ var PAYMENT_STATE_STATUS_CODES = {
365
+ pending: 202,
366
+ pending_approval: 202,
367
+ approved: 202,
368
+ proposed: 202,
369
+ executed: 200,
370
+ pending_signature: 409,
371
+ submitted: 409,
372
+ expired: 410,
373
+ failed: 502,
374
+ rejected: 409
375
+ };
376
+ function chainIdFromNetwork(network) {
377
+ if (network === "base") return 8453;
378
+ if (!network?.startsWith("eip155:")) return void 0;
379
+ const chainId = Number(network.slice("eip155:".length));
380
+ return Number.isFinite(chainId) ? chainId : void 0;
381
+ }
382
+ function phaseForStatus(status) {
383
+ if (status === "pending_signature") return "agent_signature_required";
384
+ if (status === "submitted") return "payment_submitted";
385
+ if (status === "confirmed") return "payment_confirmed";
386
+ if (status === "pending" || status === "pending_approval") return "user_approval_required";
387
+ if (status === "approved") return "user_execution_required";
388
+ if (status === "proposed") return "waiting_for_additional_approvals";
389
+ if (status === "executed") return "funding_sent";
390
+ if (status === "rejected") return "rejected";
391
+ if (status === "expired") return "expired";
392
+ if (status === "failed") return "failed";
393
+ return null;
394
+ }
395
+ function nextActionForStatus(status) {
396
+ if (status === "pending_signature") return "sign_and_submit_payment";
397
+ if (status === "submitted") return "check_status_later";
398
+ if (status === "confirmed") return "none";
399
+ if (status === "pending" || status === "pending_approval") return "wait_for_user_approval";
400
+ if (status === "approved") return "wait_for_user_to_complete_payment";
401
+ if (status === "proposed") return "wait_for_user_approval";
402
+ if (status === "executed") return "retry_original_x402_request";
403
+ if (status === "rejected") return "stop_and_tell_user";
404
+ if (status === "expired") return "request_again_if_user_still_wants_it";
405
+ if (status === "failed") return "stop_and_tell_user";
406
+ return null;
407
+ }
408
+ function messageForState(label, status, paymentId, nextAction) {
409
+ if (status === "pending" || status === "pending_approval") {
410
+ return `${label} is above the remaining agent budget and is waiting for user approval in Haven (payment_id: ${paymentId}).`;
411
+ }
412
+ if (status === "executed") {
413
+ return "The user completed the funding payment. Retry the original x402 request.";
414
+ }
415
+ if (status === "rejected") {
416
+ return `The user rejected this payment request (payment_id: ${paymentId}).`;
417
+ }
418
+ if (status === "expired") {
419
+ return `This payment request expired (payment_id: ${paymentId}).`;
420
+ }
421
+ return `${label} is ${status}; next_action=${nextAction} (payment_id: ${paymentId}).`;
422
+ }
155
423
  var HavenClient = class {
156
424
  apiKey;
157
425
  delegateKey;
158
426
  baseUrl;
427
+ x402Wallet;
159
428
  requestTimeout;
160
429
  confirmationTimeout;
161
430
  pollingInterval;
431
+ inFlightX402 = /* @__PURE__ */ new Map();
432
+ x402ReceiptCache = /* @__PURE__ */ new Map();
433
+ inFlightMachinePayments = /* @__PURE__ */ new Map();
162
434
  /** Delegate address derived from the private key (if provided) */
163
435
  delegateAddress;
164
436
  constructor(config) {
165
437
  this.apiKey = config.apiKey;
166
438
  this.delegateKey = config.delegateKey;
167
439
  this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
440
+ this.x402Wallet = config.x402Wallet;
168
441
  this.requestTimeout = config.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT;
169
442
  this.confirmationTimeout = config.confirmationTimeout ?? DEFAULT_CONFIRMATION_TIMEOUT;
170
443
  this.pollingInterval = config.pollingInterval ?? DEFAULT_POLLING_INTERVAL;
@@ -204,6 +477,9 @@ var HavenClient = class {
204
477
  amount: request.amount,
205
478
  to: request.to
206
479
  });
480
+ if (raw.status === "pending_approval") {
481
+ this.throwPaymentStateError("Payment", raw);
482
+ }
207
483
  return {
208
484
  paymentId: raw.payment_id,
209
485
  status: "pending_signature",
@@ -253,6 +529,16 @@ var HavenClient = class {
253
529
  const raw = await this.get(`/payments/${paymentId}`);
254
530
  return this.mapPaymentResult(raw);
255
531
  }
532
+ /**
533
+ * Get agent-actionable status for a payment intent or approval request.
534
+ *
535
+ * Use this for IDs returned by agent tools and machine-payment/x402 flows.
536
+ * `getPayment()` remains available for payment-intent-only integrations.
537
+ */
538
+ async getPaymentStatus(paymentId) {
539
+ const raw = await this.get(`/machine-payments/${paymentId}/status`);
540
+ return this.mapPaymentStatusResult(raw);
541
+ }
256
542
  /**
257
543
  * Poll until a payment reaches a terminal status (confirmed, failed, expired).
258
544
  */
@@ -271,8 +557,9 @@ var HavenClient = class {
271
557
  /**
272
558
  * Authorize an x402 payment.
273
559
  *
274
- * Takes the parsed PaymentRequired from a 402 response, selects a
275
- * compatible payment option, signs and executes the payment through Haven.
560
+ * Takes the parsed PaymentRequired from a 402 response, selects a compatible
561
+ * option, funds the delegate wallet through Haven, and returns the standard
562
+ * x402 header that the merchant can verify and settle.
276
563
  *
277
564
  * Requires `delegateKey` to be set in the client config.
278
565
  */
@@ -282,23 +569,43 @@ var HavenClient = class {
282
569
  "delegateKey is required for x402 payments. Pass it in the HavenClient config."
283
570
  );
284
571
  }
285
- const option = selectPaymentOption(paymentRequired.accepts);
572
+ if (!this.delegateAddress) {
573
+ throw new HavenSigningError("delegateAddress could not be derived from delegateKey.");
574
+ }
575
+ const option = selectStandardPaymentOption(paymentRequired.accepts);
286
576
  if (!option) {
287
577
  throw new HavenApiError(
288
- "No compatible payment option found in x402 requirements. Haven supports Gnosis Chain (eip155:100) and Base (eip155:8453).",
578
+ "No compatible payment option found in x402 requirements. Haven supports standard x402 exact payments on Base USDC.",
289
579
  400
290
580
  );
291
581
  }
582
+ const idempotencyKey = buildX402IdempotencyKey(paymentRequired, option);
583
+ const cached = this.x402ReceiptCache.get(idempotencyKey);
584
+ if (cached && cached.expiresAt > Date.now()) return cached.receipt;
585
+ const inFlight = this.inFlightX402.get(idempotencyKey);
586
+ if (inFlight) return inFlight;
587
+ const promise = this.authorizeStandardX402(paymentRequired, option, idempotencyKey);
588
+ this.inFlightX402.set(idempotencyKey, promise);
589
+ try {
590
+ return await promise;
591
+ } finally {
592
+ this.inFlightX402.delete(idempotencyKey);
593
+ }
594
+ }
595
+ async authorizeStandardX402(paymentRequired, option, idempotencyKey) {
596
+ const paymentHeader = await this.createStandardX402Header(paymentRequired, option);
292
597
  const raw = await this.post("/x402", {
293
598
  url: paymentRequired.resource.url,
294
- payTo: option.payTo,
599
+ payTo: this.delegateAddress,
600
+ merchantPayTo: option.payTo,
295
601
  amount: option.amount,
296
602
  asset: option.asset,
297
603
  network: option.network,
298
- description: paymentRequired.resource.description
604
+ description: paymentRequired.resource.description,
605
+ idempotencyKey
299
606
  });
300
607
  if (raw.success && raw.tx_hash) {
301
- return {
608
+ const receipt2 = {
302
609
  success: true,
303
610
  paymentId: raw.payment_id,
304
611
  txHash: raw.tx_hash,
@@ -306,9 +613,17 @@ var HavenClient = class {
306
613
  amount: raw.amount ?? "",
307
614
  to: raw.to ?? "",
308
615
  resourceUrl: paymentRequired.resource.url,
309
- explorerUrl: raw.explorer_url ?? (raw.tx_hash ? buildExplorerUrl(raw.chain_id, raw.tx_hash) : "")
616
+ explorerUrl: raw.explorer_url ?? (raw.tx_hash ? buildExplorerUrl(raw.chain_id, raw.tx_hash) : ""),
617
+ accepted: option,
618
+ paymentHeader,
619
+ merchantTo: raw.merchant_to ?? option.payTo,
620
+ payer: raw.payer ?? raw.safe_address,
621
+ chainId: raw.chain_id ?? chainIdFromNetwork(option.network)
310
622
  };
623
+ this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt2);
624
+ return receipt2;
311
625
  }
626
+ this.throwIfNonSignableAuthorizationState("x402 payment", raw);
312
627
  if (!raw.sign_data?.hash) {
313
628
  throw new HavenApiError("No sign_hash returned from x402/authorize", 500, raw);
314
629
  }
@@ -318,13 +633,9 @@ var HavenClient = class {
318
633
  { signature: sig }
319
634
  );
320
635
  if (execResult.status !== "confirmed") {
321
- throw new HavenApiError(
322
- execResult.error ?? `x402 payment ${execResult.status}`,
323
- 502,
324
- execResult
325
- );
636
+ this.throwPaymentStateError("x402 payment", execResult);
326
637
  }
327
- return {
638
+ const receipt = {
328
639
  success: true,
329
640
  paymentId: raw.payment_id,
330
641
  txHash: execResult.tx_hash ?? "",
@@ -332,8 +643,15 @@ var HavenClient = class {
332
643
  amount: execResult.amount ?? raw.amount ?? "",
333
644
  to: execResult.to ?? raw.to ?? "",
334
645
  resourceUrl: paymentRequired.resource.url,
335
- explorerUrl: execResult.explorer_url ?? (execResult.tx_hash ? buildExplorerUrl(execResult.chain_id, execResult.tx_hash) : "")
646
+ explorerUrl: execResult.explorer_url ?? (execResult.tx_hash ? buildExplorerUrl(execResult.chain_id, execResult.tx_hash) : ""),
647
+ accepted: option,
648
+ paymentHeader,
649
+ merchantTo: option.payTo,
650
+ payer: raw.payer ?? raw.safe_address ?? raw.sign_data?.components.safe,
651
+ chainId: execResult.chain_id ?? raw.chain_id ?? chainIdFromNetwork(option.network)
336
652
  };
653
+ this.cacheX402Receipt(idempotencyKey, paymentHeader, receipt);
654
+ return receipt;
337
655
  }
338
656
  /**
339
657
  * Fetch wrapper that automatically handles HTTP 402 responses.
@@ -349,21 +667,314 @@ var HavenClient = class {
349
667
  * Requires `delegateKey` to be set in the client config.
350
668
  */
351
669
  async fetch(url, init) {
352
- const response = await globalThis.fetch(url, init);
670
+ const initialInit = this.withX402Wallet(init, this.x402PayerAddress());
671
+ const response = await globalThis.fetch(url, initialInit);
353
672
  if (response.status !== 402) return response;
673
+ const machineChallengeHeader = response.headers.get("MACHINE-PAYMENT-CHALLENGE");
674
+ if (machineChallengeHeader) {
675
+ const challenge = await parseMachinePaymentChallengeResponse(response);
676
+ return this.fetchWithMachinePayment(url, initialInit, challenge);
677
+ }
354
678
  let paymentRequired;
355
679
  try {
356
- paymentRequired = parsePaymentRequired(response);
680
+ paymentRequired = await parsePaymentRequiredResponse(response);
357
681
  } catch {
358
- return response;
682
+ let challenge;
683
+ try {
684
+ challenge = await parseMachinePaymentChallengeResponse(response);
685
+ } catch {
686
+ return response;
687
+ }
688
+ return this.fetchWithMachinePayment(url, initialInit, challenge);
359
689
  }
360
690
  const receipt = await this.authorizeX402(paymentRequired);
361
- const retryHeaders = new Headers(init?.headers);
362
- retryHeaders.set("PAYMENT-SIGNATURE", encodePaymentProof(receipt));
363
- return globalThis.fetch(url, {
364
- ...init,
691
+ if (!receipt.accepted) {
692
+ throw new HavenApiError("No accepted x402 option was recorded for payment retry", 500);
693
+ }
694
+ if (!receipt.paymentHeader) {
695
+ throw new HavenApiError("No x402 payment header was returned for payment retry", 500);
696
+ }
697
+ const retryHeaders = new Headers(initialInit?.headers);
698
+ retryHeaders.set("X-PAYMENT", receipt.paymentHeader);
699
+ const retryResponse = await globalThis.fetch(url, {
700
+ ...initialInit,
365
701
  headers: retryHeaders
366
702
  });
703
+ if (retryResponse.status === 402) {
704
+ await this.recordMerchantRetryRejected({
705
+ rail: "x402",
706
+ paymentId: receipt.paymentId,
707
+ txHash: receipt.txHash,
708
+ resourceUrl: receipt.resourceUrl,
709
+ retryResponse,
710
+ details: {
711
+ merchant_to: receipt.merchantTo,
712
+ delegate_to: receipt.to
713
+ }
714
+ });
715
+ throw new HavenApiError(
716
+ "x402 retry was rejected after Haven funded the delegate wallet; reconciliation may be required.",
717
+ 402,
718
+ {
719
+ marker: "x402_retry_rejected_after_funding",
720
+ payment_id: receipt.paymentId,
721
+ tx_hash: receipt.txHash,
722
+ resource_url: receipt.resourceUrl,
723
+ merchant_to: receipt.merchantTo,
724
+ delegate_to: receipt.to
725
+ }
726
+ );
727
+ }
728
+ await this.reportMachinePaymentEvidence({
729
+ paymentId: receipt.paymentId,
730
+ rail: "x402",
731
+ txHash: receipt.txHash,
732
+ resourceUrl: receipt.resourceUrl,
733
+ merchantStatus: retryResponse.status,
734
+ challengePayload: paymentRequired,
735
+ selectedPayment: receipt.accepted,
736
+ paymentProofHeaderName: "X-PAYMENT",
737
+ paymentProofHeader: receipt.paymentHeader,
738
+ protocolReceiptHeaderName: "PAYMENT-RESPONSE",
739
+ protocolReceiptHeader: retryResponse.headers.get("PAYMENT-RESPONSE") ?? void 0
740
+ });
741
+ return retryResponse;
742
+ }
743
+ async authorizeMachinePayment(challenge) {
744
+ if (!this.delegateKey) {
745
+ throw new HavenSigningError(
746
+ "delegateKey is required for machine payments. Pass it in the HavenClient config."
747
+ );
748
+ }
749
+ if (challenge.rail !== "mpp_demo") {
750
+ throw new HavenApiError(`Unsupported machine payment rail: ${challenge.rail}`, 400);
751
+ }
752
+ const idempotencyKey = buildMachinePaymentIdempotencyKey(challenge);
753
+ const inFlight = this.inFlightMachinePayments.get(idempotencyKey);
754
+ if (inFlight) return inFlight;
755
+ const promise = this.authorizeMppDemoPayment(challenge, idempotencyKey);
756
+ this.inFlightMachinePayments.set(idempotencyKey, promise);
757
+ try {
758
+ return await promise;
759
+ } finally {
760
+ this.inFlightMachinePayments.delete(idempotencyKey);
761
+ }
762
+ }
763
+ async authorizeMppDemoPayment(challenge, idempotencyKey) {
764
+ const raw = await this.post(
765
+ "/machine-payments/authorize",
766
+ { challenge, idempotencyKey }
767
+ );
768
+ if (raw.success && raw.tx_hash) {
769
+ return this.mapMachinePaymentReceipt(challenge, raw, raw.tx_hash);
770
+ }
771
+ this.throwIfNonSignableAuthorizationState("Machine payment", raw);
772
+ if (!raw.sign_data?.hash) {
773
+ throw new HavenApiError("No sign_hash returned from machine payment authorization", 500, raw);
774
+ }
775
+ const sig = signHash(this.delegateKey, raw.sign_data.hash);
776
+ const execResult = await this.post(
777
+ `/payments/${raw.payment_id}/sign`,
778
+ { signature: sig }
779
+ );
780
+ if (execResult.status !== "confirmed" || !execResult.tx_hash) {
781
+ this.throwPaymentStateError("Machine payment", execResult);
782
+ }
783
+ return this.mapMachinePaymentReceipt(challenge, raw, execResult.tx_hash, execResult);
784
+ }
785
+ async fetchWithMachinePayment(url, initialInit, challenge) {
786
+ const receipt = await this.authorizeMachinePayment(challenge);
787
+ const retryHeaders = new Headers(initialInit?.headers);
788
+ retryHeaders.set("MACHINE-PAYMENT-PROOF", receipt.proofHeader);
789
+ const retryResponse = await globalThis.fetch(url, {
790
+ ...initialInit,
791
+ headers: retryHeaders
792
+ });
793
+ if (retryResponse.status === 402) {
794
+ await this.recordMerchantRetryRejected({
795
+ rail: receipt.rail,
796
+ paymentId: receipt.paymentId,
797
+ txHash: receipt.txHash,
798
+ resourceUrl: receipt.resourceUrl,
799
+ retryResponse,
800
+ details: {
801
+ challenge_id: receipt.challengeId
802
+ }
803
+ });
804
+ throw new HavenApiError(
805
+ "Machine payment retry was rejected after Haven sent the payment.",
806
+ 402,
807
+ {
808
+ marker: "machine_payment_retry_rejected_after_payment",
809
+ payment_id: receipt.paymentId,
810
+ tx_hash: receipt.txHash,
811
+ resource_url: receipt.resourceUrl,
812
+ rail: receipt.rail
813
+ }
814
+ );
815
+ }
816
+ await this.reportMachinePaymentEvidence({
817
+ paymentId: receipt.paymentId,
818
+ rail: receipt.rail,
819
+ txHash: receipt.txHash,
820
+ resourceUrl: receipt.resourceUrl,
821
+ merchantStatus: retryResponse.status,
822
+ challengePayload: challenge,
823
+ paymentProofHeaderName: "MACHINE-PAYMENT-PROOF",
824
+ paymentProofHeader: receipt.proofHeader,
825
+ protocolReceiptHeaderName: retryResponse.headers.has("Payment-Receipt") ? "Payment-Receipt" : retryResponse.headers.has("MACHINE-PAYMENT-RESPONSE") ? "MACHINE-PAYMENT-RESPONSE" : void 0,
826
+ protocolReceiptHeader: retryResponse.headers.get("Payment-Receipt") ?? retryResponse.headers.get("MACHINE-PAYMENT-RESPONSE") ?? void 0
827
+ });
828
+ return retryResponse;
829
+ }
830
+ async createStandardX402Header(paymentRequired, option) {
831
+ if (!this.delegateKey) {
832
+ throw new HavenSigningError("delegateKey is required to sign x402 payment headers.");
833
+ }
834
+ const account = accounts.privateKeyToAccount(this.delegateKey);
835
+ const requirements = toStandardPaymentRequirements(paymentRequired, option);
836
+ const header = await schemes.exact.evm.createPaymentHeader(
837
+ account,
838
+ paymentRequired.x402Version,
839
+ requirements
840
+ );
841
+ if (paymentRequired.x402Version < 2) return header;
842
+ const payment = decodeBase64Json3(header);
843
+ return btoa(JSON.stringify({
844
+ x402Version: paymentRequired.x402Version,
845
+ accepted: option,
846
+ payload: payment.payload
847
+ }));
848
+ }
849
+ cacheX402Receipt(idempotencyKey, paymentHeader, receipt) {
850
+ const expiresAt = getPaymentHeaderValidBefore(paymentHeader);
851
+ if (expiresAt > Date.now()) {
852
+ this.x402ReceiptCache.set(idempotencyKey, { expiresAt, receipt });
853
+ }
854
+ }
855
+ mapMachinePaymentReceipt(challenge, raw, txHash, execResult) {
856
+ const receiptWithoutHeader = {
857
+ success: true,
858
+ rail: challenge.rail,
859
+ paymentId: raw.payment_id,
860
+ challengeId: challenge.challengeId,
861
+ txHash,
862
+ token: execResult?.token ?? raw.token ?? challenge.asset.symbol,
863
+ amount: execResult?.amount ?? raw.amount ?? challenge.amount.display,
864
+ to: execResult?.to ?? raw.to ?? challenge.recipient,
865
+ resourceUrl: raw.resource_url ?? challenge.resource,
866
+ explorerUrl: execResult?.explorer_url ?? raw.explorer_url ?? buildExplorerUrl(execResult?.chain_id ?? raw.chain_id ?? challenge.network.chainId, txHash),
867
+ payer: raw.payer ?? raw.safe_address,
868
+ chainId: execResult?.chain_id ?? raw.chain_id ?? challenge.network.chainId
869
+ };
870
+ return {
871
+ ...receiptWithoutHeader,
872
+ proofHeader: encodeMachinePaymentProof(receiptWithoutHeader)
873
+ };
874
+ }
875
+ async recordMerchantRetryRejected(input) {
876
+ try {
877
+ await this.post("/machine-payments/reconciliation-events", {
878
+ paymentId: input.paymentId,
879
+ rail: input.rail,
880
+ eventType: "merchant_retry_rejected_after_payment",
881
+ txHash: input.txHash,
882
+ reason: `Merchant returned HTTP ${input.retryResponse.status} after Haven payment confirmation`,
883
+ details: {
884
+ resource_url: input.resourceUrl,
885
+ retry_status: input.retryResponse.status,
886
+ retry_body: await responseSnippet(input.retryResponse),
887
+ ...input.details
888
+ }
889
+ });
890
+ } catch {
891
+ }
892
+ }
893
+ async reportMachinePaymentEvidence(input) {
894
+ try {
895
+ await this.post("/machine-payments/evidence", {
896
+ paymentId: input.paymentId,
897
+ rail: input.rail,
898
+ txHash: input.txHash,
899
+ resourceUrl: input.resourceUrl,
900
+ merchantStatus: input.merchantStatus,
901
+ challengePayload: input.challengePayload,
902
+ selectedPayment: input.selectedPayment,
903
+ paymentProofHeaderName: input.paymentProofHeaderName,
904
+ paymentProofHeader: input.paymentProofHeader,
905
+ protocolReceiptHeaderName: input.protocolReceiptHeaderName,
906
+ protocolReceiptHeader: input.protocolReceiptHeader,
907
+ protocolReceiptPayload: input.protocolReceiptHeader ? parseProtocolReceiptHeader(input.protocolReceiptHeader) : void 0
908
+ });
909
+ } catch {
910
+ }
911
+ }
912
+ throwIfNonSignableAuthorizationState(label, raw) {
913
+ if (raw.status === "pending_signature") return;
914
+ this.throwPaymentStateError(label, raw);
915
+ }
916
+ throwPaymentStateError(label, raw) {
917
+ const statusCode = PAYMENT_STATE_STATUS_CODES[raw.status] ?? 502;
918
+ const state = this.paymentStateFromRaw(label, raw);
919
+ if (state) {
920
+ throw new HavenPaymentStateError(state.message, statusCode, state, raw);
921
+ }
922
+ if (raw.status === "pending_approval") {
923
+ throw new HavenApiError(
924
+ `${label} exceeds the on-chain allowance and was queued for owner approval (payment_id: ${raw.payment_id}).`,
925
+ statusCode,
926
+ raw
927
+ );
928
+ }
929
+ if (raw.status === "expired") {
930
+ throw new HavenApiError(
931
+ `${label} expired before it could be completed (payment_id: ${raw.payment_id}).`,
932
+ statusCode,
933
+ raw
934
+ );
935
+ }
936
+ const paymentId = raw.payment_id ? ` (payment_id: ${raw.payment_id})` : "";
937
+ const message = raw.error ?? `${label} ${raw.status}${paymentId}`;
938
+ throw new HavenApiError(message, statusCode, raw);
939
+ }
940
+ paymentStateFromRaw(label, raw) {
941
+ if (!raw.payment_id || !raw.status) return null;
942
+ const phase = raw.phase ?? phaseForStatus(raw.status);
943
+ const nextAction = raw.next_action ?? nextActionForStatus(raw.status);
944
+ if (!phase || !nextAction) return null;
945
+ const amount = raw.amount ?? raw.requested ?? "";
946
+ const token = raw.token ?? "";
947
+ const message = raw.message ?? raw.error ?? messageForState(label, raw.status, raw.payment_id, nextAction);
948
+ return {
949
+ paymentId: raw.payment_id,
950
+ kind: raw.kind === "payment_intent" ? "payment_intent" : "approval_request",
951
+ rail: raw.rail ?? "direct",
952
+ status: raw.status === "pending" ? "pending_approval" : raw.status,
953
+ phase,
954
+ nextAction,
955
+ amount,
956
+ token,
957
+ resourceUrl: raw.resource_url ?? null,
958
+ merchantAddress: raw.merchant_to ?? null,
959
+ txHash: raw.tx_hash ?? null,
960
+ expiresAt: raw.expires_at ?? "",
961
+ chainId: raw.chain_id ?? 0,
962
+ message
963
+ };
964
+ }
965
+ x402PayerAddress() {
966
+ return this.delegateAddress ?? this.x402Wallet;
967
+ }
968
+ withX402Wallet(init, wallet = this.x402PayerAddress()) {
969
+ if (!wallet) return init;
970
+ const headers = new Headers(init?.headers);
971
+ if (!headers.has("x402-wallet")) {
972
+ headers.set("x402-wallet", wallet);
973
+ }
974
+ return {
975
+ ...init,
976
+ headers
977
+ };
367
978
  }
368
979
  // ── Tool Execution (for agent frameworks) ────────────────────────
369
980
  /**
@@ -395,10 +1006,7 @@ var HavenClient = class {
395
1006
  error: result.errorMessage
396
1007
  };
397
1008
  } catch (err) {
398
- return {
399
- success: false,
400
- error: err instanceof Error ? err.message : String(err)
401
- };
1009
+ return this.toolError(err);
402
1010
  }
403
1011
  }
404
1012
  if (toolName === "authorize_x402_payment") {
@@ -426,30 +1034,95 @@ var HavenClient = class {
426
1034
  amount: receipt.amount,
427
1035
  to: receipt.to,
428
1036
  resource_url: receipt.resourceUrl,
429
- explorer_url: receipt.explorerUrl
1037
+ explorer_url: receipt.explorerUrl,
1038
+ payment_header: receipt.paymentHeader,
1039
+ merchant_to: receipt.merchantTo,
1040
+ payer: receipt.payer,
1041
+ chain_id: receipt.chainId
430
1042
  };
431
1043
  } catch (err) {
1044
+ return this.toolError(err);
1045
+ }
1046
+ }
1047
+ if (toolName === "authorize_machine_payment") {
1048
+ const { challenge } = input;
1049
+ try {
1050
+ const receipt = await this.authorizeMachinePayment(challenge);
432
1051
  return {
433
- success: false,
434
- error: err instanceof Error ? err.message : String(err)
1052
+ success: true,
1053
+ payment_id: receipt.paymentId,
1054
+ tx_hash: receipt.txHash,
1055
+ token: receipt.token,
1056
+ amount: receipt.amount,
1057
+ to: receipt.to,
1058
+ resource_url: receipt.resourceUrl,
1059
+ explorer_url: receipt.explorerUrl,
1060
+ proof_header: receipt.proofHeader,
1061
+ rail: receipt.rail,
1062
+ challenge_id: receipt.challengeId,
1063
+ payer: receipt.payer,
1064
+ chain_id: receipt.chainId
435
1065
  };
1066
+ } catch (err) {
1067
+ return this.toolError(err);
436
1068
  }
437
1069
  }
438
1070
  if (toolName === "get_payment_status") {
439
1071
  const { payment_id } = input;
440
- const result = await this.getPayment(payment_id);
1072
+ const result = await this.getPaymentStatus(payment_id);
441
1073
  return {
442
1074
  payment_id: result.paymentId,
1075
+ kind: result.kind,
1076
+ rail: result.rail,
443
1077
  status: result.status,
1078
+ phase: result.phase,
1079
+ next_action: result.nextAction,
444
1080
  tx_hash: result.txHash,
445
1081
  token: result.token,
446
1082
  amount: result.amount,
447
- to: result.to,
448
- explorer_url: result.explorerUrl
1083
+ resource_url: result.resourceUrl,
1084
+ merchant_address: result.merchantAddress,
1085
+ expires_at: result.expiresAt,
1086
+ chain_id: result.chainId,
1087
+ message: result.message
449
1088
  };
450
1089
  }
451
1090
  throw new Error(`Unknown tool: ${toolName}`);
452
1091
  }
1092
+ toolError(err) {
1093
+ if (err instanceof HavenPaymentStateError) {
1094
+ return {
1095
+ success: false,
1096
+ payment_id: err.state.paymentId,
1097
+ kind: err.state.kind,
1098
+ rail: err.state.rail,
1099
+ status: err.state.status,
1100
+ phase: err.state.phase,
1101
+ next_action: err.state.nextAction,
1102
+ tx_hash: err.state.txHash,
1103
+ token: err.state.token,
1104
+ amount: err.state.amount,
1105
+ resource_url: err.state.resourceUrl,
1106
+ merchant_address: err.state.merchantAddress,
1107
+ expires_at: err.state.expiresAt,
1108
+ chain_id: err.state.chainId,
1109
+ message: err.state.message,
1110
+ error: err.message
1111
+ };
1112
+ }
1113
+ if (err instanceof HavenApiError) {
1114
+ return {
1115
+ success: false,
1116
+ status_code: err.statusCode,
1117
+ error: err.message,
1118
+ body: err.body
1119
+ };
1120
+ }
1121
+ return {
1122
+ success: false,
1123
+ error: err instanceof Error ? err.message : String(err)
1124
+ };
1125
+ }
453
1126
  // ── HTTP Helpers ─────────────────────────────────────────────────
454
1127
  async post(path, body) {
455
1128
  return this.request("POST", path, body);
@@ -508,10 +1181,62 @@ var HavenClient = class {
508
1181
  expiresAt: raw.expires_at
509
1182
  };
510
1183
  }
1184
+ mapPaymentStatusResult(raw) {
1185
+ return {
1186
+ paymentId: raw.payment_id,
1187
+ kind: raw.kind,
1188
+ rail: raw.rail,
1189
+ status: raw.status,
1190
+ phase: raw.phase,
1191
+ nextAction: raw.next_action,
1192
+ amount: raw.amount,
1193
+ token: raw.token,
1194
+ resourceUrl: raw.resource_url,
1195
+ merchantAddress: raw.merchant_address,
1196
+ txHash: raw.tx_hash,
1197
+ expiresAt: raw.expires_at,
1198
+ chainId: raw.chain_id,
1199
+ message: raw.message
1200
+ };
1201
+ }
511
1202
  };
512
1203
  function sleep(ms) {
513
1204
  return new Promise((resolve) => setTimeout(resolve, ms));
514
1205
  }
1206
+ function getPaymentHeaderValidBefore(paymentHeader) {
1207
+ try {
1208
+ const payment = decodeBase64Json3(
1209
+ paymentHeader
1210
+ );
1211
+ const payload = payment.payload;
1212
+ const validBeforeSeconds = Number(payload.authorization?.validBefore);
1213
+ if (Number.isFinite(validBeforeSeconds)) return validBeforeSeconds * 1e3;
1214
+ } catch {
1215
+ }
1216
+ return 0;
1217
+ }
1218
+ function decodeBase64Json3(value) {
1219
+ return JSON.parse(atob(value));
1220
+ }
1221
+ function parseProtocolReceiptHeader(value) {
1222
+ try {
1223
+ return JSON.parse(atob(value));
1224
+ } catch {
1225
+ try {
1226
+ return JSON.parse(value);
1227
+ } catch {
1228
+ return void 0;
1229
+ }
1230
+ }
1231
+ }
1232
+ async function responseSnippet(response) {
1233
+ try {
1234
+ const text = await response.clone().text();
1235
+ return text.slice(0, 1e3) || null;
1236
+ } catch {
1237
+ return null;
1238
+ }
1239
+ }
515
1240
 
516
1241
  // src/tools.ts
517
1242
  var makePaymentSchema = {
@@ -576,9 +1301,20 @@ var authorizeX402Schema = {
576
1301
  },
577
1302
  required: ["url", "payTo", "amount", "asset", "network"]
578
1303
  };
579
- var MAKE_PAYMENT_DESCRIPTION = "Send a payment from the Haven-managed Safe wallet. The payment will be validated against the agent's on-chain spending policy. Gnosis Chain tokens: EURe, USDC.e, xDAI. Base tokens: USDC, ETH.";
580
- var GET_STATUS_DESCRIPTION = "Check the status of a previously initiated payment. Returns the current status, transaction hash (if confirmed), and payment details.";
581
- var AUTHORIZE_X402_DESCRIPTION = "Authorize payment for an HTTP 402 (Payment Required) response. When a paid API returns 402 with x402 payment requirements, use this tool to pay and get access. Haven evaluates the payment against policy and executes from the Safe wallet.";
1304
+ var authorizeMachinePaymentSchema = {
1305
+ type: "object",
1306
+ properties: {
1307
+ challenge: {
1308
+ type: "object",
1309
+ description: "Machine payment challenge returned by a Haven demo endpoint"
1310
+ }
1311
+ },
1312
+ required: ["challenge"]
1313
+ };
1314
+ 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.";
1315
+ 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.";
1316
+ 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.";
1317
+ 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.";
582
1318
  function claudeTools() {
583
1319
  return [
584
1320
  {
@@ -595,6 +1331,11 @@ function claudeTools() {
595
1331
  name: "authorize_x402_payment",
596
1332
  description: AUTHORIZE_X402_DESCRIPTION,
597
1333
  input_schema: authorizeX402Schema
1334
+ },
1335
+ {
1336
+ name: "authorize_machine_payment",
1337
+ description: AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION,
1338
+ input_schema: authorizeMachinePaymentSchema
598
1339
  }
599
1340
  ];
600
1341
  }
@@ -623,6 +1364,14 @@ function openaiTools() {
623
1364
  description: AUTHORIZE_X402_DESCRIPTION,
624
1365
  parameters: authorizeX402Schema
625
1366
  }
1367
+ },
1368
+ {
1369
+ type: "function",
1370
+ function: {
1371
+ name: "authorize_machine_payment",
1372
+ description: AUTHORIZE_MACHINE_PAYMENT_DESCRIPTION,
1373
+ parameters: authorizeMachinePaymentSchema
1374
+ }
626
1375
  }
627
1376
  ];
628
1377
  }
@@ -636,12 +1385,18 @@ var havenTools = {
636
1385
  exports.HavenApiError = HavenApiError;
637
1386
  exports.HavenClient = HavenClient;
638
1387
  exports.HavenError = HavenError;
1388
+ exports.HavenPaymentStateError = HavenPaymentStateError;
639
1389
  exports.HavenSigningError = HavenSigningError;
640
1390
  exports.HavenTimeoutError = HavenTimeoutError;
641
1391
  exports.addressFromKey = addressFromKey;
1392
+ exports.buildMachinePaymentIdempotencyKey = buildMachinePaymentIdempotencyKey;
1393
+ exports.encodeMachinePaymentProof = encodeMachinePaymentProof;
642
1394
  exports.encodePaymentProof = encodePaymentProof;
643
1395
  exports.havenTools = havenTools;
1396
+ exports.parseMachinePaymentChallenge = parseMachinePaymentChallenge;
1397
+ exports.parseMachinePaymentChallengeResponse = parseMachinePaymentChallengeResponse;
644
1398
  exports.parsePaymentRequired = parsePaymentRequired;
1399
+ exports.parsePaymentRequiredResponse = parsePaymentRequiredResponse;
645
1400
  exports.selectPaymentOption = selectPaymentOption;
646
1401
  exports.signHash = signHash;
647
1402
  exports.verifySignature = verifySignature;