@haven_ai/sdk 0.1.30-alpha.0 → 0.1.32-alpha.0

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/README.md CHANGED
@@ -51,8 +51,9 @@ const response = await haven.fetch('https://your-x402-endpoint.example/resource'
51
51
  const data = await response.json()
52
52
  ```
53
53
 
54
- The payment fits within the agent's on-chain allowance (or is queued for your
55
- approval if it exceeds it), and shows up in your Haven dashboard activity feed.
54
+ The payment fits within the agent's on-chain budget anything outside it is
55
+ declined before any money moves, never queued for you to approve later and it
56
+ shows up in your Haven dashboard activity feed.
56
57
 
57
58
  ## Supported Networks & Tokens
58
59
 
@@ -65,13 +66,20 @@ approval if it exceeds it), and shows up in your Haven dashboard activity feed.
65
66
 
66
67
  - The Haven API key identifies the agent. It is not payment authority.
67
68
  - The delegate key signs payment payloads locally. Haven's backend never receives it.
68
- - On-chain Safe AllowanceModule state enforces the agent budget.
69
+ - The agent's on-chain budget delegation enforces the agent budget: budget, recipient and expiry are checked by audited caveat enforcers at redemption, not by an off-chain rules engine.
69
70
  - `getAllowances()` / `get_allowances` is the right path for budget, remaining amount, reset period, or "what can I spend?" questions.
70
71
  - If an API key is exposed or lost, rotate it from the Haven agent detail page. The new key is shown once and the old key stops working.
71
- - If a delegate key is exposed or lost, a delegation-rail agent is **re-keyed** rather than replaced — same agent, new signing key, budget remainder carried. See [Replacing an agent's signing key](../../docs/product/agent-key-rotation.md). Legacy AllowanceModule agents are paused or revoked and re-onboarded instead.
72
+ - If a delegate key is exposed or lost, a delegation-rail agent is **re-keyed** rather than replaced — same agent, new signing key, budget remainder carried. See [Replacing an agent's signing key](../../docs/product/agent-key-rotation.md).
72
73
 
73
74
  ## Step-by-Step API
74
75
 
76
+ Discovery and listing: `discoverTools({ verified?: 'any' | 'verified' | 'operator' })` returns the merged
77
+ catalog — operator-curated plus `verified_payable` directory entries (epic #1717), each with `source`,
78
+ `domainVerified` and `verifiedPayable`. `submitCatalogEntry(resourceUrl)` submits a merchant endpoint to
79
+ the Verified Payable Directory (queue-only; the seller still must prove domain ownership before listing),
80
+ and `getCatalogSubmissionStatus(id)` returns coarse status plus the ownership-proof instructions while
81
+ the submission can still prove ownership.
82
+
75
83
  For agents that need control over each step (e.g., external signing):
76
84
 
77
85
  ```typescript
@@ -96,11 +104,11 @@ const result = await haven.waitForConfirmation(intent.paymentId)
96
104
 
97
105
  Production merchant acceptance, facilitator, settlement, fiat, or acquiring functionality needs separate product and legal review under the repo's [CASP / MiCA guardrails](../../docs/regulatory/casp-risk-guardrails.md). The hosted x402 endpoint is an internal technical demo, not a merchant settlement product.
98
106
 
99
- The SDK supports [x402](https://x402.org) client flows. When an API returns HTTP 402, the SDK evaluates the challenge against the agent's approved limits, uses the configured delegate key for the required signature, and retries automatically:
107
+ The SDK supports [x402](https://x402.org) client flows. When an API returns HTTP 402, the SDK evaluates the challenge against the agent's on-chain budget, uses the configured delegate key for the required signature, and retries automatically:
100
108
 
101
109
  ```typescript
102
110
  // Automatic — fetch() intercepts 402, pays, and retries.
103
- // Use a stable idempotencyKey when one user intent may need manual approval.
111
+ // Use a stable idempotencyKey so one user intent stays one Haven payment.
104
112
  const response = await haven.fetch(
105
113
  'https://paid-api.example.com/data',
106
114
  undefined,
@@ -172,7 +180,7 @@ delegate's balance, so an accidental key collision refuses on the weaker
172
180
  for.
173
181
 
174
182
  **Resuming is not affected by that.** When you are following the documented
175
- approval flow — re-calling after a queued payment is approved, or calling
183
+ resume flow — re-calling after a funding leg confirms, or calling
176
184
  `resumeAuthorizedX402({ paymentId })` — you named the payment, so an
177
185
  unverifiable balance lets the resume proceed as before. Only a balance
178
186
  verified *absent* refuses there. The stricter default applies solely to the
@@ -184,8 +192,7 @@ no funding leg and no delegate balance to exhaust.
184
192
 
185
193
  For agents that need to inspect the price before paying, use the quote-first
186
194
  path. `quoteX402()` probes the merchant and parses the HTTP 402 response, but it
187
- does not create a Haven payment, approval request, signature, or on-chain
188
- transaction.
195
+ does not create a Haven payment, signature, or on-chain transaction.
189
196
 
190
197
  ```typescript
191
198
  const quote = await haven.quoteX402(
@@ -238,13 +245,13 @@ for (const block of response.content) {
238
245
 
239
246
  | Tool | Description |
240
247
  |------|-------------|
241
- | `make_payment` | Request and sign a payment from the user-controlled Safe within approved limits |
242
- | `get_payment_status` | Check the status of a payment intent or approval request |
243
- | `get_allowances` | Read configured and on-chain allowance state, including spent and remaining allowance |
248
+ | `make_payment` | Request and sign a payment from the user-controlled account within its on-chain budget |
249
+ | `get_payment_status` | Check the status of a payment intent |
250
+ | `get_allowances` | Read configured and on-chain budget state, including spent and remaining budget |
244
251
  | `authorize_x402_payment` | Authorize a policy-limited x402 payment and return a payment header for an HTTP 402 resource |
245
- | `resume_x402_payment` | Resume an approved x402 payment and return a merchant payment header without creating a duplicate approval |
252
+ | `resume_x402_payment` | Resume an authorized x402 payment and return a merchant payment header without creating a duplicate payment |
246
253
 
247
- Use `get_allowances` for allowance, budget, spend-limit, remaining amount, reset-period, or "what can I spend?" questions. Payment tools still require the agent-held delegate key and on-chain Safe allowance state; the Haven API key identifies the agent but does not authorize spending by itself.
254
+ Use `get_allowances` for allowance, budget, spend-limit, remaining amount, reset-period, or "what can I spend?" questions. Payment tools still require the agent-held delegate key and the on-chain budget delegation; the Haven API key identifies the agent but does not authorize spending by itself.
248
255
 
249
256
  ## Configuration
250
257
 
@@ -273,12 +280,12 @@ receipts, and transactions. `POST /machine-payments/authorize` (the legacy
273
280
  internal MPP demo challenge flow) is retired — it now refuses unconditionally
274
281
  with HTTP 410; use the x402 flow for agent-to-merchant payments. Its security
275
282
  scheme is deliberate: the Haven API key identifies the agent, but payment
276
- authority still requires an agent-held delegate signature and on-chain Safe
277
- allowance state.
283
+ authority still requires an agent-held delegate signature and an on-chain
284
+ budget delegation.
278
285
 
279
286
  ## Agent payment state machine
280
287
 
281
- Every payment or approval state returned by Haven includes:
288
+ Every payment state returned by Haven includes:
282
289
 
283
290
  - `phase`: where the Haven-side payment currently is.
284
291
  - `nextAction`: the stable action an agent should take next.
@@ -312,26 +319,21 @@ import {
312
319
  │ payment_submitted │
313
320
  └──────────┬──────────────┘
314
321
  │ check_status_later
315
- ┌──────────┴──────────────┐
316
- ▼ ▼
317
- ┌────────────────────────┐ ┌──────────────────────┐
318
- │ payment_confirmed (✔) │ │ user_approval_required│
319
- └────────────────────────┘ └──────────┬───────────┘
320
- wait_for_user_approval
321
- ┌─────────────────┴───────────────────┐
322
- single-owner Safe │ multisig Safe
323
- ▼ ▼
324
- ┌──────────────────────────┐ ┌──────────────────────────────────┐
325
- user_execution_required │ waiting_for_additional_approvals │
326
- └──────────┬───────────────┘ └────────────────┬─────────────────┘
327
- wait_for_user_to_complete_payment │ wait_for_user_approval
328
- └─────────────────┬───────────────────┘
329
-
330
- ┌───────────────────────┐
331
- │ funding_sent │
332
- └──────────┬────────────┘
333
- │ retry_original_x402_request (x402)
334
- │ none (direct)
322
+
323
+ ┌─────────────────────────┐
324
+ │ payment_confirmed (✔) │
325
+ └─────────────────────────┘
326
+
327
+ (EIP-3009 bridge only. `funding_sent` is Haven's funding leg confirming —
328
+ value left the treasury and sits on the delegate EOA. `executed` is the
329
+ agent's own merchant retry succeeding; Haven has no phase for the merchant
330
+ leg itself. See the `retry_original_x402_request` row below.)
331
+ ┌───────────────────────┐
332
+ funding_sent
333
+ └──────────┬────────────┘
334
+ retry_original_x402_request (x402, after the
335
+ │ merchant-report grace window — #2145)
336
+ │ none (direct / erc7710)
335
337
 
336
338
  ┌───────────────────────┐
337
339
  │ executed (✔) │
@@ -354,12 +356,12 @@ x402 tool-window failures:
354
356
  | `agent_signature_required` | Haven prepared a payment intent; the agent must sign and submit. | no |
355
357
  | `payment_submitted` | Haven received the signed payment; the agent should poll for confirmation. | no |
356
358
  | `payment_confirmed` | Direct payment is confirmed on chain. | yes |
357
- | `user_approval_required` | Payment exceeds remaining on-chain allowance; wallet owner must approve in Haven. | no |
358
- | `user_execution_required` | Owner approved; the funding payment has not been sent yet (single-owner Safe). | no |
359
- | `waiting_for_additional_approvals` | Funding payment was proposed and is waiting for the remaining multisig approvals. | no |
360
- | `funding_sent` | Haven funding leg landed; the agent can continue the merchant/protocol leg. | no |
361
- | `rejected` | Owner rejected the request. | yes |
362
- | `expired` | Payment or approval request expired before completion. | yes |
359
+ | `user_approval_required` | **No live rail produces it.** Described the retired Safe rail's approval queue; kept in the exported enum for wire compatibility only. A payment outside the budget is now declined outright — see [Payments outside the agent's budget](#payments-outside-the-agents-budget). | n/a |
360
+ | `user_execution_required` | **No live rail produces it.** Same retirement as above. | n/a |
361
+ | `waiting_for_additional_approvals` | **No live rail produces it.** Same retirement as above. | n/a |
362
+ | `funding_sent` | Haven funding leg landed; the agent can continue the merchant/protocol leg. Only the EIP-3009 bridge has a funding leg; erc7710 direct settlement has none. | no |
363
+ | `rejected` | The payment was rejected and cannot proceed. | yes |
364
+ | `expired` | Payment expired before completion. | yes |
363
365
  | `failed` | Haven could not complete the payment. | yes |
364
366
 
365
367
  The merchant settlement leg of x402 (and the MPP retry) is the agent's own request to the merchant — it does not have a Haven `phase`. The payment is `funding_sent` until the agent retries with `X-PAYMENT` (x402) or the MPP proof header; from Haven's perspective the payment becomes `executed` only after the agent successfully resumes.
@@ -371,9 +373,9 @@ The merchant settlement leg of x402 (and the MPP retry) is the agent's own reque
371
373
  | `sign_and_submit_payment` | Sign with the delegate key and submit the payment to Haven. |
372
374
  | `check_status_later` | Poll `getPaymentStatus(payment_id)` later. |
373
375
  | `none` | Stop polling; no more action is needed for this payment id. |
374
- | `wait_for_user_approval` | Tell the user the payment is waiting in Haven, then poll later. Do not create a duplicate payment. Same `nextAction` covers both the single-owner case (waiting for one owner to approve) and the multisig case (waiting for additional approvals after the first one). |
375
- | `wait_for_user_to_complete_payment` | The user approved the request; wait for them to finish the funding payment. |
376
- | `retry_original_x402_request` | Resume this payment id and retry the original x402 request with the merchant payment header. Do not start a new merchant session. |
376
+ | `wait_for_user_approval` | **No longer produced nothing maps to it.** Retired with the Safe rail's approval queue; kept in the exported enum for wire compatibility. The SDK's own status mapping now answers `stop_and_tell_user` for the statuses that used to yield this. |
377
+ | `wait_for_user_to_complete_payment` | **No longer produced nothing maps to it.** Same retirement as above. |
378
+ | `retry_original_x402_request` | Haven's funding leg confirmed but no merchant response was ever recorded — most often because the process crashed between the funding confirmation and the merchant retry (a 15-minute grace window applies before this fires; a client-reported merchant rejection instead yields `sweep_stranded_funds`). Call `resumeX402Payment()` with the preserved `resumeState`, or rehydrate it first with `getResumeState(payment_id)`. Do not start a new payment for the same purchase. |
377
379
  | `stop_and_tell_user` | Stop retrying and tell the user the payment failed or was rejected. |
378
380
  | `request_again_if_user_still_wants_it` | The request expired; ask again only if the user still wants the payment. |
379
381
  | `payment_window_expired` | The x402 funding/quote window expired. Re-quote the same paid MCP tool call with the same `idempotency_key`, then sign the fresh `payload_hash`. |
@@ -391,55 +393,70 @@ Hosted MCP and signer tools also return stable `code` values on recoverable x402
391
393
  | `PAYMENT_WINDOW_EXPIRED` | The funding/quote window closed before `haven_x402_sign_header`, `haven_submit`, or `haven_complete_mcp_tool` could finish. | Re-run `haven_pay_mcp_tool` with the same `idempotency_key`, then sign and complete the fresh quote. Payloads include `retry_with_new_quote: true`. |
392
394
  | `MERCHANT_REJECTED_AFTER_FUNDING` | Haven's funding leg succeeded, but the merchant rejected the paid retry. | Stop retrying the merchant and call `haven_sweep_delegate` so the user can recover stranded delegate USDC. |
393
395
 
394
- ## Payments above the on-chain allowance
395
-
396
- Haven's policy lives on the Safe AllowanceModule (token, amount, reset period).
397
- If an agent requests a payment above the remaining allowance, Haven does **not**
398
- reject it it returns HTTP 202 with `status: 'pending_approval'`, a
399
- `payment_id`, `phase`, and `next_action`, then queues it for the wallet owner
400
- to approve in the dashboard.
401
-
402
- Surface that to the user: the payment isn't dead, it's waiting for a human to
403
- sign off. Check `getPaymentStatus(payment_id)` or the `get_payment_status`
404
- tool later instead of retrying in a tight loop.
405
-
406
- For x402, approval resume is explicit. If `authorizeX402()` or `haven.fetch()`
407
- throws `HavenPaymentStateError` with `nextAction: 'wait_for_user_approval'`,
408
- stop and tell the user the Haven funding leg is waiting in Haven. Do not loop
409
- and do not start a new merchant or MCP session. Pending x402 states include the
410
- resource URL, merchant address, chain id, asset, network, atomic amount, and
411
- idempotency key so agents can explain what is waiting for approval. After the
412
- user approves, call `getPaymentStatus(payment_id)`. When Haven reports
413
- `nextAction: 'retry_original_x402_request'`, call `resumeX402Payment()` with the
414
- same user-intent idempotency key and the original x402 details.
415
-
416
- When the agent used `quoteX402()` / `payX402Quote()`, pending approval errors
417
- include a serializable `resumeState`. Persist it with the MCP session details
418
- and pass it back to `resumeX402Payment()` after approval.
396
+ ## Payments outside the agent's budget
397
+
398
+ Haven's policy is the agent's on-chain budget delegation a period budget, an
399
+ optional recipient pin, and an expiry, each enforced by an audited caveat
400
+ enforcer at redemption. There is no off-chain rules engine and **no approval
401
+ queue**: the queue-and-approve path belonged to the retired Safe rail, which now
402
+ answers HTTP 410 at every agent-payment entry point.
403
+
404
+ If an agent requests a payment outside that policy, Haven **declines it before
405
+ any money moves** during prepare, before anything is written and before the
406
+ agent is asked to sign. `POST /payments` answers `403` when no active delegation
407
+ authorizes that token and recipient, and `502` when the on-chain caveat check
408
+ rejects the amount, recipient or expiry; the x402 authorize path answers `403
409
+ delegation_budget_exceeded`. In every case the SDK raises `HavenApiError` and no
410
+ `payment_id` exists to poll.
411
+
412
+ Surface that to the user as a decline, not a wait: **nothing will arrive later.**
413
+ The fix is for the wallet owner to grant or raise the budget in Haven, after
414
+ which the agent can request the payment again. Do not retry in a loop, and do
415
+ not poll `getPaymentStatus()` hoping for an approval.
416
+
417
+ ### Resuming an x402 payment
418
+
419
+ Resume was triggered by *funding confirmation*, not by an approval, and applied
420
+ only to the EIP-3009 bridge erc7710 direct settlement has no funding leg and
421
+ nothing to resume.
422
+
423
+ > **Resume is reachable again (#2145).** If the agent process crashes after
424
+ > Haven's funding leg confirms but before the merchant retry is recorded, a
425
+ > later `getPaymentStatus(payment_id)` reports
426
+ > `nextAction: 'retry_original_x402_request'` — Haven's funding confirmed but
427
+ > the merchant has likely not been paid. Gate on that structured field, not on
428
+ > message prose: call `resumeX402Payment()` with the preserved `resumeState`, or
429
+ > rehydrate it first via `getResumeState(payment_id)`. Any other `nextAction`
430
+ > means the payment is not ready to resume — do not call it speculatively.
431
+ >
432
+ > Meanwhile: the `payX402*` helpers perform the merchant retry themselves, so
433
+ > the ordinary in-flight path never needs resume. Only reach for
434
+ > `resumeX402Payment()` after seeing the trigger on a later status check —
435
+ > never speculatively, and never as a substitute for a fresh payment.
436
+
437
+ When the agent used `quoteX402()` / `payX402Quote()`, the thrown
438
+ `HavenPaymentStateError` includes a serializable `resumeState`. Persist it with
439
+ the MCP session details and pass it back to `resumeX402Payment()`.
419
440
 
420
441
  If the agent process restarts and only kept the `payment_id`, call
421
- `getResumeState(payment_id)` after approval to rehydrate the stored x402/MPP
422
- context from Haven, then pass that state to the matching resume helper. For
423
- POST-based merchant or MCP calls, rebuild the live request details before
424
- retrying; Haven stores payment context, not the agent's local request stream.
442
+ `getResumeState(payment_id)` to rehydrate the stored x402/MPP context from
443
+ Haven, then pass that state to the matching resume helper. For POST-based
444
+ merchant or MCP calls, rebuild the live request details before retrying; Haven
445
+ stores payment context, not the agent's local request stream.
425
446
 
426
447
  ```typescript
427
448
  let resumeState
428
449
  try {
429
450
  await haven.payX402Quote(quote)
430
451
  } catch (err) {
431
- if (
432
- err instanceof HavenPaymentStateError &&
433
- err.nextAction === AgentPaymentNextAction.WaitForUserApproval &&
434
- err.resumeState
435
- ) {
452
+ if (err instanceof HavenPaymentStateError && err.resumeState) {
436
453
  resumeState = err.resumeState
437
454
  console.log(err.paymentId, err.phase, err.nextAction)
438
- console.log('Queued for owner approval. Save resumeState and wait.')
455
+ console.log('Funding has not confirmed yet. Save resumeState and poll.')
439
456
  }
440
457
  }
441
458
 
442
- const status = await haven.getPaymentStatus('approval-or-payment-id')
459
+ const status = await haven.getPaymentStatus('payment-id')
443
460
  if (status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request) {
444
461
  resumeState ??= await haven.getResumeState(status.paymentId)
445
462
  const response = await haven.resumeX402Payment(resumeState)
@@ -447,11 +464,12 @@ if (status.nextAction === AgentPaymentNextAction.RetryOriginalX402Request) {
447
464
  }
448
465
  ```
449
466
 
450
- Think of manual approval x402 as two separate legs:
467
+ Think of bridged x402 as two separate legs:
451
468
 
452
- - Haven funding leg: the user may need to approve a Safe AllowanceModule transfer
453
- to the agent delegate wallet. Status fields such as `phase`,
454
- `nextAction`, and `txHash` describe this leg.
469
+ - Haven funding leg: the account funds the agent delegate wallet by redeeming
470
+ the budget delegation. Status fields such as `phase`, `nextAction`, and
471
+ `txHash` describe this leg. It is automatic and bounded by the budget — no
472
+ human step.
455
473
  - Merchant x402 leg: after the funding leg is complete, the agent resumes the
456
474
  same payment id and retries the original merchant request with `X-PAYMENT`.
457
475
  Do not treat a new 402 probe or a new MCP session as a resume.
@@ -473,14 +491,15 @@ await fetch('https://paid-api.example.com/data', {
473
491
 
474
492
  For MCP/SSE x402 tools, keep the same MCP session and JSON-RPC payload where the
475
493
  merchant requires it: initialize, retain `mcp-session-id`, send the original
476
- `tools/call`, parse the 402 challenge, wait for approval if needed, then resume
477
- with the same `payment_id` and retry the original `tools/call` with
478
- `X-PAYMENT`. Use a stable `idempotencyKey` for the user intent so fresh merchant
479
- quotes or sessions do not become duplicate Haven approval requests.
494
+ `tools/call`, parse the 402 challenge, wait for the funding leg to confirm if
495
+ the payment is bridged, then resume with the same `payment_id` and retry the
496
+ original `tools/call` with `X-PAYMENT`. Use a stable `idempotencyKey` for the
497
+ user intent so fresh merchant quotes or sessions do not become duplicate Haven
498
+ payments.
480
499
 
481
500
  See [`examples/mcp-x402-sse.ts`](./examples/mcp-x402-sse.ts) for a complete
482
501
  MCP flow with initialize, `mcp-session-id`, JSON-RPC `tools/call`, quote
483
- inspection, user approval, saved resume state, and final retry.
502
+ inspection, saved resume state, and final retry.
484
503
 
485
504
  ## Error Handling
486
505