@haven_ai/sdk 0.1.21-alpha.0 → 0.1.23-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/dist/index.d.ts CHANGED
@@ -65,6 +65,11 @@ interface HavenClientConfig {
65
65
  x402Wallet?: string;
66
66
  /** Timeout in ms for individual HTTP requests (default: 30000) */
67
67
  requestTimeout?: number;
68
+ /** Timeout (ms) for MERCHANT-facing requests — x402/MPP probes, MCP
69
+ * handshakes, paid retries. Separate from requestTimeout (Haven API):
70
+ * merchants may settle on-chain synchronously, so the default is
71
+ * deliberately generous. #1300. */
72
+ merchantTimeout?: number;
68
73
  /** Timeout in ms when polling for tx confirmation (default: 90000) */
69
74
  confirmationTimeout?: number;
70
75
  /** Polling interval in ms when waiting for confirmation (default: 3000) */
@@ -257,6 +262,29 @@ interface X402Receipt {
257
262
  interface X402AuthorizationOptions {
258
263
  /** Stable caller-supplied key for this user intent. Prevents duplicate approvals across fresh 402 quotes. */
259
264
  idempotencyKey?: string;
265
+ /**
266
+ * #1307: the merchant MCP-tool call context this quote was made against
267
+ * (merchant_url, tool_name, arguments, mcp_transport). Persisted on the
268
+ * intent so `getX402MerchantCallContext` can rehydrate it by payment_id at
269
+ * settle/complete time instead of the caller re-threading it. Optional —
270
+ * omit for a non-MCP-tool x402 merchant (plain HTTP resource).
271
+ */
272
+ mcpCallContext?: X402McpCallContext;
273
+ /**
274
+ * #1348: the agent's delegate address, when the caller already resolved it
275
+ * from `getAgent()` in this same flow — skips `createX402Intent`'s internal
276
+ * agent fetch (one full round trip on every guided purchase). Staleness
277
+ * caveat (#1358 review): the backend derives the funding shape by comparing
278
+ * `payTo` to the CURRENT delegate address, so a value made stale by a
279
+ * delegate rotation mid-flow is not always a clean failure — a pinned-budget
280
+ * agent gets a 403, but an open-budget delegation agent would route to the
281
+ * settlement shape with the stale address. The window is one tool call
282
+ * (previously sub-millisecond, now the merchant-quote duration), never
283
+ * externally suppliable; server-truth hardening is tracked in #1360. Only
284
+ * pass an address fetched in THIS flow; omit to keep the self-contained
285
+ * fetch.
286
+ */
287
+ delegateAddress?: string;
260
288
  }
261
289
  /**
262
290
  * Keyless x402 construct result.
@@ -352,6 +380,30 @@ interface X402McpTransport {
352
380
  handshakeRequired: boolean;
353
381
  source: 'path' | 'bazaar';
354
382
  }
383
+ /**
384
+ * #1307: the merchant MCP-tool call an x402 quote was made against — carried
385
+ * through `createX402Intent`'s options so Haven can persist it for the
386
+ * settle-leg rehydration handoff (`getX402MerchantCallContext`). Convenience
387
+ * metadata for retrying the merchant's OWN JSON-RPC call, never payment
388
+ * authority.
389
+ */
390
+ interface X402McpCallContext {
391
+ merchantUrl: string;
392
+ toolName: string;
393
+ arguments?: Record<string, unknown>;
394
+ mcpTransport?: X402McpTransport;
395
+ }
396
+ /**
397
+ * Response shape of `getX402MerchantCallContext` — the stored merchant call
398
+ * context for a payment_id, rehydrated instead of re-threaded (#1307).
399
+ */
400
+ interface X402MerchantCallContext {
401
+ paymentId: string;
402
+ merchantUrl: string;
403
+ toolName: string;
404
+ arguments: Record<string, unknown>;
405
+ mcpTransport?: X402McpTransport;
406
+ }
355
407
  /** Quote parsed from an HTTP 402 response without creating a Haven payment. */
356
408
  interface X402Quote {
357
409
  rail: 'x402';
@@ -366,6 +418,16 @@ interface X402Quote {
366
418
  amountAtomic: string;
367
419
  amount: string;
368
420
  token: string;
421
+ /**
422
+ * #1351: decimals for `asset` on `network`, resolved from the SAME
423
+ * address→token binding that produced `token` — the quote's own authority on
424
+ * how many atomic units one human unit is. `null` when the merchant's asset
425
+ * is not a token Haven recognises on that network, in which case `token` is
426
+ * an unverified fallback label and NO human→atomic conversion is safe.
427
+ * Consumers converting a human-denominated figure (a user-intent spending
428
+ * cap) MUST fail closed on `null` rather than assume 6.
429
+ */
430
+ decimals: number | null;
369
431
  asset: string;
370
432
  network: string;
371
433
  chainId: number | null;
@@ -516,6 +578,14 @@ interface HavenAgent {
516
578
  safeAddress: string;
517
579
  delegateAddress: string;
518
580
  chainId: number;
581
+ /**
582
+ * Which on-chain policy primitive gates this agent's spend (#1306): the
583
+ * legacy Safe AllowanceModule (import-only accounts) or the delegation
584
+ * rail's active budget delegations (#1090). Read-only reporting — the
585
+ * on-chain state is the actual gate either way, this only says which
586
+ * mechanism a caller should read/derive from.
587
+ */
588
+ executionRail: 'legacy' | 'delegation';
519
589
  }
520
590
  interface HavenAllowance {
521
591
  id: string;
@@ -532,6 +602,15 @@ interface HavenAllowance {
532
602
  lastResetMin: number;
533
603
  nonce: number;
534
604
  isResetPending: boolean;
605
+ /**
606
+ * Delegation rail only (#1319, provenance for #1145's fallback): true
607
+ * when `remaining` came from a live on-chain enforcer read, false when
608
+ * the read failed and `remaining` is the fallback full configured
609
+ * budget. Undefined on the legacy AllowanceModule rail, which has no
610
+ * fallback concept. Reporting only — the on-chain policy remains the
611
+ * actual spend gate either way.
612
+ */
613
+ remainingIsFromChain?: boolean;
535
614
  };
536
615
  }
537
616
  interface HavenAllowanceSummary {
@@ -541,6 +620,34 @@ interface HavenAllowanceSummary {
541
620
  chainId: number;
542
621
  allowances: HavenAllowance[];
543
622
  }
623
+ /**
624
+ * Post-purchase allowance/budget summary attached to a settled x402 payment
625
+ * (#1310). Read-only reporting — the on-chain policy remains the actual
626
+ * spend gate either way, this only says what is left after the purchase.
627
+ *
628
+ * Deliberately the SAME rail-labeled field spelling as #1306's
629
+ * catalog-purchase preflight `allowance` block (never a new spelling),
630
+ * minus the preflight-only `sufficient` field: post-purchase reporting
631
+ * answers "what is left", not "was this purchase covered". Read through the
632
+ * exact same source as {@link HavenAllowanceSummary} / `haven_get_allowances`
633
+ * (`GET /machine-payments/allowances`; delegation-rail values are the #1090
634
+ * `deriveDelegationBudgets`-backed enforcer read, never `agent_allowances`),
635
+ * so this can never disagree with `haven_get_allowances` for the same
636
+ * fixture.
637
+ */
638
+ interface PostPurchaseAllowanceSummary {
639
+ /** Which on-chain policy primitive gates this agent's spend (#1306 labeling). */
640
+ rail: 'legacy' | 'delegation';
641
+ /** Remaining atomic units, read through the same source as {@link HavenAllowance.onchain.remaining}. */
642
+ remaining_atomic: string;
643
+ /** Human-readable remaining, e.g. "4.96 USDC". Omitted when the token's decimals are unknown. */
644
+ remaining_display?: string;
645
+ token_symbol?: string;
646
+ token_address?: string;
647
+ /** Minutes — mirrors {@link HavenAllowance.resetPeriodMin} / the delegation's period. */
648
+ reset_period?: number;
649
+ source: 'allowance_module' | 'active_delegations';
650
+ }
544
651
  /**
545
652
  * Affirmative spend-readiness for the authenticated agent, derived from the raw
546
653
  * agent status plus the remaining spend authority the backend reports per rail
@@ -701,6 +808,8 @@ declare const AgentPaymentNextAction: {
701
808
  readonly StopAndTellUser: "stop_and_tell_user";
702
809
  /** Ask again only if the user still wants the payment after expiry. */
703
810
  readonly RequestAgainIfUserStillWantsIt: "request_again_if_user_still_wants_it";
811
+ /** #1307: retry the SAME tool call, supplying the explicit context fields the server could not rehydrate. */
812
+ readonly RetryWithExplicitContext: "retry_with_explicit_context";
704
813
  /**
705
814
  * The x402 funding/quote window expired. Re-quote the same logical merchant
706
815
  * operation with the same idempotency key to stay double-charge-safe.
@@ -727,6 +836,36 @@ declare const AgentPaymentFailureCode: {
727
836
  readonly PaymentWindowExpired: "PAYMENT_WINDOW_EXPIRED";
728
837
  /** The Haven funding leg succeeded, but the merchant rejected the paid retry. */
729
838
  readonly MerchantRejectedAfterFunding: "MERCHANT_REJECTED_AFTER_FUNDING";
839
+ /** #1300 review: funding is on-chain but the merchant never ANSWERED the
840
+ * paid retry within the timeout. NOT proof of rejection — the merchant
841
+ * holds a valid EIP-3009 authorization and may still settle late, so the
842
+ * guidance is verify-then-sweep, never blind sweep. */
843
+ readonly MerchantUnresponsiveAfterFunding: "MERCHANT_UNRESPONSIVE_AFTER_FUNDING";
844
+ /**
845
+ * #1307: the caller omitted merchant_url/tool_name (asking Haven to
846
+ * rehydrate the stored MCP merchant-call context by payment_id), but no
847
+ * usable context was stored for this intent — either it was never an
848
+ * MCP-tool quote, or the stored context is incomplete. The fallback is
849
+ * mechanical: re-send merchant_url, tool_name, arguments, and
850
+ * mcp_transport explicitly (the version-skew path).
851
+ */
852
+ readonly MerchantCallContextUnavailable: "MERCHANT_CALL_CONTEXT_UNAVAILABLE";
853
+ /**
854
+ * #1351: the caller supplied BOTH the atomic `max_amount` and the
855
+ * human-denominated `max_amount_human` cap for one purchase. Haven refuses
856
+ * to guess which the user meant — the two differ by a factor of 10^decimals,
857
+ * so picking wrong is exactly the silent-overspend this cap exists to
858
+ * prevent. Rejected before any merchant probe, funding intent, or signature.
859
+ */
860
+ readonly AmbiguousMaxAmount: "AMBIGUOUS_MAX_AMOUNT";
861
+ /**
862
+ * #1351: a human-denominated cap was supplied, but it cannot be converted to
863
+ * atomic units against THIS quote — either the quote's asset has no known
864
+ * decimals on its network, or the cap carries more fraction digits than the
865
+ * asset can represent (truncating it would silently change the user's cap).
866
+ * The fallback is the exact atomic `max_amount`.
867
+ */
868
+ readonly MaxAmountUnconvertible: "MAX_AMOUNT_UNCONVERTIBLE";
730
869
  };
731
870
  type AgentPaymentFailureCode = (typeof AgentPaymentFailureCode)[keyof typeof AgentPaymentFailureCode];
732
871
  /**
@@ -767,12 +906,117 @@ type AgentPaymentRail = (typeof AgentPaymentRail)[keyof typeof AgentPaymentRail]
767
906
  type PaymentPhase = AgentPaymentPhase;
768
907
  type PaymentNextAction = AgentPaymentNextAction;
769
908
  declare const AGENT_PAYMENT_PHASE_VALUES: ("rejected" | "expired" | "failed" | "agent_signature_required" | "payment_submitted" | "payment_confirmed" | "user_approval_required" | "user_execution_required" | "waiting_for_additional_approvals" | "funding_sent" | "insufficient_funds" | "funded_but_unsettled")[];
770
- declare const AGENT_PAYMENT_NEXT_ACTION_VALUES: ("sign_and_submit_payment" | "check_status_later" | "none" | "wait_for_user_approval" | "wait_for_user_to_complete_payment" | "retry_original_x402_request" | "stop_and_tell_user" | "request_again_if_user_still_wants_it" | "payment_window_expired" | "fund_safe_or_raise_allowance" | "sweep_stranded_funds")[];
771
- declare const AGENT_PAYMENT_FAILURE_CODE_VALUES: ("PRICE_EXCEEDS_MAX" | "PAYMENT_WINDOW_EXPIRED" | "MERCHANT_REJECTED_AFTER_FUNDING")[];
909
+ declare const AGENT_PAYMENT_NEXT_ACTION_VALUES: ("sign_and_submit_payment" | "check_status_later" | "none" | "wait_for_user_approval" | "wait_for_user_to_complete_payment" | "retry_original_x402_request" | "stop_and_tell_user" | "request_again_if_user_still_wants_it" | "retry_with_explicit_context" | "payment_window_expired" | "fund_safe_or_raise_allowance" | "sweep_stranded_funds")[];
910
+ declare const AGENT_PAYMENT_FAILURE_CODE_VALUES: ("PRICE_EXCEEDS_MAX" | "PAYMENT_WINDOW_EXPIRED" | "MERCHANT_REJECTED_AFTER_FUNDING" | "MERCHANT_UNRESPONSIVE_AFTER_FUNDING" | "MERCHANT_CALL_CONTEXT_UNAVAILABLE" | "AMBIGUOUS_MAX_AMOUNT" | "MAX_AMOUNT_UNCONVERTIBLE")[];
772
911
  declare const AGENT_PAYMENT_RAIL_VALUES: ("x402" | "mpp" | "mpp_demo" | "mpp_crypto" | "stripe_deposit" | "spt" | "direct")[];
773
912
  declare const AgentPaymentPhaseDescriptions: Record<AgentPaymentPhase, string>;
774
913
  declare const AgentPaymentNextActionDescriptions: Record<AgentPaymentNextAction, string>;
775
914
  declare const AgentPaymentFailureCodeDescriptions: Record<AgentPaymentFailureCode, string>;
915
+ /**
916
+ * #1308: machine-readable warning codes carried in the `warnings` array on
917
+ * x402 MCP tool responses. Warnings are ADVISORY — they never replace a
918
+ * refusal, and existing failure codes stay authoritative for errors. The
919
+ * legacy `cap_warning` string field is kept for compatibility; the structured
920
+ * entry carries the same message under MISSING_MAX_AMOUNT.
921
+ */
922
+ declare const AgentPaymentWarningCode: {
923
+ /** No max_amount cap was supplied — the live quoted price was accepted as-is. */
924
+ readonly MissingMaxAmount: "MISSING_MAX_AMOUNT";
925
+ /** The signing window closes soon; sign promptly or re-quote with the same idempotency key. */
926
+ readonly QuoteExpiresSoon: "QUOTE_EXPIRES_SOON";
927
+ /** The merchant URL was resolved via discovery — pass the RESOLVED url forward. */
928
+ readonly MerchantUrlDiscovered: "MERCHANT_URL_DISCOVERED";
929
+ /**
930
+ * #1306: the catalog's last-verified price_atomic differs from the LIVE
931
+ * merchant quote for a guided catalog purchase. The catalog price is only
932
+ * ever indicative; the live quote in the same response is authoritative.
933
+ */
934
+ readonly CatalogPriceDiffers: "CATALOG_PRICE_DIFFERS";
935
+ /**
936
+ * #1306: the rail-aware allowance/budget pre-check could not be read (RPC
937
+ * failure, etc). `sufficient` is reported as null rather than a fabricated
938
+ * true/false — the on-chain policy remains the actual gate either way.
939
+ */
940
+ readonly AllowanceCheckUnavailable: "ALLOWANCE_CHECK_UNAVAILABLE";
941
+ /**
942
+ * #1319: the delegation-rail read itself SUCCEEDED, but the remaining
943
+ * figure it returned is the #1145 fallback (the full configured budget)
944
+ * rather than a live ERC20PeriodTransferEnforcer read — `sufficient` is a
945
+ * real true/false, just computed from an optimistic number. Distinct from
946
+ * {@link AgentPaymentWarningCode.AllowanceCheckUnavailable}, which fires
947
+ * when the read failed outright and `sufficient` degrades to null. The
948
+ * on-chain policy re-checks at redemption either way; this only says the
949
+ * guidance shown here may be optimistic.
950
+ */
951
+ readonly AllowanceReadOptimistic: "ALLOWANCE_READ_OPTIMISTIC";
952
+ };
953
+ type AgentPaymentWarningCode = (typeof AgentPaymentWarningCode)[keyof typeof AgentPaymentWarningCode];
954
+ interface AgentPaymentWarning {
955
+ code: AgentPaymentWarningCode;
956
+ message: string;
957
+ }
958
+ /**
959
+ * #1308: the structured next-step contract on x402 MCP tool responses. It
960
+ * EXTENDS the existing taxonomy — `next_action` values come from
961
+ * AgentPaymentNextAction, never a parallel vocabulary. `next_arguments`
962
+ * carries the small, literally-usable arguments; bulky pass-through fields
963
+ * (payment_required) are named in `reason` and taken from the SAME response.
964
+ */
965
+ interface AgentNextStep {
966
+ next_action: AgentPaymentNextAction;
967
+ /** Fully-qualified tool name for the next call, when one exists. */
968
+ next_tool?: string;
969
+ /** Small literal arguments for next_tool. Bulky fields are referenced by reason. */
970
+ next_arguments?: Record<string, unknown>;
971
+ /** False when the agent should stop and involve the user before continuing. */
972
+ safe_to_continue: boolean;
973
+ reason: string;
974
+ }
975
+ /**
976
+ * #1349: compact, Haven-generated reporting evidence for a completed x402
977
+ * merchant purchase. `status`, money fields, merchant endpoint/address, and
978
+ * funding transaction come from Haven payment state; `product` and
979
+ * `invoice_id` are optional merchant-supplied display metadata. The raw
980
+ * merchant result remains separate evidence and MUST NOT be used to infer
981
+ * settlement status.
982
+ */
983
+ interface AgentPurchaseSummary {
984
+ /** Set only after Haven has completed the funding and merchant-settlement flow. */
985
+ status: 'settled';
986
+ product: string | null;
987
+ amount: string | null;
988
+ amount_atomic: string | null;
989
+ asset: string | null;
990
+ network: string | null;
991
+ merchant: {
992
+ address: string | null;
993
+ resource_url: string | null;
994
+ };
995
+ /** Merchant-supplied identifier, or null when the merchant did not supply one. */
996
+ invoice_id: string | null;
997
+ funding_tx_hash: string | null;
998
+ /** Optional merchant receipt reference parsed from PAYMENT-RESPONSE; not Haven settlement proof. */
999
+ settlement_tx_hash: string | null;
1000
+ /** Same read-only allowance block returned at the top level, or null when unavailable. */
1001
+ allowance: PostPurchaseAllowanceSummary | null;
1002
+ }
1003
+ /** #1308: compact reporting summary — what the agent tells the user. */
1004
+ interface AgentPaymentSummary {
1005
+ payment_id: string;
1006
+ status: string;
1007
+ amount?: string;
1008
+ amount_atomic?: string;
1009
+ token?: string;
1010
+ network?: string;
1011
+ expires_at?: string;
1012
+ product?: string;
1013
+ /**
1014
+ * Default reporting contract for a successful `haven_settle_mcp_tool` call.
1015
+ * The merchant's raw `result` remains available separately as advanced
1016
+ * evidence; do not parse it to determine whether a payment settled.
1017
+ */
1018
+ purchase_summary?: AgentPurchaseSummary;
1019
+ }
776
1020
  declare const AgentPaymentRailDescriptions: Record<AgentPaymentRail, string>;
777
1021
  declare const AgentPaymentPhaseSchema: AgentPaymentEnumSchema;
778
1022
  declare const AgentPaymentNextActionSchema: AgentPaymentEnumSchema;
@@ -839,6 +1083,7 @@ interface HavenCatalogEntry {
839
1083
  rail: 'x402' | 'mpp';
840
1084
  protocol: 'http' | 'mcp';
841
1085
  toolName: string | null;
1086
+ toolArguments: Record<string, unknown> | null;
842
1087
  priceDisplay: string | null;
843
1088
  priceAtomic: string | null;
844
1089
  asset: string | null;
@@ -856,6 +1101,26 @@ declare class HavenApiError extends HavenError {
856
1101
  readonly body?: unknown | undefined;
857
1102
  constructor(message: string, statusCode: number, body?: unknown | undefined, paymentId?: string);
858
1103
  }
1104
+ /**
1105
+ * #1300: quoteX402 hit a URL that answered something other than 402 — the
1106
+ * typed form of "this is not the x402 endpoint". Exists so consumers (the
1107
+ * hosted MCP's #1271 discovery trigger) can key on a class instead of
1108
+ * message text.
1109
+ */
1110
+ /**
1111
+ * #1300: a merchant-facing fetch hit the client-side merchantTimeout. Typed
1112
+ * so consumers can distinguish "merchant never answered" from a real HTTP
1113
+ * error response — the funded-retry path routes this to verify-then-sweep
1114
+ * guidance instead of a bare 504.
1115
+ */
1116
+ declare class MerchantTimeoutError extends HavenApiError {
1117
+ readonly merchantErrorCode: "merchant_timeout";
1118
+ constructor(message: string);
1119
+ }
1120
+ declare class X402UnexpectedStatusError extends HavenApiError {
1121
+ readonly x402ErrorCode: "unexpected_non_402_status";
1122
+ constructor(message: string, statusCode: number);
1123
+ }
859
1124
  declare class HavenPaymentStateError extends HavenApiError {
860
1125
  readonly state: PaymentStatusResult;
861
1126
  resumeState?: X402ResumeState | MppResumeState;
@@ -867,6 +1132,53 @@ declare class HavenPaymentStateError extends HavenApiError {
867
1132
  declare class HavenSigningError extends HavenError {
868
1133
  constructor(message: string);
869
1134
  }
1135
+ /**
1136
+ * Refusal codes the local signer returns when it does not recognise the
1137
+ * VERSION of a Haven-signed binding it was asked to sign (#1309). Distinct
1138
+ * from `AgentPaymentFailureCode`: these describe a **signer capability**
1139
+ * problem (this install cannot evaluate what Haven sent), not a payment-domain
1140
+ * outcome, and they never reach the backend's REST/OpenAPI surface — only the
1141
+ * local signer's own MCP tool responses (`haven_sign` / `haven_sign_x402` /
1142
+ * `haven_sign_sweep_delegate`). That is also why this pair does not go through
1143
+ * the `AgentPaymentFailureCode` four-gate (sdk → backend mirror → spec →
1144
+ * api-types): there is no backend mirror to keep in sync with.
1145
+ */
1146
+ declare const SignerRefusalCode: {
1147
+ /** `SUPPORTED_X402_EXPECTED_VERSIONS` in `@haven_ai/signer` does not include the received version. */
1148
+ readonly UnsupportedExpectedContextVersion: "UNSUPPORTED_EXPECTED_CONTEXT_VERSION";
1149
+ /** `SUPPORTED_SWEEP_BINDING_VERSIONS` in `@haven_ai/signer` does not include the received version. */
1150
+ readonly UnsupportedSweepBindingVersion: "UNSUPPORTED_SWEEP_BINDING_VERSION";
1151
+ };
1152
+ type SignerRefusalCode = (typeof SignerRefusalCode)[keyof typeof SignerRefusalCode];
1153
+ /**
1154
+ * Canonical recovery guidance for a stale local signer (#1309) — the ONE
1155
+ * string both the signer's structured refusal (`fallback` field, carried by
1156
+ * `HavenUnsupportedSignerVersionError`) and the hosted quote's advisory
1157
+ * `signer_compatibility.fallback` (#1155) render, so an agent that meets
1158
+ * either surface is told the identical fix. A second hand-maintained copy of
1159
+ * this sentence is exactly how the two surfaces could start disagreeing about
1160
+ * what to do.
1161
+ */
1162
+ declare const SIGNER_UPDATE_FALLBACK: string;
1163
+ /**
1164
+ * Thrown by the local signer when a Haven-signed binding (x402 expected
1165
+ * context or sweep authorization) carries a version outside what this signer
1166
+ * install enforces (#1143, structured as #1309). Machine-readable: `code`,
1167
+ * `supportedVersions`, and `receivedVersion` are DERIVED from the signer's own
1168
+ * `SUPPORTED_X402_EXPECTED_VERSIONS` / `SUPPORTED_SWEEP_BINDING_VERSIONS`
1169
+ * constants at the throw site, never a second literal — see
1170
+ * `assertSupportedBindingVersion` in `@haven_ai/signer`.
1171
+ *
1172
+ * This narrows HOW the refusal is reported. It does not weaken it: nothing is
1173
+ * signed either way, and the version stays inside the Haven-signed binding
1174
+ * message (callers must not "fix" a mismatch by rewriting it).
1175
+ */
1176
+ declare class HavenUnsupportedSignerVersionError extends HavenError {
1177
+ readonly supportedVersions: readonly number[];
1178
+ readonly receivedVersion: number;
1179
+ readonly fallback: string;
1180
+ constructor(message: string, code: SignerRefusalCode, supportedVersions: readonly number[], receivedVersion: number, fallback: string);
1181
+ }
870
1182
  declare class HavenTimeoutError extends HavenError {
871
1183
  constructor(paymentId: string);
872
1184
  }
@@ -1057,6 +1369,7 @@ declare class HavenClient {
1057
1369
  private readonly baseUrl;
1058
1370
  private readonly x402Wallet;
1059
1371
  private readonly requestTimeout;
1372
+ private readonly merchantTimeout;
1060
1373
  private readonly confirmationTimeout;
1061
1374
  private readonly pollingInterval;
1062
1375
  private readonly chainRpcs;
@@ -1170,6 +1483,8 @@ declare class HavenClient {
1170
1483
  * Get the agent identity tied to this API key.
1171
1484
  */
1172
1485
  getAgent(): Promise<HavenAgent>;
1486
+ private agentInFlight;
1487
+ private fetchAgent;
1173
1488
  /**
1174
1489
  * One-shot "am I ready?" bootstrap: identity + live spend authority + a
1175
1490
  * readiness signal, in a single call. Folds {@link getAgent} and
@@ -1209,6 +1524,58 @@ declare class HavenClient {
1209
1524
  * Get configured and on-chain allowances for the authenticated agent.
1210
1525
  */
1211
1526
  getAllowances(): Promise<HavenAllowanceSummary>;
1527
+ /**
1528
+ * Post-purchase allowance/budget summary for a settled payment (#1310).
1529
+ *
1530
+ * Reuses the EXACT rail-aware read path {@link getAllowances} / #1306's
1531
+ * catalog-purchase preflight `allowance` block use — `GET
1532
+ * /machine-payments/allowances`, with delegation-rail values coming from
1533
+ * the #1090 `deriveDelegationBudgets`-backed enforcer read, never
1534
+ * `agent_allowances` — so this can never disagree with
1535
+ * {@link getAllowances} for the same fixture. The settled token is
1536
+ * resolved from {@link getPaymentStatus} so callers pass only
1537
+ * `paymentId`, never a second haven_get_agent-style round trip.
1538
+ *
1539
+ * NEVER throws: any failed read (status lookup, agent lookup, or the
1540
+ * allowance/budget lookup itself) degrades to `{ allowance: null,
1541
+ * warnings: [ALLOWANCE_CHECK_UNAVAILABLE] }` rather than converting a
1542
+ * successful settlement into a failure — the on-chain policy remains the
1543
+ * actual spend gate regardless of whether this report can be produced.
1544
+ *
1545
+ * Freshness caveat (#1319): the delegation rail's on-chain enforcer read
1546
+ * can silently fall back to the optimistic full period budget without
1547
+ * throwing when the RPC read itself fails (#1145's fund-safe design,
1548
+ * unchanged here). {@link getAllowances}'s `onchain.remainingIsFromChain`
1549
+ * now carries that provenance on the wire, and the #1306 catalog-purchase
1550
+ * preflight (`haven_prepare_catalog_purchase`) surfaces it as a warning —
1551
+ * this summary does not (yet). `remaining_atomic` here reflects the last
1552
+ * successful chain read, not a guaranteed-live one, and callers should not
1553
+ * phrase it as guaranteed-fresh.
1554
+ */
1555
+ getPostPurchaseAllowanceSummary(paymentId: string): Promise<{
1556
+ allowance: PostPurchaseAllowanceSummary | null;
1557
+ warnings: AgentPaymentWarning[];
1558
+ /** Same authenticated payment-state read used to resolve the settled token. */
1559
+ payment: PaymentStatusResult | null;
1560
+ }>;
1561
+ /**
1562
+ * `haven_get_payment_status` convenience: fetch status and, for a
1563
+ * genuinely SETTLED x402 payment, attach the same post-purchase
1564
+ * allowance/budget summary a settle response carries.
1565
+ *
1566
+ * #1310/#1311 parity: this is the ONE home for logic that was duplicated
1567
+ * verbatim in `packages/mcp-server/src/tools.ts` and `packages/mcp/src/tools.ts`
1568
+ * (both hosted and local `haven_get_payment_status` handlers) — extracted
1569
+ * here because both packages already depend on `@haven_ai/sdk` and call
1570
+ * methods on a `HavenClient` instance, so this needed no new dependency
1571
+ * edge. `funded_but_unsettled` is deliberately excluded: that phase means
1572
+ * the merchant did NOT accept the retry. Every other phase/rail returns
1573
+ * the status untouched.
1574
+ */
1575
+ getPaymentStatusWithPostPurchaseAllowance(paymentId: string): Promise<PaymentStatusResult & {
1576
+ allowance?: PostPurchaseAllowanceSummary | null;
1577
+ warnings?: AgentPaymentWarning[];
1578
+ }>;
1212
1579
  /**
1213
1580
  * Discover payable services from Haven's curated merchant catalog.
1214
1581
  *
@@ -1218,8 +1585,19 @@ declare class HavenClient {
1218
1585
  */
1219
1586
  discoverTools(options?: {
1220
1587
  category?: string;
1588
+ search?: string;
1221
1589
  rail?: 'x402' | 'mpp';
1222
1590
  }): Promise<HavenCatalogEntry[]>;
1591
+ /**
1592
+ * Fetch one curated catalog entry by id (#1306).
1593
+ *
1594
+ * Chain-scoped for free by the backend's SQL when the client is
1595
+ * agent-authenticated (#1299): an unknown id and an id curated for a
1596
+ * DIFFERENT chain than this agent's both 404 identically — this method does
1597
+ * not (and must not) re-filter by chain in JS. Read-only, like
1598
+ * {@link discoverTools}.
1599
+ */
1600
+ getCatalogEntry(id: string): Promise<HavenCatalogEntry>;
1223
1601
  /**
1224
1602
  * List recent machine-payment receipts/evidence for bookkeeping.
1225
1603
  */
@@ -1262,6 +1640,17 @@ declare class HavenClient {
1262
1640
  * payment or approval request.
1263
1641
  */
1264
1642
  quoteX402(url: string, init?: RequestInit, options?: X402AuthorizationOptions): Promise<X402Quote>;
1643
+ /**
1644
+ * Probe an MCP tool for its x402 quote without creating a payment.
1645
+ *
1646
+ * Unlike the generic {@link quoteX402} helper, this completes the
1647
+ * Streamable-HTTP MCP lifecycle before sending the unpaid `tools/call`.
1648
+ * Hosted MCP uses this path while remaining keyless: it resolves only the
1649
+ * agent's public delegate address for `x402-wallet`; signing remains local.
1650
+ * It refuses before the quote when the merchant does not establish a session;
1651
+ * callers that need a plain x402 endpoint must use {@link quoteX402}.
1652
+ */
1653
+ quoteMcpX402(url: string, init?: RequestInit, options?: X402AuthorizationOptions): Promise<X402Quote>;
1265
1654
  /**
1266
1655
  * Pay a previously inspected x402 quote and retry the exact captured request.
1267
1656
  */
@@ -1382,6 +1771,17 @@ declare class HavenClient {
1382
1771
  body: unknown;
1383
1772
  settlementTxHash?: string;
1384
1773
  }>;
1774
+ /**
1775
+ * GET /x402/:id/merchant-call-context — the settle-leg twin of #1263's
1776
+ * sign-context fetch (#1307). Re-serves the stored merchant MCP-tool call
1777
+ * context (merchant_url, tool_name, arguments, mcp_transport) recorded at
1778
+ * quote time, so `haven_settle_mcp_tool` / `haven_complete_mcp_tool` can
1779
+ * omit those fields and let Haven rehydrate them by payment_id instead of
1780
+ * the caller re-threading them. Throws `HavenApiError` (404 unknown/foreign
1781
+ * payment_id, 409 no stored context, 410 expired) — the caller decides the
1782
+ * fallback (re-send the full context explicitly).
1783
+ */
1784
+ getX402MerchantCallContext(paymentId: string): Promise<X402MerchantCallContext>;
1385
1785
  private resolveX402MerchantCompletionContext;
1386
1786
  private resolveX402WalletForMerchantCall;
1387
1787
  authorizeMachinePayment(challenge: MachinePaymentChallenge, options?: MppAuthorizationOptions): Promise<MachinePaymentReceipt>;
@@ -1445,6 +1845,15 @@ declare class HavenClient {
1445
1845
  private toolError;
1446
1846
  private post;
1447
1847
  private get;
1848
+ /**
1849
+ * #1300: every MERCHANT-facing fetch goes through here. Haven API calls
1850
+ * have always been bounded (request() below); the merchant probes/retries
1851
+ * called globalThis.fetch bare, so a slow-loris merchant could hold a tool
1852
+ * call open forever. A caller-supplied signal still applies (combined via
1853
+ * AbortSignal.any); a timeout abort surfaces as a clear HavenApiError 504
1854
+ * naming the URL rather than a bare AbortError.
1855
+ */
1856
+ private merchantFetch;
1448
1857
  private request;
1449
1858
  private mapPaymentResult;
1450
1859
  private mapPaymentStatusResult;
@@ -1649,16 +2058,16 @@ declare const toolDescriptions: {
1649
2058
  readonly nextActionGuidance: "";
1650
2059
  };
1651
2060
  readonly payMcpTool: {
1652
- readonly summary: "Call a named tool on an MCP merchant that requires an x402 payment, handling the full initialize → pay → retry round trip.";
2061
+ readonly summary: "Call a named tool on an MCP merchant that requires an x402 payment, handling the full initialize → pay → retry round trip in one call.";
1653
2062
  readonly selectionGuidance: string;
1654
2063
  readonly behavior: string;
1655
2064
  readonly nextActionGuidance: string;
1656
2065
  };
1657
2066
  readonly discoverTools: {
1658
- readonly summary: "Discover payable services from Haven's curated merchant catalog — names, prices, and which pay tool to use.";
2067
+ readonly summary: "Step 1 of a purchase: discover payable services from Haven's curated merchant catalog — names, prices, and which pay tool to use next.";
1659
2068
  readonly selectionGuidance: string;
1660
2069
  readonly behavior: string;
1661
- readonly nextActionGuidance: "Pick an entry and pay it with the tool named in suggested_tool, passing the entry's resource_url (and tool_name for MCP merchants). Confirm the price from the live pay-tool result (not the catalog), and pass max_amount when the user has a cap.";
2070
+ readonly nextActionGuidance: "Pick an entry and pay it with the tool named in suggested_tool, passing the entry's resource_url, tool_name, and tool_arguments for MCP merchants. Confirm the price from the live pay-tool result (not the catalog), and pass the user's cap as max_amount_human in whole tokens (\"no more than 1 USDC\" → max_amount_human: \"1\") — never convert it to atomic units by hand (#1351).";
1662
2071
  };
1663
2072
  readonly sweep_delegate: {
1664
2073
  readonly summary: "Sweep stranded USDC and/or ETH from the delegate wallet back to the originating Safe.";
@@ -1694,7 +2103,7 @@ type SharedToolKey = keyof typeof toolDescriptions;
1694
2103
  * this canonical string and asserts byte-for-byte equality, so the two copies
1695
2104
  * cannot drift.
1696
2105
  */
1697
- declare const HAVEN_SKILL_MD = "---\nname: haven-pay\ndescription: Pay for things from the user's Haven wallet within their agent rules. Use when the user asks to send, pay, tip, or transfer crypto \u2014 or when a request hits an HTTP 402 (x402) paywall.\n---\n\n# Haven: pay from a Haven wallet\n\nThis skill lets the agent make payments from the user's Haven wallet through\nthe Haven MCP tools. Every payment is checked against the agent's on-chain\nbudget before money moves; payments above the remaining budget wait for the\nuser's approval in Haven.\n\nHosted tools run in the `mcp__haven__` namespace. Local signing tools run in\nthe `mcp__haven-signer__` namespace and keep the delegate key on this machine.\n\n## When to use this skill\n\n- The user asks to send money, pay someone, tip, donate, or transfer tokens.\n- A request returns HTTP 402 (x402): use the Haven pay tools to settle it,\n then retry the original request.\n\n## Identity and budget\n\nDo not guess the wallet address, network, or budget.\n\nFor instant orientation at the start of a session, read the non-secret\n`agent.json` the connector wrote to your Haven credential directory (typically\n`~/.haven/agents/<agent-id>/agent.json` \u2014 if you don't know the agent id, list\n`~/.haven/agents/` to find the folder). It\nholds your agent id, Haven wallet address, network, and *configured* per-token\nbudget, and contains no keys \u2014 the fastest way to answer \"who am I and what may\nI spend\" with no round trip. If that file is absent (some setups don't write\nit), use the tools below instead.\n\nBefore any payment, confirm the *live remaining* budget with the tools \u2014\n`agent.json` shows the configured budget, not what is left after recent\nspending:\n\n- `haven_get_agent` \u2014 the recommended first call: identity (wallet, network)\n plus a readiness signal (`ready` / `needs_approval` / `revoked`) and live\n remaining per-token allowance, in one shot.\n- `haven_get_allowances` \u2014 detailed per-token breakdown (configured, spent,\n reset window) when you need more than the summary.\n\nBudgets reset on a period the user chose. If a payment exceeds the remaining\nbudget it is queued for the user to approve in the Haven dashboard \u2014 this is\nnormal, not an error.\n\n## Paying\n\n- **Direct transfer:** `haven_pay` with recipient, amount, and token.\n- **x402 paywall:** `haven_quote_x402` to get a quote, then\n `haven_pay_x402_quote`. In the hosted setup the signing step happens in\n the local Haven signer; follow the tool results \u2014 they tell you the next\n action at every step. Retry the original request only when the result says\n `retry_original_x402_request`.\n- **Paid MCP tool call:** `mcp__haven__haven_pay_mcp_tool` with the merchant\n URL, tool name, and arguments, then finish in two calls (fast path):\n `mcp__haven-signer__haven_sign_x402` on the local signer (pass\n `payload_hash`, `x402_expected` as the nested `x402.expected` object, and\n `payment_required`) returns `{ signature, payment_header }`; then\n `mcp__haven__haven_settle_mcp_tool` (pass `payment_id`, `signature`,\n `payment_header`, `merchant_url`, `tool_name`, `arguments`,\n `mcp_transport`) funds and settles in one step and returns the tool result.\n If it returns `settled: false`, funding is queued for the user's approval \u2014\n tell them and check status later, do not re-pay. Step-by-step alternative:\n `mcp__haven-signer__haven_sign` \u2192 `mcp__haven__haven_submit` \u2192\n `mcp__haven-signer__haven_x402_sign_header` \u2192\n `mcp__haven__haven_complete_mcp_tool`. Pass `payment_required`,\n `arguments`, and `mcp_transport` verbatim from the\n `mcp__haven__haven_pay_mcp_tool` result. The returned `expires_at` is the\n signing window; if a tool returns `PAYMENT_WINDOW_EXPIRED`, re-run\n `mcp__haven__haven_pay_mcp_tool` with the same\n `idempotency_key`. Do not call the merchant yourself \u2014 Haven completes the\n merchant leg for you.\n- **Prices:** show the user the live price from the pay-tool result, never a\n catalog price. `haven_discover_tools` prices are indicative\n (`price_is_indicative`) and can be stale. The pay-tool result's `amount` /\n `amount_atomic` is the amount Haven authorizes for the call \u2014 a ceiling the\n merchant settles at or below \u2014 so present it as the most the user will pay.\n Pass `max_amount` (atomic units) to `haven_pay_mcp_tool` /\n `haven_pay_x402_quote` to reject a quote whose authorized amount is above the\n user's cap, before any funds move.\n- **Status:** `haven_get_payment_status` with a `payment_id` to check on\n queued or in-flight payments. Do not poll in a tight loop.\n\n## Approval semantics\n\n- A result with `pending_approval` means the payment exceeded the remaining\n budget and is waiting for the user in Haven. Tell the user, then check\n status later.\n- Never ask the user for private keys. Signing happens only in the local Haven\n signer; the hosted Haven tools never receive the signing key. If a tool\n reports a missing or invalid credential, tell the user to re-run the Haven\n setup command.\n\n## Failure handling\n\nHaven tool failures are shaped like `{ success: false, code, message, ... }`\nor older `{ error, status, details? }` responses. Branch on `code` when\npresent and surface `message` or `error` verbatim. Common cases:\n\n- `pending_approval`: queued for the user's approval (see above).\n- `insufficient_funds`: the Haven wallet doesn't hold enough of that token.\n Suggest the user add funds in the Haven dashboard.\n- `PRICE_EXCEEDS_MAX`: the live merchant price exceeded your `max_amount`.\n No funds moved; ask the user before retrying with a higher cap.\n- `PAYMENT_WINDOW_EXPIRED`: re-run `mcp__haven__haven_pay_mcp_tool` with the same\n `idempotency_key`, then sign the fresh `payload_hash`.\n- `MERCHANT_REJECTED_AFTER_FUNDING`: stop retrying the merchant and use\n `mcp__haven__haven_sweep_delegate` to recover stranded delegate funds.\n- Budget exceeded: tell the user how much remains (from\n `haven_get_allowances`) and that they can raise the budget in Haven.\n\n## Revoke\n\nIf this agent's credential may have leaked, tell the user to pause or revoke\nthe agent in the Haven dashboard under Agents. New requests stop immediately\nfor that credential.\n";
2106
+ declare const HAVEN_SKILL_MD = "---\nname: haven-pay\ndescription: Pay for things from the user's Haven wallet within their agent rules. Use when the user asks to send, pay, tip, or transfer crypto \u2014 or when a request hits an HTTP 402 (x402) paywall.\n---\n\n# Haven: pay from a Haven wallet\n\nThis skill lets the agent make payments from the user's Haven wallet through\nthe Haven MCP tools. Every payment is checked against the agent's on-chain\nbudget before money moves; payments above the remaining budget wait for the\nuser's approval in Haven.\n\nHosted tools run in the `mcp__haven__` namespace. Local signing tools run in\nthe `mcp__haven-signer__` namespace and keep the delegate key on this machine.\nTool results carry the exact next step (`next_action`, `next_tool`,\n`next_arguments`) \u2014 follow those fields first; the prose below is fallback\nand orientation, not the source of truth.\n\n## When to use this skill\n\n- The user asks to send money, pay someone, tip, donate, or transfer tokens.\n- A request returns HTTP 402 (x402): use the Haven pay tools to settle it,\n then retry the original request.\n\n## Identity and budget\n\nDo not guess the wallet address, network, or budget.\n\nFor instant orientation at the start of a session, read the non-secret\n`agent.json` the connector wrote to your Haven credential directory (typically\n`~/.haven/agents/<agent-id>/agent.json` \u2014 if you don't know the agent id, list\n`~/.haven/agents/` to find the folder). It\nholds your agent id, Haven wallet address, network, and *configured* per-token\nbudget, and contains no keys \u2014 the fastest way to answer \"who am I and what may\nI spend\" with no round trip. If that file is absent (some setups don't write\nit), use the tools below instead.\n\nBefore any payment, confirm the *live remaining* budget with the tools \u2014\n`agent.json` shows the configured budget, not what is left after recent\nspending:\n\n- `mcp__haven__haven_get_agent` \u2014 the recommended first call: identity\n (wallet, network) plus a readiness signal (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot.\n- `mcp__haven__haven_get_allowances` \u2014 detailed per-token breakdown\n (configured, spent, reset window) when you need more than the summary.\n\nBudgets reset on a period the user chose. If a payment exceeds the remaining\nbudget it is queued for the user to approve in the Haven dashboard \u2014 this is\nnormal, not an error.\n\n## Paying\n\n**Catalog purchases \u2014 the primary path for MCP merchants:**\n\n1. `mcp__haven__haven_discover_tools` to find a payable service and its\n `catalog_id`.\n2. `mcp__haven__haven_prepare_catalog_purchase` with `catalog_id` and a\n spending cap. A cap is REQUIRED on this tool and is best practice on every\n paid call below too \u2014 it caps what the LIVE merchant quote may charge,\n checked before any funding intent is created. Write it the way the user\n said it: `max_amount_human` is whole tokens, so \"no more than 1 USDC\" is\n `max_amount_human: \"1\"`. (`max_amount` is the atomic-unit form, where\n \"1\" means 0.000001 USDC \u2014 do not convert by hand, and never send both.)\n3. Then FOLLOW THE RESPONSE'S GUIDANCE FIELDS: `next_action`, `next_tool`,\n and `next_arguments` name the exact next call \u2014 act on those first; the\n prose in this section is fallback and debugging detail. If the catalog\n entry is missing or degraded, the response instead names\n `mcp__haven__haven_pay_mcp_tool` (merchant URL, tool name, arguments) as\n the manual fallback.\n\n**Signing:** `mcp__haven-signer__haven_sign_x402` with `payment_id` ONLY \u2014\nthe local signer fetches the exact signing bytes AND `payment_required`\nitself, so never relay `typed_data` or the 402 blob yourself. If the signer\nreports its fetched context carried no `payment_required` (older backend),\nre-call with `payment_required` added verbatim. Fallback for an older signer\nor backend: re-run the quote/prepare tool with the SAME `idempotency_key`\nplus `include_signing_payload=true`, then pass `payload_hash`,\n`x402_expected` (the nested `x402.expected` object), and\n`typed_data`/`typed_data_b64` through unchanged.\n\n**Settle:** `mcp__haven__haven_settle_mcp_tool` with `payment_id`,\n`signature`, and `payment_header` ONLY \u2014 Haven rehydrates the merchant call\ncontext (`merchant_url`, `tool_name`, `arguments`, `mcp_transport`)\nserver-side from `payment_id`. Pass those four fields explicitly only as a\nversion-skew fallback when Haven has no stored context for the id \u2014 both or\nnone together, never just one. If the settle result carries `settled: false`,\nfunding is queued for the user's approval \u2014 tell them and check status later,\ndo not re-pay.\n\nStep-by-step alternative (also key-safe; for an older signer or backend, or\nwhen you already have a merchant URL and tool name instead of a\n`catalog_id`): `mcp__haven__haven_pay_mcp_tool` then\n`mcp__haven-signer__haven_sign` \u2192 `mcp__haven__haven_submit` \u2192\n`mcp__haven-signer__haven_x402_sign_header` \u2192\n`mcp__haven__haven_complete_mcp_tool`. Pass `payment_required`,\n`arguments`, and `mcp_transport` verbatim from the quote/prepare result.\nThe returned `expires_at` is the signing window; if a tool returns\n`PAYMENT_WINDOW_EXPIRED`, re-run the same quote/prepare tool with the same\n`idempotency_key`. Do not call the merchant yourself \u2014 Haven completes the\nmerchant leg for you.\n\n**Direct transfer / non-MCP paywall:** `mcp__haven__haven_pay` with\nrecipient, amount, and token for a plain transfer. For an arbitrary,\nnon-MCP x402 paywall: `mcp__haven__haven_quote_x402` to get a quote, then\n`mcp__haven__haven_pay_x402_quote` \u2014 follow the result's guidance fields\nfirst, sign in the local Haven signer, and retry the original request only\nwhen the result says `retry_original_x402_request`.\n\n**Catalog tool arguments:** when `haven_discover_tools` returns\n`tool_arguments`, pass that object unchanged as the pay tool's\n`arguments` field (for example\n`tool_arguments: { \"tier\": \"50gb\" }` -> `arguments: { \"tier\": \"50gb\" }`).\n\n**Prices:** show the user the live price from the pay-tool result, never a\ncatalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. The pay-tool result's `amount` /\n`amount_atomic` is the amount Haven authorizes for the call \u2014 a ceiling the\nmerchant settles at or below \u2014 so present it as the most the user will pay.\n\n**Status:** `mcp__haven__haven_get_payment_status` with a `payment_id` to\ncheck on queued or in-flight payments. Do not poll in a tight loop.\n\n## Approval semantics\n\n- A result with `pending_approval` means the payment exceeded the remaining\n budget and is waiting for the user in Haven. Tell the user, then check\n status later.\n- `safe_to_continue: false` on a guidance block is the same signal in\n machine-readable form: stop and involve the user before calling anything\n else for this payment.\n- Never ask the user for private keys. Signing happens only in the local Haven\n signer; the hosted Haven tools never receive the signing key. If a tool\n reports a missing or invalid credential, tell the user to re-run the Haven\n setup command.\n\n## Failure handling\n\nHaven tool failures are shaped like `{ success: false, code, message, ... }`\nor older `{ error, status, details? }` responses. Branch on `code` when\npresent and surface `message` or `error` verbatim. Common cases:\n\n- `pending_approval`: queued for the user's approval (see above).\n- `insufficient_funds`: the Haven wallet doesn't hold enough of that token.\n Suggest the user add funds in the Haven dashboard.\n- `PRICE_EXCEEDS_MAX`: the live merchant price exceeded your cap. No funds\n moved; ask the user before retrying with a higher one.\n- `AMBIGUOUS_MAX_AMOUNT`: you sent both `max_amount` and\n `max_amount_human`. Nothing was contacted or spent \u2014 re-send with exactly\n one (`max_amount_human` for a cap the user stated in tokens).\n- `MAX_AMOUNT_UNCONVERTIBLE`: `max_amount_human` does not fit this quote's\n asset \u2014 unknown decimals, or more decimal places than the asset supports.\n Round the cap, or send an exact atomic `max_amount`.\n- `PAYMENT_WINDOW_EXPIRED`: re-run the quote/prepare tool with the same\n `idempotency_key`, then sign the fresh payload.\n- `MERCHANT_REJECTED_AFTER_FUNDING`: the merchant refused the paid retry.\n Stop-and-sweep \u2014 stop retrying the merchant and use\n `mcp__haven__haven_sweep_delegate` to recover stranded delegate funds.\n- `MERCHANT_UNRESPONSIVE_AFTER_FUNDING`: funding confirmed on-chain, but the\n merchant never answered the paid retry. This is NOT proof of rejection \u2014 the\n merchant may still settle late. Verify-then-sweep, never a blind sweep:\n check `mcp__haven__haven_get_payment_status`, retry\n `mcp__haven__haven_complete_mcp_tool` ONCE, and only sweep with\n `mcp__haven__haven_sweep_delegate` if no settlement appears.\n- Budget exceeded: tell the user how much remains (from\n `mcp__haven__haven_get_allowances`) and that they can raise the budget in\n Haven.\n\n## Reporting after a purchase\n\nA settled `mcp__haven__haven_settle_mcp_tool` response carries\n`agent_summary.purchase_summary` and the remaining post-purchase allowance\nin `allowance` \u2014 report the product, Haven-derived payment/transaction\nfields, and what is left from those fields directly. `result` is optional\nraw merchant evidence; never use it to decide whether the purchase was paid.\nDo not call `haven_get_agent` or `haven_get_allowances` again just to\nreport a purchase you already made.\n\n## Revoke\n\nIf this agent's credential may have leaked, tell the user to pause or revoke\nthe agent in the Haven dashboard under Agents. New requests stop immediately\nfor that credential.\n";
1698
2107
  /** Directory name for the installed skill folder. */
1699
2108
  declare const SKILL_FOLDER_NAME = "haven-pay";
1700
2109
 
@@ -1732,7 +2141,7 @@ declare const SKILL_FOLDER_NAME = "haven-pay";
1732
2141
  * package. A guard test in each package asserts exactly that against its own
1733
2142
  * `package.json`, so the two cannot drift again silently.
1734
2143
  */
1735
- declare const HAVEN_MINIMUM_NODE_VERSION = "24.0.0";
2144
+ declare const HAVEN_MINIMUM_NODE_VERSION = "22.0.0";
1736
2145
  /**
1737
2146
  * Compare two Node versions. Negative when `left` is older.
1738
2147
  *
@@ -1877,6 +2286,16 @@ declare function encodePaymentProof(receipt: {
1877
2286
  payer?: string;
1878
2287
  chainId?: number;
1879
2288
  }): string;
2289
+ /**
2290
+ * Resolve a token symbol from a contract address.
2291
+ *
2292
+ * Checks all supported chains. For chain-specific resolution,
2293
+ * pass the optional `network` CAIP-2 string (e.g. "eip155:100").
2294
+ */
2295
+ declare function resolveTokenFromAddress(address: string, network?: string): {
2296
+ symbol: string;
2297
+ decimals: number;
2298
+ } | null;
1880
2299
 
1881
2300
  declare function parseMachinePaymentChallenge(response: Response): MachinePaymentChallenge;
1882
2301
  declare function parseMachinePaymentChallengeResponse(response: Response): Promise<MachinePaymentChallenge>;
@@ -1921,4 +2340,32 @@ declare function encodeBase64Json(value: unknown): string;
1921
2340
  */
1922
2341
  declare function decodeBase64Json<T>(value: string, label?: string): T;
1923
2342
 
1924
- export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type ClaudeTool, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, type MachinePaymentChallenge, type MachinePaymentRail, type MachinePaymentReceipt, type MppAuthorizationOptions, type MppQuote, type MppResumeState, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PendingApproval, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedMppInput, type ResumeAuthorizedX402Input, type ResumeMppPaymentInput, type ResumeX402PaymentInput, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, type SweepAuthorization, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, type X402AuthorizationOptions, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpTransport, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildMachinePaymentIdempotencyKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, encodeBase64Json, encodeBase64Utf8, encodeMachinePaymentProof, encodePaymentProof, havenTools, isSupportedNodeVersion, isSweepableChain, parseMachinePaymentChallenge, parseMachinePaymentChallengeResponse, parsePaymentRequired, parsePaymentRequiredResponse, selectPaymentOption, selectStandardPaymentOption, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, verifyPaymentReceipt, verifySignature, x402AuthorizationAmount };
2343
+ /**
2344
+ * #1271 / #1301: bounded same-origin merchant MCP endpoint discovery.
2345
+ *
2346
+ * An agent handed a BASE merchant URL previously had to hand-probe /, /mcp,
2347
+ * /sse, … until something answered 402. The demo merchant (and the #1266
2348
+ * contract) serves a machine-readable discovery document at
2349
+ * `/.well-known/haven-demo-merchant` (also at `/`) naming `mcp_url`. This
2350
+ * helper fetches ONLY those two fixed same-origin paths — no redirects
2351
+ * (`redirect: 'error'`), a 5 s timeout, a 64 KB read cap — and accepts the
2352
+ * document's `mcp_url` ONLY when it stays on the same origin as the input.
2353
+ * Anything else returns null and the caller reports the original probe
2354
+ * failure. Discovery finds endpoints; it carries no payment authority and an
2355
+ * off-origin `mcp_url` is never even fetched — this must not grow into a
2356
+ * general network scanner (SSRF bound, per the issue).
2357
+ *
2358
+ * Originally hosted-only (mcp-server, #1271). Moved here in #1301 so the
2359
+ * local/self-signed MCP package (`@haven_ai/mcp`) can share the EXACT same
2360
+ * bounded implementation instead of re-deriving discovery semantics —
2361
+ * behavior is byte-identical to the pre-move mcp-server copy; the #1271
2362
+ * contract tests in packages/mcp-server/src/tools.test.ts pass unmodified
2363
+ * against this moved implementation.
2364
+ */
2365
+ declare const MERCHANT_DISCOVERY_PATHS: readonly ["/.well-known/haven-demo-merchant", "/"];
2366
+ declare const DISCOVERY_MAX_BYTES: number;
2367
+ declare function discoverMerchantMcpUrl(inputUrl: string): Promise<string | null>;
2368
+ /** Trailing-slash/percent-case echoes compare equal; unparseable never does. */
2369
+ declare function sameUrl(a: string, b: string): boolean;
2370
+
2371
+ export { AGENT_PAYMENT_FAILURE_CODE_VALUES, AGENT_PAYMENT_NEXT_ACTION_VALUES, AGENT_PAYMENT_PHASE_VALUES, AGENT_PAYMENT_RAIL_VALUES, type AgentNextStep, type AgentPaymentEnumSchema, AgentPaymentFailureCode, AgentPaymentFailureCodeDescriptions, AgentPaymentFailureCodeSchema, AgentPaymentNextAction, AgentPaymentNextActionDescriptions, AgentPaymentNextActionSchema, AgentPaymentPhase, AgentPaymentPhaseDescriptions, AgentPaymentPhaseSchema, AgentPaymentRail, AgentPaymentRailDescriptions, AgentPaymentRailSchema, type AgentPaymentSummary, type AgentPaymentWarning, AgentPaymentWarningCode, type AgentPurchaseSummary, type ClaudeTool, DISCOVERY_MAX_BYTES, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentChallenge, type MachinePaymentRail, type MachinePaymentReceipt, MerchantTimeoutError, type MppAuthorizationOptions, type MppQuote, type MppResumeState, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PendingApproval, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedMppInput, type ResumeAuthorizedX402Input, type ResumeMppPaymentInput, type ResumeX402PaymentInput, SIGNER_UPDATE_FALLBACK, SKILL_FOLDER_NAME, SWEEP_BASE_CHAIN_ID, SWEEP_BASE_SEPOLIA_CHAIN_ID, SWEEP_BASE_SEPOLIA_USDC_ADDRESS, SWEEP_BASE_USDC_ADDRESS, type SharedToolKey, type SignData, SignerRefusalCode, type SweepAuthorization, type SweepEip712Domain, type SweepEntry, type SweepExpectedAuth, type SweepPreparation, type SweepPrepareResponse, type SweepResult, type SweepSubmitResponse, type SweepSubmitResult, type SweepTypedData, TRANSFER_WITH_AUTHORIZATION_TYPES, type ToolDescription, type UnsupportedNodeVersionMessageOptions, type X402AuthorizationOptions, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildMachinePaymentIdempotencyKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodeMachinePaymentProof, encodePaymentProof, havenTools, isSupportedNodeVersion, isSweepableChain, parseMachinePaymentChallenge, parseMachinePaymentChallengeResponse, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectPaymentOption, selectStandardPaymentOption, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, verifyPaymentReceipt, verifySignature, x402AuthorizationAmount };