@haven_ai/sdk 0.1.32-alpha.0 → 0.1.34-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.cts CHANGED
@@ -207,6 +207,7 @@ interface X402PaymentRequired {
207
207
  url: string;
208
208
  description?: string;
209
209
  mimeType?: string;
210
+ [key: string]: unknown;
210
211
  };
211
212
  accepts: X402PaymentOption[];
212
213
  error?: string;
@@ -1102,7 +1103,12 @@ interface PaymentStatusResult {
1102
1103
  */
1103
1104
  interface X402Erc7710Settlement {
1104
1105
  paymentId: string;
1105
- /** Pass verbatim as the `X-PAYMENT` header on the merchant retry. */
1106
+ /**
1107
+ * Pass verbatim as the `PAYMENT-SIGNATURE` header on the merchant retry —
1108
+ * that name ALONE. erc7710 is always x402 v2, and this header carries the
1109
+ * delegation chain, so also sending the legacy `X-PAYMENT` overflows the
1110
+ * merchant's header limit (HTTP 431, #2341).
1111
+ */
1106
1112
  paymentHeader: string;
1107
1113
  /** The merchant address the child delegation is pinned to. */
1108
1114
  merchantPayTo: string;
@@ -1462,6 +1468,42 @@ declare function buildSweepTypedData(auth: SweepAuthorization): SweepTypedData;
1462
1468
  */
1463
1469
  declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): string;
1464
1470
 
1471
+ /**
1472
+ * Merchant delivery and the evidence trail behind it (#1620, epic #1613).
1473
+ *
1474
+ * Where `mcp-merchant-transport.ts` (#1616) owns the wire — timeouts,
1475
+ * sessions, SSE framing — this module owns what has to be TRUE around a
1476
+ * merchant call once a payment exists: which wallet the merchant should see,
1477
+ * what the payment's live state permits, and what gets written down
1478
+ * afterwards.
1479
+ *
1480
+ * The reporting is deliberately best-effort and deliberately asymmetric. A
1481
+ * merchant that REJECTS a retry after Haven already moved money is a
1482
+ * reconciliation event and is recorded as one; a merchant that accepts is
1483
+ * evidence, plus its own receipt when it offers one. Neither write may ever
1484
+ * change the caller-visible outcome — the resource is already paid for, and
1485
+ * an exception thrown from bookkeeping would turn a completed payment into a
1486
+ * reported failure. That is why every one of these swallows.
1487
+ *
1488
+ * Scheme-neutral by construction: it is handed a receipt or a payment id and
1489
+ * never asks how the money moved, which is what lets the #1508 no-funding-leg
1490
+ * path through the same door as the 3009 path.
1491
+ *
1492
+ * Internal to `HavenClient`. Exported for direct tests and composition only.
1493
+ */
1494
+ /** #2292: what an agent says a merchant answered to a retry Haven did not make. */
1495
+ type X402MerchantOutcome = 'accepted' | 'rejected';
1496
+ /** #2292: what Haven wrote down for such a report. */
1497
+ interface X402MerchantOutcomeReport {
1498
+ paymentId: string;
1499
+ outcome: X402MerchantOutcome;
1500
+ /** Haven's own funding tx for this payment — the anchor, never caller-supplied. */
1501
+ txHash: string;
1502
+ /** Haven's own recorded resource URL — likewise never caller-supplied. */
1503
+ resourceUrl: string;
1504
+ recorded: 'reconciliation_event' | 'evidence';
1505
+ }
1506
+
1465
1507
  declare class HavenClient {
1466
1508
  private readonly delegateKey;
1467
1509
  private readonly havenApi;
@@ -1819,8 +1861,8 @@ declare class HavenClient {
1819
1861
  /**
1820
1862
  * The account's rail, when the caller has ALREADY read it — passing it
1821
1863
  * skips a duplicate fetch (#1456). An optimisation, not a trust
1822
- * boundary: the backend independently refuses erc7710 from a
1823
- * non-delegation account (`validateGenericSchemeRail`).
1864
+ * boundary: the backend independently refuses a non-delegation account
1865
+ * at the rail seam (the #1986 retired-rail 410, #2245).
1824
1866
  */
1825
1867
  delegationRail?: boolean;
1826
1868
  /**
@@ -1878,7 +1920,7 @@ declare class HavenClient {
1878
1920
  * Deliver an already-signed x402 payment header to the merchant and return
1879
1921
  * the merchant's response. Used by the hosted MCP server to complete the
1880
1922
  * merchant leg of an MCP tool payment after the edge signer has built the
1881
- * `X-PAYMENT` header.
1923
+ * merchant payment header.
1882
1924
  *
1883
1925
  * Custody note: this never needs the delegate key. It relays a signed,
1884
1926
  * amount/merchant/nonce-bound EIP-3009 authorization the edge signer already
@@ -1888,13 +1930,14 @@ declare class HavenClient {
1888
1930
  * says the merchant was Bazaar-discoverable, runs a fresh `initialize`
1889
1931
  * handshake (the quote-time session is gone once funding confirms; the x402
1890
1932
  * challenge is stateless w.r.t. the MCP session, so a fresh session is
1891
- * accepted), threads the session + wallet headers, sets `X-PAYMENT`, and
1933
+ * accepted), threads the session + wallet headers, sets the x402 payment
1934
+ * header under the names that scheme requires (#2341), and
1892
1935
  * collapses an SSE JSON-RPC response to its `result`.
1893
1936
  */
1894
1937
  /**
1895
1938
  * Wait for a payment's Safe→delegate funding tx to reach ≥1 on-chain
1896
1939
  * confirmation. The hosted x402 completion path MUST call this after funding
1897
- * and before delivering the X-PAYMENT header, so the merchant's
1940
+ * and before delivering the merchant payment header, so the merchant's
1898
1941
  * balanceOf(delegate) / transferWithAuthorization verification sees the funded
1899
1942
  * balance — otherwise it rejects with "Payment verification failed". The
1900
1943
  * SDK's local path already does this (see `X402FundingLeg.authorize`); the hosted
@@ -1935,6 +1978,21 @@ declare class HavenClient {
1935
1978
  body: unknown;
1936
1979
  settlementTxHash?: string;
1937
1980
  }>;
1981
+ /**
1982
+ * #2292: report the outcome of a merchant retry the AGENT performed.
1983
+ *
1984
+ * The hosted `haven_complete_mcp_tool` / `completeX402MerchantCall` path is
1985
+ * for merchants Haven calls itself. On the plain-HTTP x402 path Haven never
1986
+ * talks to the merchant, so the outcome of that retry had no way back —
1987
+ * see `MerchantCompletion.reportMerchantOutcome` for what is verified about
1988
+ * a caller-asserted report and what deliberately is not.
1989
+ */
1990
+ reportX402MerchantOutcome(input: {
1991
+ paymentId: string;
1992
+ outcome: X402MerchantOutcome;
1993
+ merchantStatus: number;
1994
+ merchantBody?: string;
1995
+ }): Promise<X402MerchantOutcomeReport>;
1938
1996
  /**
1939
1997
  * GET /x402/:id/merchant-call-context — the settle-leg twin of #1263's
1940
1998
  * sign-context fetch (#1307). Re-serves the stored merchant MCP-tool call
@@ -2113,12 +2171,12 @@ declare const toolDescriptions: {
2113
2171
  readonly payX402OneShot: {
2114
2172
  readonly summary: "Fetch an x402 paid HTTP resource in a single call. Handles the full probe -> pay -> retry round trip and returns the merchant response.";
2115
2173
  readonly selectionGuidance: "Prefer this over the quote+pay split when the agent just wants the paid resource and does not need to inspect the price first. If you already have a quote from haven_quote_x402, use haven_pay_x402_quote instead. Do not use for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.";
2116
- readonly behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the payment locally, then retries the original request with the X-PAYMENT header and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later. If the resource returns a non-402 status, returns it unchanged without contacting Haven.";
2174
+ readonly behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the payment locally, then retries the original request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only) and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later. If the resource returns a non-402 status, returns it unchanged without contacting Haven.";
2117
2175
  readonly nextActionGuidance: string;
2118
2176
  };
2119
2177
  readonly resumeX402: {
2120
2178
  readonly summary: "Resume an x402 payment whose Haven-side authorization already succeeded but whose merchant retry did not complete.";
2121
- readonly behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the authorized Haven funding, and retries the merchant request with the X-PAYMENT header. No new Haven payment is created.";
2179
+ readonly behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the authorized Haven funding, and retries the merchant request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only). No new Haven payment is created.";
2122
2180
  readonly nextActionGuidance: string;
2123
2181
  };
2124
2182
  readonly getPaymentStatus: {
@@ -2207,7 +2265,7 @@ type SharedToolKey = keyof typeof toolDescriptions;
2207
2265
  * this canonical string and asserts byte-for-byte equality, so the two copies
2208
2266
  * cannot drift.
2209
2267
  */
2210
- 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; a payment above the remaining budget is declined \u2014\nnothing is paid past the rules the user set.\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.\nThat namespacing is Claude-family; other runtimes name the servers by their\nown config keys (Codex: `haven`, `haven_signer`). Tool results carry the\nexact next step (`next_action`, `next_tool`, `next_arguments`, plus the\nruntime-neutral `next_tool_server` + `next_tool_name` \u2014 the bare tool name\non that logical server, whatever your runtime calls it).\nFollow those fields first; the prose below is fallback and orientation, not\nthe 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 `spend_authority_readiness` (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot. That signal\n covers hosted identity and on-chain spend authority only \u2014 it cannot see the\n local signer; the signer is verified by calling any signer tool.\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 declined before any money moves \u2014 tell the user; they can raise\nthe budget in the Haven dashboard, or wait for the period reset.\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. If the user needs the live price before authorizing a cap, call\n `mcp__haven__haven_quote_catalog_purchase` with `catalog_id`. It is\n read-only and informational only: it never reserves a price or creates a\n payment. Tell the user its `amount` / `amount_atomic`, then choose a cap.\n3. `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.)\n4. 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 has not confirmed \u2014 follow the result's guidance fields and check\nstatus later, do 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`): if the user needs the live price before choosing a cap, first\ncall `mcp__haven__haven_quote_mcp_tool` with that merchant URL, tool name,\nand arguments. It is informational only; then call\n`mcp__haven__haven_pay_mcp_tool` with the same inputs and the explicit cap.\nThe paid call always obtains a fresh quote before it creates any intent. Then\ncontinue `mcp__haven__haven_pay_mcp_tool` \u2192\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 and sign in the local Haven signer. The pay tool performs the merchant\nretry itself, so do not wait on a signal while it runs. If the process\ncrashes after payment, a later `mcp__haven__haven_get_payment_status` call\nmay report `nextAction: 'retry_original_x402_request'` \u2014 only then call\n`mcp__haven__haven_resume_x402_payment` with the preserved resume state or\npayment id, instead of paying again.\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 a read-only quote or the pay-tool\nresult, never a catalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. A read-only quote is informational\nonly and does not reserve a price; the later paid call re-quotes and enforces\nthe cap. The pay-tool result's `amount` / `amount_atomic` is the amount\nHaven authorizes for that call \u2014 a ceiling the merchant settles at or below \u2014\nso 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 in-flight payments. Do not poll in a tight loop.\n\n## Declines and stop signals\n\n- A payment outside the agent's rules \u2014 above the remaining budget, wrong\n recipient, or expired budget \u2014 is declined before any money moves. Nothing\n is queued; tell the user, who can raise the budget in Haven.\n- `safe_to_continue: false` on a guidance block is a stop 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- `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";
2268
+ 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; a payment above the remaining budget is declined \u2014\nnothing is paid past the rules the user set.\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.\nThat namespacing is Claude-family; other runtimes name the servers by their\nown config keys (Codex: `haven`, `haven_signer`). Tool results carry the\nexact next step (`next_action`, `next_tool`, `next_arguments`, plus the\nruntime-neutral `next_tool_server` + `next_tool_name` \u2014 the bare tool name\non that logical server, whatever your runtime calls it).\nFollow those fields first; the prose below is fallback and orientation, not\nthe 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 `spend_authority_readiness` (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot. That signal\n covers hosted identity and on-chain spend authority only \u2014 it cannot see the\n local signer; the signer is verified by calling any signer tool.\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 declined before any money moves \u2014 tell the user; they can raise\nthe budget in the Haven dashboard, or wait for the period reset.\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. If the user needs the live price before authorizing a cap, call\n `mcp__haven__haven_quote_catalog_purchase` with `catalog_id`. It is\n read-only and informational only: it never reserves a price or creates a\n payment. Tell the user its `amount` / `amount_atomic`, then choose a cap.\n3. `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.)\n4. 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 has not confirmed \u2014 follow the result's guidance fields and check\nstatus later, do 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`): if the user needs the live price before choosing a cap, first\ncall `mcp__haven__haven_quote_mcp_tool` with that merchant URL, tool name,\nand arguments. It is informational only; then call\n`mcp__haven__haven_pay_mcp_tool` with the same inputs and the explicit cap.\nThe paid call always obtains a fresh quote before it creates any intent. Then\ncontinue `mcp__haven__haven_pay_mcp_tool` \u2192\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`. Call that last step with\n`payment_id` and the signer's `payment_header` ONLY. It does not take\n`payment_required`: Haven rehydrates the merchant call context\n(`merchant_url`, `tool_name`, `arguments`, `mcp_transport`) and the\n402 server-side from `payment_id`, exactly as at settle. Pass that context\nexplicitly only as a version-skew fallback when Haven has no stored context\nfor the id \u2014 `merchant_url` and `tool_name` both or none together, never\njust one.\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 and sign in the local Haven signer. On THIS path Haven does not talk to\nthe merchant: `mcp__haven-signer__haven_sign_x402` returns both\n`signature` and `payment_header`; relay `signature` with\n`mcp__haven__haven_submit`, then retry the paywalled URL yourself with\n`payment_header`. Do not pass that call's `x402_binding` to\n`mcp__haven-signer__haven_x402_sign_header` \u2014 the one-shot already spent it\nbuilding the header, so the call can only refuse. Then tell Haven what the\nmerchant answered: `mcp__haven__haven_report_x402_outcome` with the\n`payment_id`, `outcome` (`\"accepted\"` for a 2xx, else `\"rejected\"`)\nand the `merchant_status` you got. Because Haven never contacted that\nmerchant, this is the only way it can learn the purchase failed \u2014 without it a\nfailed purchase reads as complete for fifteen minutes. (The SDK's own\n`haven_pay_x402` tool does perform the merchant retry itself; that tool is\nnot part of the hosted MCP surface.) If the process\ncrashes after payment, a later `mcp__haven__haven_get_payment_status` call\nmay report `nextAction: 'retry_original_x402_request'` \u2014 only then call\n`mcp__haven__haven_resume_x402_payment` with the preserved resume state or\npayment id, instead of paying again.\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 a read-only quote or the pay-tool\nresult, never a catalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. A read-only quote is informational\nonly and does not reserve a price; the later paid call re-quotes and enforces\nthe cap. The pay-tool result's `amount` / `amount_atomic` is the merchant's\nown quoted price for that call \u2014 a ceiling the merchant settles at or below \u2014\nso present it as the most the user will pay. It is a price, not an approval:\nthe payment goes through only if it also fits the cap you set and the on-chain\nbudget the user signed, which is enforced on-chain rather than by Haven.\n\n**Status:** `mcp__haven__haven_get_payment_status` with a `payment_id` to\ncheck on in-flight payments. Do not poll in a tight loop.\n\n## Declines and stop signals\n\n- A payment outside the agent's rules \u2014 above the remaining budget, wrong\n recipient, or expired budget \u2014 is declined before any money moves. Nothing\n is queued; tell the user, who can raise the budget in Haven.\n- `safe_to_continue: false` on a guidance block is a stop 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- `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";
2211
2269
  /** Directory name for the installed skill folder. */
2212
2270
  declare const SKILL_FOLDER_NAME = "haven-pay";
2213
2271
  /**
@@ -2351,6 +2409,66 @@ declare const X402_MAX_AUTHORIZATION_WINDOW_SECONDS = 600;
2351
2409
  */
2352
2410
  declare const X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = 300;
2353
2411
  declare function normalizePaymentRequired(value: unknown): X402PaymentRequired | null;
2412
+ /**
2413
+ * The x402 wire header names, in one place (#2289).
2414
+ *
2415
+ * v2 renamed all three; v1's only name was `X-PAYMENT`, used in BOTH
2416
+ * directions. Haven had adopted the v2 names for everything it *reads* and
2417
+ * kept the v1 name for the one thing it *writes*, which is how a strict v2
2418
+ * merchant came to never see a payment header at all.
2419
+ *
2420
+ * The 2026-08-31 owner decision was to send both outbound names on every
2421
+ * retry rather than switch on `x402Version`: a v1 merchant ignores the name it
2422
+ * does not know, a v2 merchant ignores the legacy one, and no version
2423
+ * heuristic has to be right for a payment to land.
2424
+ *
2425
+ * **That is no longer unconditional (#2341).** It held while the cost of a
2426
+ * spare header was zero, and on the EIP-3009 bridge it still is. On erc7710 it
2427
+ * is not: that header carries a whole delegation chain, and duplicating it
2428
+ * overflowed the merchant's header limit — HTTP 431, every erc7710 settlement
2429
+ * refused. `x402PaymentHeaderNamesFor` below is the live rule; read it rather
2430
+ * than this paragraph, which records why the simpler rule was right first.
2431
+ */
2432
+ /** v2 client→server payment payload. The name a strict v2 merchant reads. */
2433
+ declare const X402_PAYMENT_HEADER_NAME = "PAYMENT-SIGNATURE";
2434
+ /** v1 client→server payment payload; still accepted by most v2 merchants. */
2435
+ declare const X402_LEGACY_PAYMENT_HEADER_NAME = "X-PAYMENT";
2436
+ /** v2 server→client payment requirements. */
2437
+ declare const X402_PAYMENT_REQUIRED_HEADER_NAME = "PAYMENT-REQUIRED";
2438
+ /** v2 server→client settlement receipt. */
2439
+ declare const X402_PAYMENT_RESPONSE_HEADER_NAME = "PAYMENT-RESPONSE";
2440
+ /**
2441
+ * Both wire names, v2 first — the value an EIP-3009 retry actually sends.
2442
+ *
2443
+ * **Not the general answer any more (#2341), and not what a recorder should
2444
+ * reach for.** This was the evidence record's `paymentProofHeaderName` while
2445
+ * both names always went on the wire; erc7710 now sends one, so a recorder
2446
+ * still reading this constant would log a legacy header that was never sent —
2447
+ * exactly the drift the previous wording promised it prevented. Use
2448
+ * `x402PaymentHeaderNamesSent(paymentHeader)`. Kept exported because it is a
2449
+ * published surface and removing it would break consumers.
2450
+ */
2451
+ declare const X402_PAYMENT_HEADER_NAMES_SENT = "PAYMENT-SIGNATURE, X-PAYMENT";
2452
+ /**
2453
+ * The x402 v2 payment envelope: `{x402Version, resource?, accepted, payload,
2454
+ * extensions?}` per the spec's PaymentPayload (§5.2.2).
2455
+ *
2456
+ * The `resource` and `extensions` echoes are the #2361 fix, and they are not
2457
+ * optional politeness: the spec makes the extensions echo a MUST ("the client
2458
+ * must include at least the info received"), and CoinGecko's facilitator was
2459
+ * live-bisected rejecting the echo-less envelope with a bare 400 while
2460
+ * accepting the identical signature and `accepted`/`payload` bytes with the
2461
+ * echoes added (#2360, Base mainnet, 2026-09-01). Both objects are echoed
2462
+ * VERBATIM from the merchant's 402 — never reconstructed — and omitted when
2463
+ * the challenge carries none, which keeps the envelope byte-identical to the
2464
+ * pre-#2361 shape for echo-less merchants (Ampersend and Soundside settled
2465
+ * that shape live, so omission is the proven-compatible default).
2466
+ *
2467
+ * The `accepted` wrap itself is #303's shape and predates this helper — see
2468
+ * the #300/#303 history before "fixing" it: scheme/network live INSIDE
2469
+ * `accepted` in v2, never at the top level.
2470
+ */
2471
+ declare function x402V2PaymentEnvelope(paymentRequired: Pick<X402PaymentRequired, 'x402Version' | 'resource' | 'extensions'>, accepted: X402PaymentOption, payload: unknown): Record<string, unknown>;
2354
2472
  /**
2355
2473
  * Parse an HTTP 402 response into x402 PaymentRequired data.
2356
2474
  *
@@ -2445,9 +2563,10 @@ interface X402SchemeSelection {
2445
2563
  * caller's to supply — the SDK cannot see which rail an account is on from a
2446
2564
  * 402 response alone. A legacy AllowanceModule account passing
2447
2565
  * `delegationRail: true` would select a scheme its account cannot settle; the
2448
- * backend refuses that at authorize (`validateGenericSchemeRail`), which is
2449
- * where a rail mismatch SHOULD fail, on-chain-adjacent rather than in a client
2450
- * that could be lying to itself.
2566
+ * backend refuses that at authorize with the #1986 retired-rail 410 (#2245 —
2567
+ * previously a scheme-specific 400 that wrongly implied the legacy rail could
2568
+ * still settle via EIP-3009), which is where a rail mismatch SHOULD fail,
2569
+ * on-chain-adjacent rather than in a client that could be lying to itself.
2451
2570
  *
2452
2571
  * Returns `null` when neither scheme has a payable entry — the caller decides
2453
2572
  * whether that is an error or a reason to look elsewhere.
@@ -2577,4 +2696,4 @@ declare function discoverMerchantMcpUrl(inputUrl: string): Promise<string | null
2577
2696
  /** Trailing-slash/percent-case echoes compare equal; unparseable never does. */
2578
2697
  declare function sameUrl(a: string, b: string): boolean;
2579
2698
 
2580
- 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 CatalogSubmissionAccepted, type ClaudeTool, DEFAULT_CONFIRMATION_TIMEOUT_MS, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, type HavenCatalogSubmission, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, 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 SweepConfirmation, 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, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
2699
+ 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 CatalogSubmissionAccepted, type ClaudeTool, DEFAULT_CONFIRMATION_TIMEOUT_MS, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, type HavenCatalogSubmission, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, 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 SweepConfirmation, 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, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402MerchantOutcome, type X402MerchantOutcomeReport, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_LEGACY_PAYMENT_HEADER_NAME, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_PAYMENT_HEADER_NAME, X402_PAYMENT_HEADER_NAMES_SENT, X402_PAYMENT_REQUIRED_HEADER_NAME, X402_PAYMENT_RESPONSE_HEADER_NAME, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses, x402V2PaymentEnvelope };
package/dist/index.d.ts CHANGED
@@ -207,6 +207,7 @@ interface X402PaymentRequired {
207
207
  url: string;
208
208
  description?: string;
209
209
  mimeType?: string;
210
+ [key: string]: unknown;
210
211
  };
