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