211
212
  accepts: X402PaymentOption[];
212
213
  error?: string;
@@ -1102,7 +1103,12 @@ interface PaymentStatusResult {
1102
1103
  */
1103
1104
  interface X402Erc7710Settlement {
1104
1105
  paymentId: string;
1105
- /** Pass verbatim as the `X-PAYMENT` header on the merchant retry. */
1106
+ /**
1107
+ * Pass verbatim as the `PAYMENT-SIGNATURE` header on the merchant retry —
1108
+ * that name ALONE. erc7710 is always x402 v2, and this header carries the
1109
+ * delegation chain, so also sending the legacy `X-PAYMENT` overflows the
1110
+ * merchant's header limit (HTTP 431, #2341).
1111
+ */
1106
1112
  paymentHeader: string;
1107
1113
  /** The merchant address the child delegation is pinned to. */
1108
1114
  merchantPayTo: string;
@@ -1462,6 +1468,42 @@ declare function buildSweepTypedData(auth: SweepAuthorization): SweepTypedData;
1462
1468
  */
1463
1469
  declare function buildSweepAuthorizationMessage(auth: SweepAuthorization): string;
1464
1470
 
1471
+ /**
1472
+ * Merchant delivery and the evidence trail behind it (#1620, epic #1613).
1473
+ *
1474
+ * Where `mcp-merchant-transport.ts` (#1616) owns the wire — timeouts,
1475
+ * sessions, SSE framing — this module owns what has to be TRUE around a
1476
+ * merchant call once a payment exists: which wallet the merchant should see,
1477
+ * what the payment's live state permits, and what gets written down
1478
+ * afterwards.
1479
+ *
1480
+ * The reporting is deliberately best-effort and deliberately asymmetric. A
1481
+ * merchant that REJECTS a retry after Haven already moved money is a
1482
+ * reconciliation event and is recorded as one; a merchant that accepts is
1483
+ * evidence, plus its own receipt when it offers one. Neither write may ever
1484
+ * change the caller-visible outcome — the resource is already paid for, and
1485
+ * an exception thrown from bookkeeping would turn a completed payment into a
1486
+ * reported failure. That is why every one of these swallows.
1487
+ *
1488
+ * Scheme-neutral by construction: it is handed a receipt or a payment id and
1489
+ * never asks how the money moved, which is what lets the #1508 no-funding-leg
1490
+ * path through the same door as the 3009 path.
1491
+ *
1492
+ * Internal to `HavenClient`. Exported for direct tests and composition only.
1493
+ */
1494
+ /** #2292: what an agent says a merchant answered to a retry Haven did not make. */
1495
+ type X402MerchantOutcome = 'accepted' | 'rejected';
1496
+ /** #2292: what Haven wrote down for such a report. */
1497
+ interface X402MerchantOutcomeReport {
1498
+ paymentId: string;
1499
+ outcome: X402MerchantOutcome;
1500
+ /** Haven's own funding tx for this payment — the anchor, never caller-supplied. */
1501
+ txHash: string;
1502
+ /** Haven's own recorded resource URL — likewise never caller-supplied. */
1503
+ resourceUrl: string;
1504
+ recorded: 'reconciliation_event' | 'evidence';
1505
+ }
1506
+
1465
1507
  declare class HavenClient {
1466
1508
  private readonly delegateKey;
1467
1509
  private readonly havenApi;
@@ -1819,8 +1861,8 @@ declare class HavenClient {
1819
1861
  /**
1820
1862
  * The account's rail, when the caller has ALREADY read it — passing it
1821
1863
  * skips a duplicate fetch (#1456). An optimisation, not a trust
1822
- * boundary: the backend independently refuses erc7710 from a
1823
- * non-delegation account (`validateGenericSchemeRail`).
1864
+ * boundary: the backend independently refuses a non-delegation account
1865
+ * at the rail seam (the #1986 retired-rail 410, #2245).
1824
1866
  */
1825
1867
  delegationRail?: boolean;
1826
1868
  /**
@@ -1878,7 +1920,7 @@ declare class HavenClient {
1878
1920
  * Deliver an already-signed x402 payment header to the merchant and return
1879
1921
  * the merchant's response. Used by the hosted MCP server to complete the
1880
1922
  * merchant leg of an MCP tool payment after the edge signer has built the
1881
- * `X-PAYMENT` header.
1923
+ * merchant payment header.
1882
1924
  *
1883
1925
  * Custody note: this never needs the delegate key. It relays a signed,
1884
1926
  * amount/merchant/nonce-bound EIP-3009 authorization the edge signer already
@@ -1888,13 +1930,14 @@ declare class HavenClient {
1888
1930
  * says the merchant was Bazaar-discoverable, runs a fresh `initialize`
1889
1931
  * handshake (the quote-time session is gone once funding confirms; the x402
1890
1932
  * challenge is stateless w.r.t. the MCP session, so a fresh session is
1891
- * accepted), threads the session + wallet headers, sets `X-PAYMENT`, and
1933
+ * accepted), threads the session + wallet headers, sets the x402 payment
1934
+ * header under the names that scheme requires (#2341), and
1892
1935
  * collapses an SSE JSON-RPC response to its `result`.
1893
1936
  */
1894
1937
  /**
1895
1938
  * Wait for a payment's Safe→delegate funding tx to reach ≥1 on-chain
1896
1939
  * confirmation. The hosted x402 completion path MUST call this after funding
1897
- * and before delivering the X-PAYMENT header, so the merchant's
1940
+ * and before delivering the merchant payment header, so the merchant's
1898
1941
  * balanceOf(delegate) / transferWithAuthorization verification sees the funded
1899
1942
  * balance — otherwise it rejects with "Payment verification failed". The
1900
1943
  * SDK's local path already does this (see `X402FundingLeg.authorize`); the hosted
@@ -1935,6 +1978,21 @@ declare class HavenClient {
1935
1978
  body: unknown;
1936
1979
  settlementTxHash?: string;
1937
1980
  }>;
1981
+ /**
1982
+ * #2292: report the outcome of a merchant retry the AGENT performed.
1983
+ *
1984
+ * The hosted `haven_complete_mcp_tool` / `completeX402MerchantCall` path is
1985
+ * for merchants Haven calls itself. On the plain-HTTP x402 path Haven never
1986
+ * talks to the merchant, so the outcome of that retry had no way back —
1987
+ * see `MerchantCompletion.reportMerchantOutcome` for what is verified about
1988
+ * a caller-asserted report and what deliberately is not.
1989
+ */
1990
+ reportX402MerchantOutcome(input: {
1991
+ paymentId: string;
1992
+ outcome: X402MerchantOutcome;
1993
+ merchantStatus: number;
1994
+ merchantBody?: string;
1995
+ }): Promise<X402MerchantOutcomeReport>;
1938
1996
  /**
1939
1997
  * GET /x402/:id/merchant-call-context — the settle-leg twin of #1263's
1940
1998
  * sign-context fetch (#1307). Re-serves the stored merchant MCP-tool call
@@ -2113,12 +2171,12 @@ declare const toolDescriptions: {
2113
2171
  readonly payX402OneShot: {
2114
2172
  readonly summary: "Fetch an x402 paid HTTP resource in a single call. Handles the full probe -> pay -> retry round trip and returns the merchant response.";
2115
2173
  readonly selectionGuidance: "Prefer this over the quote+pay split when the agent just wants the paid resource and does not need to inspect the price first. If you already have a quote from haven_quote_x402, use haven_pay_x402_quote instead. Do not use for read-only allowance, budget, spend-limit, remaining-amount, reset-period, or what-can-I-spend questions; use the allowance lookup tool instead.";
2116
- readonly behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the payment locally, then retries the original request with the X-PAYMENT header and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later. If the resource returns a non-402 status, returns it unchanged without contacting Haven.";
2174
+ readonly behavior: "Calls the URL, parses any HTTP 402 x402 challenge, signs the payment locally, then retries the original request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only) and returns the merchant response. Settlement is either direct account-to-merchant with no funding leg, or a bridge that first redeems the agent's budget delegation to fund the delegate wallet for an EIP-3009 authorization. A payment outside the on-chain budget is declined before any money moves; nothing is queued for a human to approve later. If the resource returns a non-402 status, returns it unchanged without contacting Haven.";
2117
2175
  readonly nextActionGuidance: string;
2118
2176
  };
2119
2177
  readonly resumeX402: {
2120
2178
  readonly summary: "Resume an x402 payment whose Haven-side authorization already succeeded but whose merchant retry did not complete.";
2121
- readonly behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the authorized Haven funding, and retries the merchant request with the X-PAYMENT header. No new Haven payment is created.";
2179
+ readonly behavior: "Accepts either resume_state or payment_id, validates the original x402 details against the authorized Haven funding, and retries the merchant request with the signed payment header (sent under PAYMENT-SIGNATURE, plus the legacy X-PAYMENT on the EIP-3009 path only). No new Haven payment is created.";
2122
2180
  readonly nextActionGuidance: string;
2123
2181
  };
2124
2182
  readonly getPaymentStatus: {
@@ -2207,7 +2265,7 @@ type SharedToolKey = keyof typeof toolDescriptions;
2207
2265
  * this canonical string and asserts byte-for-byte equality, so the two copies
2208
2266
  * cannot drift.
2209
2267
  */
2210
- 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; a payment above the remaining budget is declined \u2014\nnothing is paid past the rules the user set.\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.\nThat namespacing is Claude-family; other runtimes name the servers by their\nown config keys (Codex: `haven`, `haven_signer`). Tool results carry the\nexact next step (`next_action`, `next_tool`, `next_arguments`, plus the\nruntime-neutral `next_tool_server` + `next_tool_name` \u2014 the bare tool name\non that logical server, whatever your runtime calls it).\nFollow those fields first; the prose below is fallback and orientation, not\nthe 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 `spend_authority_readiness` (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot. That signal\n covers hosted identity and on-chain spend authority only \u2014 it cannot see the\n local signer; the signer is verified by calling any signer tool.\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 declined before any money moves \u2014 tell the user; they can raise\nthe budget in the Haven dashboard, or wait for the period reset.\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. If the user needs the live price before authorizing a cap, call\n `mcp__haven__haven_quote_catalog_purchase` with `catalog_id`. It is\n read-only and informational only: it never reserves a price or creates a\n payment. Tell the user its `amount` / `amount_atomic`, then choose a cap.\n3. `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.)\n4. 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 has not confirmed \u2014 follow the result's guidance fields and check\nstatus later, do 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`): if the user needs the live price before choosing a cap, first\ncall `mcp__haven__haven_quote_mcp_tool` with that merchant URL, tool name,\nand arguments. It is informational only; then call\n`mcp__haven__haven_pay_mcp_tool` with the same inputs and the explicit cap.\nThe paid call always obtains a fresh quote before it creates any intent. Then\ncontinue `mcp__haven__haven_pay_mcp_tool` \u2192\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 and sign in the local Haven signer. The pay tool performs the merchant\nretry itself, so do not wait on a signal while it runs. If the process\ncrashes after payment, a later `mcp__haven__haven_get_payment_status` call\nmay report `nextAction: 'retry_original_x402_request'` \u2014 only then call\n`mcp__haven__haven_resume_x402_payment` with the preserved resume state or\npayment id, instead of paying again.\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 a read-only quote or the pay-tool\nresult, never a catalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. A read-only quote is informational\nonly and does not reserve a price; the later paid call re-quotes and enforces\nthe cap. The pay-tool result's `amount` / `amount_atomic` is the amount\nHaven authorizes for that call \u2014 a ceiling the merchant settles at or below \u2014\nso 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 in-flight payments. Do not poll in a tight loop.\n\n## Declines and stop signals\n\n- A payment outside the agent's rules \u2014 above the remaining budget, wrong\n recipient, or expired budget \u2014 is declined before any money moves. Nothing\n is queued; tell the user, who can raise the budget in Haven.\n- `safe_to_continue: false` on a guidance block is a stop 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- `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";
2268
+ 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; a payment above the remaining budget is declined \u2014\nnothing is paid past the rules the user set.\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.\nThat namespacing is Claude-family; other runtimes name the servers by their\nown config keys (Codex: `haven`, `haven_signer`). Tool results carry the\nexact next step (`next_action`, `next_tool`, `next_arguments`, plus the\nruntime-neutral `next_tool_server` + `next_tool_name` \u2014 the bare tool name\non that logical server, whatever your runtime calls it).\nFollow those fields first; the prose below is fallback and orientation, not\nthe 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 `spend_authority_readiness` (`ready` / `needs_approval` /\n `revoked`) and live remaining per-token allowance, in one shot. That signal\n covers hosted identity and on-chain spend authority only \u2014 it cannot see the\n local signer; the signer is verified by calling any signer tool.\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 declined before any money moves \u2014 tell the user; they can raise\nthe budget in the Haven dashboard, or wait for the period reset.\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. If the user needs the live price before authorizing a cap, call\n `mcp__haven__haven_quote_catalog_purchase` with `catalog_id`. It is\n read-only and informational only: it never reserves a price or creates a\n payment. Tell the user its `amount` / `amount_atomic`, then choose a cap.\n3. `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.)\n4. 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 has not confirmed \u2014 follow the result's guidance fields and check\nstatus later, do 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`): if the user needs the live price before choosing a cap, first\ncall `mcp__haven__haven_quote_mcp_tool` with that merchant URL, tool name,\nand arguments. It is informational only; then call\n`mcp__haven__haven_pay_mcp_tool` with the same inputs and the explicit cap.\nThe paid call always obtains a fresh quote before it creates any intent. Then\ncontinue `mcp__haven__haven_pay_mcp_tool` \u2192\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`. Call that last step with\n`payment_id` and the signer's `payment_header` ONLY. It does not take\n`payment_required`: Haven rehydrates the merchant call context\n(`merchant_url`, `tool_name`, `arguments`, `mcp_transport`) and the\n402 server-side from `payment_id`, exactly as at settle. Pass that context\nexplicitly only as a version-skew fallback when Haven has no stored context\nfor the id \u2014 `merchant_url` and `tool_name` both or none together, never\njust one.\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 and sign in the local Haven signer. On THIS path Haven does not talk to\nthe merchant: `mcp__haven-signer__haven_sign_x402` returns both\n`signature` and `payment_header`; relay `signature` with\n`mcp__haven__haven_submit`, then retry the paywalled URL yourself with\n`payment_header`. Do not pass that call's `x402_binding` to\n`mcp__haven-signer__haven_x402_sign_header` \u2014 the one-shot already spent it\nbuilding the header, so the call can only refuse. Then tell Haven what the\nmerchant answered: `mcp__haven__haven_report_x402_outcome` with the\n`payment_id`, `outcome` (`\"accepted\"` for a 2xx, else `\"rejected\"`)\nand the `merchant_status` you got. Because Haven never contacted that\nmerchant, this is the only way it can learn the purchase failed \u2014 without it a\nfailed purchase reads as complete for fifteen minutes. (The SDK's own\n`haven_pay_x402` tool does perform the merchant retry itself; that tool is\nnot part of the hosted MCP surface.) If the process\ncrashes after payment, a later `mcp__haven__haven_get_payment_status` call\nmay report `nextAction: 'retry_original_x402_request'` \u2014 only then call\n`mcp__haven__haven_resume_x402_payment` with the preserved resume state or\npayment id, instead of paying again.\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 a read-only quote or the pay-tool\nresult, never a catalog price. `haven_discover_tools` prices are indicative\n(`price_is_indicative`) and can be stale. A read-only quote is informational\nonly and does not reserve a price; the later paid call re-quotes and enforces\nthe cap. The pay-tool result's `amount` / `amount_atomic` is the merchant's\nown quoted price for that call \u2014 a ceiling the merchant settles at or below \u2014\nso present it as the most the user will pay. It is a price, not an approval:\nthe payment goes through only if it also fits the cap you set and the on-chain\nbudget the user signed, which is enforced on-chain rather than by Haven.\n\n**Status:** `mcp__haven__haven_get_payment_status` with a `payment_id` to\ncheck on in-flight payments. Do not poll in a tight loop.\n\n## Declines and stop signals\n\n- A payment outside the agent's rules \u2014 above the remaining budget, wrong\n recipient, or expired budget \u2014 is declined before any money moves. Nothing\n is queued; tell the user, who can raise the budget in Haven.\n- `safe_to_continue: false` on a guidance block is a stop 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- `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";
2211
2269
  /** Directory name for the installed skill folder. */
2212
2270
  declare const SKILL_FOLDER_NAME = "haven-pay";
2213
2271
  /**
@@ -2351,6 +2409,66 @@ declare const X402_MAX_AUTHORIZATION_WINDOW_SECONDS = 600;
2351
2409
  */
2352
2410
  declare const X402_SETTLEMENT_FORWARD_MARGIN_SECONDS = 300;
2353
2411
  declare function normalizePaymentRequired(value: unknown): X402PaymentRequired | null;
2412
+ /**
2413
+ * The x402 wire header names, in one place (#2289).
2414
+ *
2415
+ * v2 renamed all three; v1's only name was `X-PAYMENT`, used in BOTH
2416
+ * directions. Haven had adopted the v2 names for everything it *reads* and
2417
+ * kept the v1 name for the one thing it *writes*, which is how a strict v2
2418
+ * merchant came to never see a payment header at all.
2419
+ *
2420
+ * The 2026-08-31 owner decision was to send both outbound names on every
2421
+ * retry rather than switch on `x402Version`: a v1 merchant ignores the name it
2422
+ * does not know, a v2 merchant ignores the legacy one, and no version
2423
+ * heuristic has to be right for a payment to land.
2424
+ *
2425
+ * **That is no longer unconditional (#2341).** It held while the cost of a
2426
+ * spare header was zero, and on the EIP-3009 bridge it still is. On erc7710 it
2427
+ * is not: that header carries a whole delegation chain, and duplicating it
2428
+ * overflowed the merchant's header limit — HTTP 431, every erc7710 settlement
2429
+ * refused. `x402PaymentHeaderNamesFor` below is the live rule; read it rather
2430
+ * than this paragraph, which records why the simpler rule was right first.
2431
+ */
2432
+ /** v2 client→server payment payload. The name a strict v2 merchant reads. */
2433
+ declare const X402_PAYMENT_HEADER_NAME = "PAYMENT-SIGNATURE";
2434
+ /** v1 client→server payment payload; still accepted by most v2 merchants. */
2435
+ declare const X402_LEGACY_PAYMENT_HEADER_NAME = "X-PAYMENT";
2436
+ /** v2 server→client payment requirements. */
2437
+ declare const X402_PAYMENT_REQUIRED_HEADER_NAME = "PAYMENT-REQUIRED";
2438
+ /** v2 server→client settlement receipt. */
2439
+ declare const X402_PAYMENT_RESPONSE_HEADER_NAME = "PAYMENT-RESPONSE";
2440
+ /**
2441
+ * Both wire names, v2 first — the value an EIP-3009 retry actually sends.
2442
+ *
2443
+ * **Not the general answer any more (#2341), and not what a recorder should
2444
+ * reach for.** This was the evidence record's `paymentProofHeaderName` while
2445
+ * both names always went on the wire; erc7710 now sends one, so a recorder
2446
+ * still reading this constant would log a legacy header that was never sent —
2447
+ * exactly the drift the previous wording promised it prevented. Use
2448
+ * `x402PaymentHeaderNamesSent(paymentHeader)`. Kept exported because it is a
2449
+ * published surface and removing it would break consumers.
2450
+ */
2451
+ declare const X402_PAYMENT_HEADER_NAMES_SENT = "PAYMENT-SIGNATURE, X-PAYMENT";
2452
+ /**
2453
+ * The x402 v2 payment envelope: `{x402Version, resource?, accepted, payload,
2454
+ * extensions?}` per the spec's PaymentPayload (§5.2.2).
2455
+ *
2456
+ * The `resource` and `extensions` echoes are the #2361 fix, and they are not
2457
+ * optional politeness: the spec makes the extensions echo a MUST ("the client
2458
+ * must include at least the info received"), and CoinGecko's facilitator was
2459
+ * live-bisected rejecting the echo-less envelope with a bare 400 while
2460
+ * accepting the identical signature and `accepted`/`payload` bytes with the
2461
+ * echoes added (#2360, Base mainnet, 2026-09-01). Both objects are echoed
2462
+ * VERBATIM from the merchant's 402 — never reconstructed — and omitted when
2463
+ * the challenge carries none, which keeps the envelope byte-identical to the
2464
+ * pre-#2361 shape for echo-less merchants (Ampersend and Soundside settled
2465
+ * that shape live, so omission is the proven-compatible default).
2466
+ *
2467
+ * The `accepted` wrap itself is #303's shape and predates this helper — see
2468
+ * the #300/#303 history before "fixing" it: scheme/network live INSIDE
2469
+ * `accepted` in v2, never at the top level.
2470
+ */
2471
+ declare function x402V2PaymentEnvelope(paymentRequired: Pick<X402PaymentRequired, 'x402Version' | 'resource' | 'extensions'>, accepted: X402PaymentOption, payload: unknown): Record<string, unknown>;
2354
2472
  /**
2355
2473
  * Parse an HTTP 402 response into x402 PaymentRequired data.
2356
2474
  *
@@ -2445,9 +2563,10 @@ interface X402SchemeSelection {
2445
2563
  * caller's to supply — the SDK cannot see which rail an account is on from a
2446
2564
  * 402 response alone. A legacy AllowanceModule account passing
2447
2565
  * `delegationRail: true` would select a scheme its account cannot settle; the
2448
- * backend refuses that at authorize (`validateGenericSchemeRail`), which is
2449
- * where a rail mismatch SHOULD fail, on-chain-adjacent rather than in a client
2450
- * that could be lying to itself.
2566
+ * backend refuses that at authorize with the #1986 retired-rail 410 (#2245 —
2567
+ * previously a scheme-specific 400 that wrongly implied the legacy rail could
2568
+ * still settle via EIP-3009), which is where a rail mismatch SHOULD fail,
2569
+ * on-chain-adjacent rather than in a client that could be lying to itself.
2451
2570
  *
2452
2571
  * Returns `null` when neither scheme has a payable entry — the caller decides
2453
2572
  * whether that is an error or a reason to look elsewhere.
@@ -2577,4 +2696,4 @@ declare function discoverMerchantMcpUrl(inputUrl: string): Promise<string | null
2577
2696
  /** Trailing-slash/percent-case echoes compare equal; unparseable never does. */
2578
2697
  declare function sameUrl(a: string, b: string): boolean;
2579
2698
 
2580
- 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 CatalogSubmissionAccepted, type ClaudeTool, DEFAULT_CONFIRMATION_TIMEOUT_MS, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, type HavenCatalogSubmission, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, 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 SweepConfirmation, 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, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses };
2699
+ 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 CatalogSubmissionAccepted, type ClaudeTool, DEFAULT_CONFIRMATION_TIMEOUT_MS, DISCOVERY_MAX_BYTES, ERC7710_ASSET_TRANSFER_METHOD, HAVEN_MINIMUM_NODE_VERSION, HAVEN_SKILL_BODY_MD, HAVEN_SKILL_MD, type HavenAgent, type HavenAgentAllowanceSummary, type HavenAgentReadiness, type HavenAgentSummary, type HavenAllowance, type HavenAllowanceSummary, HavenApiError, type HavenCatalogEntry, type HavenCatalogSubmission, HavenClient, type HavenClientConfig, HavenError, type HavenPaymentReceipt, HavenPaymentStateError, HavenSigningError, HavenTimeoutError, HavenUnsupportedSignerVersionError, MERCHANT_DISCOVERY_PATHS, type MachinePaymentRail, MerchantTimeoutError, type OpenAITool, type PaymentFee, type PaymentIntent, type PaymentNextAction, type PaymentPhase, type PaymentReceipt, type PaymentRequest, type PaymentResult, type PaymentResumeState, type PaymentStatus, type PaymentStatusResult, type PostPurchaseAllowanceSummary, RECEIPT_VERSION, type ReceiptVerification, type ResumeAuthorizedX402Input, 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 SweepConfirmation, 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, X402AlreadySettledError, type X402AuthorizationOptions, type X402Erc7710Settlement, type X402ExpectedAuth, type X402ExpectedContext, type X402Intent, type X402McpCallContext, type X402McpTransport, type X402MerchantCallContext, type X402MerchantOutcome, type X402MerchantOutcomeReport, type X402PaymentHeaderContext, X402PaymentHeaderValidationError, type X402PaymentOption, type X402PaymentRequired, type X402Quote, type X402Receipt, type X402RequestSnapshot, type X402ResumeState, type X402SchemeSelection, X402UnexpectedStatusError, X402_LEGACY_PAYMENT_HEADER_NAME, X402_MAX_AUTHORIZATION_WINDOW_SECONDS, X402_PAYMENT_HEADER_NAME, X402_PAYMENT_HEADER_NAMES_SENT, X402_PAYMENT_REQUIRED_HEADER_NAME, X402_PAYMENT_RESPONSE_HEADER_NAME, X402_SETTLEMENT_FORWARD_MARGIN_SECONDS, addressFromKey, buildSweepAuthorizationMessage, buildSweepTypedData, buildX402ExpectedMessage, compareNodeVersions, composeDescription, decodeBase64Json, decodeBase64Utf8, discoverMerchantMcpUrl, encodeBase64Json, encodeBase64Utf8, encodePaymentProof, havenTools, isErc7710Option, isSupportedNodeVersion, isSweepableChain, normalizePaymentRequired, parsePaymentRequired, parsePaymentRequiredResponse, resolveTokenFromAddress, sameUrl, selectErc7710PaymentOption, selectPaymentOption, selectStandardPaymentOption, selectX402SettlementScheme, signHash, signUserOpTypedDataForDelegation, sweepUsdcAddress, sweepUsdcDomain, toStandardPaymentRequirements, toolDescriptions, unsupportedNodeVersionMessage, validateStandardX402PaymentHeader, verifyPaymentReceipt, verifySignature, x402AssetTransferMethod, x402AuthorizationAmount, x402FacilitatorAddresses, x402V2PaymentEnvelope };