@conto_finance/sdk 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # @conto_finance/sdk
2
2
 
3
+ Conto is a buyer-side control layer. Integrate it in the agent owner's runtime or payment tools;
4
+ the owner or budget holder sets policy before the agent pays.
5
+ See [buyer-side control](https://conto.finance/docs/guides/buyer-side-control) for the authorization
6
+ and execution boundary.
7
+
3
8
  TypeScript SDK for Conto. Use it when you control the agent runtime and want typed access to
4
9
  payment requests, payment execution, and organization-level provisioning.
5
10
 
@@ -95,34 +100,9 @@ await admin.cards.revokeFromAgent('agent_id', card.id);
95
100
  ```
96
101
 
97
102
  The policy overlay stops at approval, claiming, and reconciliation. For a
98
- customer-hosted payment tool that gates access to customer payment code, use the
99
- separate
100
- [`@conto_finance/card-access`](https://conto.finance/docs/card-access/overview) product
101
- package.
102
-
103
- ```typescript
104
- import { ContoCardAccess } from '@conto_finance/card-access';
105
-
106
- const cardAccess = new ContoCardAccess({
107
- policy: conto.cards,
108
- integrationId: 'procurement-agent-production',
109
- deployment: {
110
- credentialCustody: 'CUSTOMER',
111
- agentHasRawCredentialAccess: false,
112
- uncontrolledAgentPaymentPath: false,
113
- },
114
- executor: customerHostedExecutor,
115
- });
116
- ```
117
-
118
- Card Access claims each approved request exactly once before the executor can run. A
119
- duplicate or uncertain claim cannot invoke the executor again. It remains
120
- bypassable if another person or tool can access the card, and results are
121
- self-reported rather than issuer-verified. The executor receives the normalized
122
- purchase `idempotencyKey`; pass it to the payment processor so ambiguous
123
- processor responses cannot create duplicate charges. The legacy `conto.cards.controlled()`
124
- helper remains available for compatibility, but new customer-hosted enforcement
125
- should use the standalone Card Access package. Use
103
+ customer-hosted payment tool that gates access to customer payment code, see
104
+ [Card Access](https://conto.finance/docs/card-access/overview), available on request.
105
+ The legacy `conto.cards.controlled()` helper remains available for compatibility. Use
126
106
  `admin.cards.listRequests({ status: 'EXECUTING' })` for reconciliation and
127
107
  `admin.cards.pause(card.id)` to revoke unclaimed grants and stop new approvals
128
108
  in the Conto-controlled path.
@@ -144,14 +124,16 @@ const result = await conto.payments.pay({
144
124
  ```typescript
145
125
  const paymentId = crypto.randomUUID();
146
126
 
147
- await conto.x402.preAuthorize({
127
+ const decision = await conto.x402.preAuthorize({
148
128
  amount: 0.01,
149
129
  recipientAddress: '0x...',
150
130
  resourceUrl: 'https://api.example.com/v1/search',
151
131
  paymentId,
152
132
  sessionId: 'session_123',
153
133
  });
134
+ if (!decision.authorized) throw new Error(decision.message);
154
135
 
136
+ // Sign and settle the x402 payment, then record it with the grant.
155
137
  await conto.x402.record({
156
138
  amount: 0.01,
157
139
  recipientAddress: '0x...',
@@ -159,18 +141,53 @@ await conto.x402.record({
159
141
  paymentId,
160
142
  txHash: '0x...',
161
143
  sessionId: 'session_123',
144
+ grantId: decision.grantId,
145
+ grantSignature: decision.grantSignature,
162
146
  });
163
147
 
164
148
  const budget = await conto.x402.budget();
165
149
  ```
166
150
 
151
+ An approved `preAuthorize` returns a single-use grant (`grantId`, `grantSignature`,
152
+ `grantExpiresAt`) for that wallet, recipient, and amount, and reserves the amount against the
153
+ agent's spend limits for 10 minutes. Pass the grant to `record`. A record without a valid,
154
+ unexpired grant is still accepted because the payment already settled, but Conto flags it as a
155
+ policy bypass and raises a critical alert. Organizations can also have the agent frozen
156
+ automatically. The record response then includes `policyBypass: true`, `bypassReason`, and
157
+ `agentFrozen`.
158
+
159
+ For a Privy-managed EVM wallet, `conto.x402.pay` replaces `preAuthorize`. Pass the same fields
160
+ plus the accepted 402 requirements; when approved, Conto signs the payment and returns the header
161
+ to retry with:
162
+
163
+ ```typescript
164
+ const paid = await conto.x402.pay({
165
+ amount: 0.01,
166
+ recipientAddress: requirements.payTo,
167
+ resourceUrl: 'https://api.example.com/v1/search',
168
+ paymentId,
169
+ paymentRequirements: requirements, // accepted entry from the 402 challenge
170
+ });
171
+ if (!paid.authorized) throw new Error(paid.message);
172
+
173
+ const response = await fetch('https://api.example.com/v1/search', {
174
+ headers: { [paid.paymentHeaderName!]: paid.xPaymentHeader! },
175
+ });
176
+ // Then record with paid.grantId, paid.grantSignature, and the settlement txHash.
177
+ ```
178
+
179
+ `pay` is not retried automatically: each grant is signed once, and a repeat returns
180
+ `GRANT_ALREADY_SIGNED`. External wallets get `MANAGED_SIGNING_UNAVAILABLE`.
181
+
167
182
  The MPP client mirrors the same shape with `conto.mpp.preAuthorize`, `conto.mpp.record`,
168
- `conto.mpp.budget`, and `conto.mpp.services`.
183
+ `conto.mpp.budget`, and `conto.mpp.services`. An MPP session grant is a ceiling: several
184
+ `record` calls with the same `sessionId` may draw it down until it is used up or expires.
169
185
 
170
- ## Stripe Link Checkout Commerce
186
+ ## Stripe Link Checkout Commerce (test only)
171
187
 
172
- For a merchant Conto controls, `LINK_CHECKOUT` evaluates policy before creating an ordinary
173
- Stripe-hosted Checkout Session with card and Link enabled. It needs no private Link SDK permission,
188
+ `LINK_CHECKOUT` is test-only and works only with a merchant enrolled with Conto. It is not a
189
+ general merchant integration. It evaluates policy before creating an ordinary Stripe-hosted
190
+ Checkout Session with card and Link enabled. It needs no private Link SDK permission,
174
191
  Link connection, saved payment-method ID, SPT, or LPT.
175
192
 
176
193
  Commerce execution responses separate the provider-neutral `executionChannel`, optional
@@ -224,15 +241,16 @@ fallback, surfaced as `actualPaymentMethod: 'CARD'`; it is a valid payment but n
224
241
  The read-only `getCommerceExecution` projection redacts action URLs; use the initial begin result or
225
242
  the `payments:confirm` refresh path while action remains required.
226
243
  The server resolves the exact merchant name, Stripe account, and return URLs from configuration, so
227
- the caller cannot redirect the approved purchase. This path controls only that merchant's Conto
228
- channel, not unrelated Checkout pages or the consumer's Link wallet. See
244
+ the caller cannot redirect the approved purchase. This path covers only that enrolled merchant's
245
+ Conto channel, not unrelated Checkout pages or the consumer's Link wallet. See
229
246
  `docs/STRIPE_LINK_CHECKOUT_ADAPTER.md` for configuration, webhook, drill, and reconciliation
230
247
  requirements.
231
248
 
232
249
  ## Agent checkout guard
233
250
 
234
- For arbitrary third-party merchants, use `runGuardedCheckout` with
235
- `executionMethod: 'BROWSER_CHECKOUT'`. It binds and atomically authorizes one exact Link, card,
251
+ For browser checkouts on supported rails (Link, card, Shop Pay, or PayPal), use
252
+ `runGuardedCheckout` with `executionMethod: 'BROWSER_CHECKOUT'`. Other rails and checkout flows are
253
+ not covered. It binds and atomically authorizes one exact Link, card,
236
254
  Shop Pay, or PayPal browser action without requiring merchant or private provider integration. The
237
255
  privileged browser executor must be available only through this wrapper; an unrestricted click or
238
256
  payment tool would bypass the control. Persist its stable dispatch attempt before calling the helper; it owns authorization,
@@ -502,7 +520,9 @@ The SDK automatically adds an idempotency key to wallet payment authorization
502
520
  requests. Provide your own stable `idempotencyKey` when a retry may happen in
503
521
  another process or job attempt. External-card approvals always require a stable
504
522
  caller-supplied `idempotencyKey`; card approval and confirmation are safe to
505
- retry. x402 and MPP pre-authorization calls are non-mutating policy checks.
523
+ retry. x402 and MPP pre-authorization calls issue a grant and reserve spend. A retry
524
+ with the same `paymentId` (x402) or `challengeId`/`credentialId` (MPP) returns the
525
+ same live grant instead of reserving again.
506
526
  Record calls require an explicit stable `paymentId` or `credentialId` so an
507
527
  ambiguous failure can be reconciled safely.
508
528
 
@@ -2,6 +2,8 @@ import { Browser } from 'playwright-core';
2
2
  import { GuardedPlaywrightCheckoutHttpHandler, PlaywrightSessionObservation, GuardedPlaywrightCheckoutClient, PlaywrightCdpSessionRegistryConfig, EncryptedPlaywrightCheckoutTargetStoreConfig, GuardedPlaywrightCheckoutRuntimeConfig } from './playwright.mjs';
3
3
  import './index.mjs';
4
4
 
5
+ /** Exact provider endpoints verified against Browserbase's session API; never use a wildcard. */
6
+ declare const BROWSERBASE_CONNECT_ORIGINS: readonly string[];
5
7
  type BrowserbaseSessionStatus = 'PENDING' | 'RUNNING' | 'ERROR' | 'TIMED_OUT' | 'COMPLETED';
6
8
  type BrowserbaseSessionBindingState = 'ACTIVE' | 'REVOKED';
7
9
  type BrowserbaseSessionLifecycleOwner = 'CONTO_RUNTIME' | 'AGENT_HOST';
@@ -128,12 +130,23 @@ declare class BrowserbaseSessionError extends Error {
128
130
  readonly code: BrowserbaseSessionErrorCode;
129
131
  constructor(code: BrowserbaseSessionErrorCode, message: string);
130
132
  }
133
+ interface BrowserbaseSessionManager {
134
+ createSession(): Promise<BrowserbaseOwnedSession>;
135
+ attachSession(input: BrowserbaseSessionHandoff): Promise<BrowserbaseAttachedSession>;
136
+ connectUrlForSession(browserSessionId: string): Promise<string | null>;
137
+ liveViewForSession(browserSessionId: string): Promise<BrowserbaseOwnedLiveView>;
138
+ revokeSession(browserSessionId: string, lifecycleOwner: BrowserbaseSessionLifecycleOwner): Promise<boolean>;
139
+ releaseProviderSession(browserSessionId: string): Promise<void>;
140
+ releaseContextLease(browserSessionId: string): Promise<boolean>;
141
+ }
131
142
  /** Creates a short-lived assertion after the trusted agent host creates its Browserbase session. */
132
143
  declare function createBrowserbaseSessionHandoffAssertion(input: BrowserbaseSessionHandoffAssertionInput, keyValue: Uint8Array): string;
144
+ /** Server-only capability. Never expose connect URLs or this manager as agent tools. */
145
+ declare function createBrowserbaseSessionManager(config: BrowserbaseSessionConfig): BrowserbaseSessionManager;
133
146
  /**
134
147
  * Creates the recommended Browserbase deployment boundary. Provider lifecycle, ownership checks,
135
148
  * remote connection resolution, guarded execution, and cleanup remain in one privileged object.
136
149
  */
137
150
  declare function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config: BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig): BrowserbaseGuardedPlaywrightCheckoutRuntimeHost;
138
151
 
139
- export { type BrowserbaseAttachedSession, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, type BrowserbaseOwnedLiveView, type BrowserbaseOwnedSession, type BrowserbaseSessionBinding, type BrowserbaseSessionBindingState, type BrowserbaseSessionBindingStore, type BrowserbaseSessionConfig, BrowserbaseSessionError, type BrowserbaseSessionErrorCode, type BrowserbaseSessionHandoff, type BrowserbaseSessionHandoffAssertionInput, type BrowserbaseSessionLifecycleOwner, type BrowserbaseSessionStatus, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion };
152
+ export { BROWSERBASE_CONNECT_ORIGINS, type BrowserbaseAttachedSession, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, type BrowserbaseOwnedLiveView, type BrowserbaseOwnedSession, type BrowserbaseSessionBinding, type BrowserbaseSessionBindingState, type BrowserbaseSessionBindingStore, type BrowserbaseSessionConfig, BrowserbaseSessionError, type BrowserbaseSessionErrorCode, type BrowserbaseSessionHandoff, type BrowserbaseSessionHandoffAssertionInput, type BrowserbaseSessionLifecycleOwner, type BrowserbaseSessionManager, type BrowserbaseSessionStatus, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion, createBrowserbaseSessionManager };
@@ -2,6 +2,8 @@ import { Browser } from 'playwright-core';
2
2
  import { GuardedPlaywrightCheckoutHttpHandler, PlaywrightSessionObservation, GuardedPlaywrightCheckoutClient, PlaywrightCdpSessionRegistryConfig, EncryptedPlaywrightCheckoutTargetStoreConfig, GuardedPlaywrightCheckoutRuntimeConfig } from './playwright.js';
3
3
  import './index.js';
4
4
 
5
+ /** Exact provider endpoints verified against Browserbase's session API; never use a wildcard. */
6
+ declare const BROWSERBASE_CONNECT_ORIGINS: readonly string[];
5
7
  type BrowserbaseSessionStatus = 'PENDING' | 'RUNNING' | 'ERROR' | 'TIMED_OUT' | 'COMPLETED';
6
8
  type BrowserbaseSessionBindingState = 'ACTIVE' | 'REVOKED';
7
9
  type BrowserbaseSessionLifecycleOwner = 'CONTO_RUNTIME' | 'AGENT_HOST';
@@ -128,12 +130,23 @@ declare class BrowserbaseSessionError extends Error {
128
130
  readonly code: BrowserbaseSessionErrorCode;
129
131
  constructor(code: BrowserbaseSessionErrorCode, message: string);
130
132
  }
133
+ interface BrowserbaseSessionManager {
134
+ createSession(): Promise<BrowserbaseOwnedSession>;
135
+ attachSession(input: BrowserbaseSessionHandoff): Promise<BrowserbaseAttachedSession>;
136
+ connectUrlForSession(browserSessionId: string): Promise<string | null>;
137
+ liveViewForSession(browserSessionId: string): Promise<BrowserbaseOwnedLiveView>;
138
+ revokeSession(browserSessionId: string, lifecycleOwner: BrowserbaseSessionLifecycleOwner): Promise<boolean>;
139
+ releaseProviderSession(browserSessionId: string): Promise<void>;
140
+ releaseContextLease(browserSessionId: string): Promise<boolean>;
141
+ }
131
142
  /** Creates a short-lived assertion after the trusted agent host creates its Browserbase session. */
132
143
  declare function createBrowserbaseSessionHandoffAssertion(input: BrowserbaseSessionHandoffAssertionInput, keyValue: Uint8Array): string;
144
+ /** Server-only capability. Never expose connect URLs or this manager as agent tools. */
145
+ declare function createBrowserbaseSessionManager(config: BrowserbaseSessionConfig): BrowserbaseSessionManager;
133
146
  /**
134
147
  * Creates the recommended Browserbase deployment boundary. Provider lifecycle, ownership checks,
135
148
  * remote connection resolution, guarded execution, and cleanup remain in one privileged object.
136
149
  */
137
150
  declare function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config: BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig): BrowserbaseGuardedPlaywrightCheckoutRuntimeHost;
138
151
 
139
- export { type BrowserbaseAttachedSession, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, type BrowserbaseOwnedLiveView, type BrowserbaseOwnedSession, type BrowserbaseSessionBinding, type BrowserbaseSessionBindingState, type BrowserbaseSessionBindingStore, type BrowserbaseSessionConfig, BrowserbaseSessionError, type BrowserbaseSessionErrorCode, type BrowserbaseSessionHandoff, type BrowserbaseSessionHandoffAssertionInput, type BrowserbaseSessionLifecycleOwner, type BrowserbaseSessionStatus, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion };
152
+ export { BROWSERBASE_CONNECT_ORIGINS, type BrowserbaseAttachedSession, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHost, type BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig, type BrowserbaseOwnedLiveView, type BrowserbaseOwnedSession, type BrowserbaseSessionBinding, type BrowserbaseSessionBindingState, type BrowserbaseSessionBindingStore, type BrowserbaseSessionConfig, BrowserbaseSessionError, type BrowserbaseSessionErrorCode, type BrowserbaseSessionHandoff, type BrowserbaseSessionHandoffAssertionInput, type BrowserbaseSessionLifecycleOwner, type BrowserbaseSessionManager, type BrowserbaseSessionStatus, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion, createBrowserbaseSessionManager };
@@ -20,9 +20,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/browserbase.ts
21
21
  var browserbase_exports = {};
22
22
  __export(browserbase_exports, {
23
+ BROWSERBASE_CONNECT_ORIGINS: () => BROWSERBASE_CONNECT_ORIGINS,
23
24
  BrowserbaseSessionError: () => BrowserbaseSessionError,
24
25
  createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost: () => createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost,
25
- createBrowserbaseSessionHandoffAssertion: () => createBrowserbaseSessionHandoffAssertion
26
+ createBrowserbaseSessionHandoffAssertion: () => createBrowserbaseSessionHandoffAssertion,
27
+ createBrowserbaseSessionManager: () => createBrowserbaseSessionManager
26
28
  });
27
29
  module.exports = __toCommonJS(browserbase_exports);
28
30
  var import_node_crypto3 = require("crypto");
@@ -1382,7 +1384,10 @@ function createGuardedPlaywrightCheckoutHttpHandler(config) {
1382
1384
 
1383
1385
  // src/browserbase.ts
1384
1386
  var BROWSERBASE_API_ORIGIN = "https://api.browserbase.com";
1385
- var BROWSERBASE_CONNECT_ORIGIN = "wss://connect.browserbase.com";
1387
+ var BROWSERBASE_CONNECT_ORIGINS = Object.freeze([
1388
+ "wss://connect.browserbase.com",
1389
+ "wss://connect.usw2.browserbase.com"
1390
+ ]);
1386
1391
  var BROWSERBASE_LIVE_VIEW_DOMAIN = "browserbase.com";
1387
1392
  var DEFAULT_SESSION_TIMEOUT_SECONDS = 900;
1388
1393
  var MIN_SESSION_TIMEOUT_SECONDS = 60;
@@ -1508,7 +1513,7 @@ function secureConnectUrl(value) {
1508
1513
  const normalized = providerText(value, "connectUrl", 4096);
1509
1514
  try {
1510
1515
  const url = new URL(normalized);
1511
- if (url.protocol !== "wss:" || url.origin !== BROWSERBASE_CONNECT_ORIGIN || url.username || url.password || url.hash) {
1516
+ if (url.protocol !== "wss:" || !BROWSERBASE_CONNECT_ORIGINS.includes(url.origin) || url.username || url.password || url.hash) {
1512
1517
  throw new Error("unsafe Browserbase connect URL");
1513
1518
  }
1514
1519
  return url.toString();
@@ -1568,7 +1573,9 @@ function parseProviderSession(value, expectedProjectId, expectedSessionId) {
1568
1573
  status,
1569
1574
  createdAt,
1570
1575
  expiresAt,
1571
- connectUrl: secureConnectUrl(record.connectUrl)
1576
+ // Completed sessions need not retain a connection capability. Validate it
1577
+ // only for active states; identity and timestamps above still must match.
1578
+ connectUrl: status === "PENDING" || status === "RUNNING" ? secureConnectUrl(record.connectUrl) : null
1572
1579
  });
1573
1580
  }
1574
1581
  async function readProviderJson(response) {
@@ -1664,11 +1671,13 @@ function createBrowserbaseSessionManager(config) {
1664
1671
  projectId,
1665
1672
  timeout: durationSeconds,
1666
1673
  keepAlive: true,
1667
- ...contextId ? {
1668
- browserSettings: {
1669
- context: { id: contextId, persist: true }
1670
- }
1671
- } : {}
1674
+ proxies: false,
1675
+ browserSettings: {
1676
+ recordSession: false,
1677
+ logSession: false,
1678
+ solveCaptchas: false,
1679
+ ...contextId ? { context: { id: contextId, persist: true } } : {}
1680
+ }
1672
1681
  })
1673
1682
  });
1674
1683
  if (response.status !== 201) {
@@ -1911,7 +1920,7 @@ function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config) {
1911
1920
  const host = createGuardedPlaywrightCheckoutRuntimeHost({
1912
1921
  conto: config.conto,
1913
1922
  browserSessions: {
1914
- allowedConnectOrigins: [BROWSERBASE_CONNECT_ORIGIN],
1923
+ allowedConnectOrigins: BROWSERBASE_CONNECT_ORIGINS,
1915
1924
  connectUrlForSession: manager.connectUrlForSession,
1916
1925
  connectOverCDP: config.connectOverCDP,
1917
1926
  selectPage: config.selectPage,
@@ -1974,7 +1983,9 @@ function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config) {
1974
1983
  }
1975
1984
  // Annotate the CommonJS export names for ESM import in node:
1976
1985
  0 && (module.exports = {
1986
+ BROWSERBASE_CONNECT_ORIGINS,
1977
1987
  BrowserbaseSessionError,
1978
1988
  createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost,
1979
- createBrowserbaseSessionHandoffAssertion
1989
+ createBrowserbaseSessionHandoffAssertion,
1990
+ createBrowserbaseSessionManager
1980
1991
  });
@@ -7,7 +7,10 @@ import "./chunk-B7F5QLE5.mjs";
7
7
  // src/browserbase.ts
8
8
  import { createHmac, timingSafeEqual } from "crypto";
9
9
  var BROWSERBASE_API_ORIGIN = "https://api.browserbase.com";
10
- var BROWSERBASE_CONNECT_ORIGIN = "wss://connect.browserbase.com";
10
+ var BROWSERBASE_CONNECT_ORIGINS = Object.freeze([
11
+ "wss://connect.browserbase.com",
12
+ "wss://connect.usw2.browserbase.com"
13
+ ]);
11
14
  var BROWSERBASE_LIVE_VIEW_DOMAIN = "browserbase.com";
12
15
  var DEFAULT_SESSION_TIMEOUT_SECONDS = 900;
13
16
  var MIN_SESSION_TIMEOUT_SECONDS = 60;
@@ -133,7 +136,7 @@ function secureConnectUrl(value) {
133
136
  const normalized = providerText(value, "connectUrl", 4096);
134
137
  try {
135
138
  const url = new URL(normalized);
136
- if (url.protocol !== "wss:" || url.origin !== BROWSERBASE_CONNECT_ORIGIN || url.username || url.password || url.hash) {
139
+ if (url.protocol !== "wss:" || !BROWSERBASE_CONNECT_ORIGINS.includes(url.origin) || url.username || url.password || url.hash) {
137
140
  throw new Error("unsafe Browserbase connect URL");
138
141
  }
139
142
  return url.toString();
@@ -193,7 +196,9 @@ function parseProviderSession(value, expectedProjectId, expectedSessionId) {
193
196
  status,
194
197
  createdAt,
195
198
  expiresAt,
196
- connectUrl: secureConnectUrl(record.connectUrl)
199
+ // Completed sessions need not retain a connection capability. Validate it
200
+ // only for active states; identity and timestamps above still must match.
201
+ connectUrl: status === "PENDING" || status === "RUNNING" ? secureConnectUrl(record.connectUrl) : null
197
202
  });
198
203
  }
199
204
  async function readProviderJson(response) {
@@ -289,11 +294,13 @@ function createBrowserbaseSessionManager(config) {
289
294
  projectId,
290
295
  timeout: durationSeconds,
291
296
  keepAlive: true,
292
- ...contextId ? {
293
- browserSettings: {
294
- context: { id: contextId, persist: true }
295
- }
296
- } : {}
297
+ proxies: false,
298
+ browserSettings: {
299
+ recordSession: false,
300
+ logSession: false,
301
+ solveCaptchas: false,
302
+ ...contextId ? { context: { id: contextId, persist: true } } : {}
303
+ }
297
304
  })
298
305
  });
299
306
  if (response.status !== 201) {
@@ -536,7 +543,7 @@ function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config) {
536
543
  const host = createGuardedPlaywrightCheckoutRuntimeHost({
537
544
  conto: config.conto,
538
545
  browserSessions: {
539
- allowedConnectOrigins: [BROWSERBASE_CONNECT_ORIGIN],
546
+ allowedConnectOrigins: BROWSERBASE_CONNECT_ORIGINS,
540
547
  connectUrlForSession: manager.connectUrlForSession,
541
548
  connectOverCDP: config.connectOverCDP,
542
549
  selectPage: config.selectPage,
@@ -598,7 +605,9 @@ function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config) {
598
605
  });
599
606
  }
600
607
  export {
608
+ BROWSERBASE_CONNECT_ORIGINS,
601
609
  BrowserbaseSessionError,
602
610
  createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost,
603
- createBrowserbaseSessionHandoffAssertion
611
+ createBrowserbaseSessionHandoffAssertion,
612
+ createBrowserbaseSessionManager
604
613
  };
package/dist/index.d.mts CHANGED
@@ -65,7 +65,7 @@ interface PaginatedResponse<T> {
65
65
  limit: number;
66
66
  offset: number;
67
67
  }
68
- type AgentType = 'OPENAI_ASSISTANT' | 'ANTHROPIC_CLAUDE' | 'LANGCHAIN' | 'AUTOGPT' | 'CUSTOM';
68
+ type AgentType = 'OPENAI_ASSISTANT' | 'ANTHROPIC_CLAUDE' | 'AUTOGPT' | 'CUSTOM';
69
69
  type AgentStatus = 'ACTIVE' | 'PAUSED' | 'SUSPENDED' | 'REVOKED' | 'FROZEN' | 'DELETED';
70
70
  type AgentEnvironment = 'DEV' | 'STAGING' | 'PROD';
71
71
  type AgentRiskTier = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
@@ -1131,7 +1131,7 @@ interface PaymentRequestResult {
1131
1131
  /** Unique request ID - use this to execute or check status */
1132
1132
  requestId: string;
1133
1133
  /** Current status */
1134
- status: 'APPROVED' | 'DENIED' | 'REQUIRES_APPROVAL' | 'ACTION_REQUIRED' | 'PROCESSING';
1134
+ status: 'APPROVED' | 'DENIED' | 'REQUIRES_APPROVAL' | 'PROCESSING';
1135
1135
  /** Requested amount */
1136
1136
  amount: number;
1137
1137
  /** Currency selected for the payment */
@@ -1164,6 +1164,11 @@ interface PaymentRequestResult {
1164
1164
  interface PaymentExecuteResult {
1165
1165
  /** Payment request ID */
1166
1166
  requestId: string;
1167
+ /**
1168
+ * True when the payment had already been executed, for example by an
1169
+ * approver in Conto. The receipt is the existing one; nothing was sent again.
1170
+ */
1171
+ alreadyExecuted?: boolean;
1167
1172
  /** Customer-facing execution state */
1168
1173
  status: 'processing' | 'completed';
1169
1174
  /** Amount sent */
@@ -1187,7 +1192,7 @@ interface PaymentStatusResult {
1187
1192
  requestId: string;
1188
1193
  /** Unknown for legacy records without execution evidence, or before execution. */
1189
1194
  settlementMode: 'live' | 'test' | 'unknown';
1190
- status: 'approved' | 'declined' | 'review_required' | 'action_required' | 'reconciliation_required' | 'processing' | 'completed' | 'failed' | 'expired';
1195
+ status: 'approved' | 'declined' | 'review_required' | 'reconciliation_required' | 'processing' | 'completed' | 'failed' | 'expired';
1191
1196
  amount: number;
1192
1197
  currency: string;
1193
1198
  recipient: string;
@@ -1196,10 +1201,9 @@ interface PaymentStatusResult {
1196
1201
  category: string | null;
1197
1202
  expiresAt: string | null;
1198
1203
  createdAt: string;
1199
- action: {
1200
- type: 'complete_verification';
1201
- url: string;
1202
- } | null;
1204
+ /** Customer-facing reasons for a declined payment or a pending review. */
1205
+ reasons?: string[];
1206
+ action: null;
1203
1207
  transaction: {
1204
1208
  /** Stable Conto transaction ID */
1205
1209
  id: string;
@@ -1858,6 +1862,38 @@ interface ProtocolPreAuthorizeResult {
1858
1862
  authorized: boolean;
1859
1863
  decision: 'approved' | 'declined' | 'review_required';
1860
1864
  message: string;
1865
+ /**
1866
+ * Present when not authorized. Fixed reasons the agent can act on, such as a
1867
+ * spending limit or a service that is not allowed. Never includes rule values.
1868
+ */
1869
+ reasons?: string[];
1870
+ /** Present when not authorized. Codes for `reasons`, for example `SPENDING_LIMIT`. */
1871
+ reasonCodes?: string[];
1872
+ /**
1873
+ * Present when authorized. Pass grantId and grantSignature to record(). A
1874
+ * record without a valid, unexpired grant is accepted but treated as a policy
1875
+ * bypass: the payment is flagged and the owner is alerted. The organization
1876
+ * can also have the agent frozen automatically.
1877
+ */
1878
+ grantId?: string;
1879
+ grantSignature?: string;
1880
+ /** ISO timestamp. Record the payment before this time. */
1881
+ grantExpiresAt?: string;
1882
+ }
1883
+ interface ProtocolRecordGrant {
1884
+ /** grantId from the approved preAuthorize() response. */
1885
+ grantId?: string;
1886
+ /** grantSignature from the approved preAuthorize() response. */
1887
+ grantSignature?: string;
1888
+ }
1889
+ interface ProtocolRecordGrantResult {
1890
+ /** Grant consumed by this record. */
1891
+ grantId?: string;
1892
+ /** True when the payment was recorded without a valid grant. */
1893
+ policyBypass?: true;
1894
+ bypassReason?: 'GRANT_MISSING' | 'GRANT_INVALID' | 'GRANT_EXPIRED';
1895
+ /** True when the organization freezes agents on bypass and this record froze it. */
1896
+ agentFrozen?: boolean;
1861
1897
  }
1862
1898
  interface X402PreAuthorizeInput {
1863
1899
  amount: number;
@@ -1884,7 +1920,55 @@ interface X402PreAuthorizeResult extends ProtocolPreAuthorizeResult {
1884
1920
  sessionId?: string;
1885
1921
  };
1886
1922
  }
1887
- interface X402RecordInput {
1923
+ /** The accepted entry from a 402 challenge (x402 "exact" scheme on EVM). */
1924
+ interface X402PaymentRequirements {
1925
+ scheme: 'exact' | (string & {});
1926
+ /** Network as the challenge sent it: CAIP-2 (eip155:8453) or an x402 v1 name (base). */
1927
+ network: string;
1928
+ /** v1: amount in token base units, as an integer string. */
1929
+ maxAmountRequired?: string;
1930
+ /** v2: amount in token base units, as an integer string. */
1931
+ amount?: string;
1932
+ /** Token contract. Conto signs only for managed USDC. */
1933
+ asset: string;
1934
+ payTo: string;
1935
+ maxTimeoutSeconds: number;
1936
+ resource?: string;
1937
+ /** EIP-712 domain of the token. */
1938
+ extra?: {
1939
+ name?: string;
1940
+ version?: string;
1941
+ [key: string]: unknown;
1942
+ };
1943
+ [key: string]: unknown;
1944
+ }
1945
+ interface X402PayInput extends X402PreAuthorizeInput {
1946
+ /** x402 protocol version of the challenge. Defaults to 1. */
1947
+ x402Version?: 1 | 2;
1948
+ paymentRequirements: X402PaymentRequirements;
1949
+ }
1950
+ interface X402Authorization {
1951
+ from: string;
1952
+ to: string;
1953
+ value: string;
1954
+ validAfter: string;
1955
+ validBefore: string;
1956
+ nonce: string;
1957
+ }
1958
+ interface X402PayResult extends ProtocolPreAuthorizeResult {
1959
+ x402: {
1960
+ serviceDomain?: string;
1961
+ amount: number;
1962
+ sessionId?: string;
1963
+ };
1964
+ /** Present when authorized: send as this header when retrying the resource request. */
1965
+ paymentHeaderName?: 'X-PAYMENT' | 'PAYMENT-SIGNATURE';
1966
+ /** Present when authorized: base64 payment payload signed by Conto. */
1967
+ xPaymentHeader?: string;
1968
+ /** Present when authorized: the EIP-3009 authorization Conto signed. */
1969
+ authorization?: X402Authorization;
1970
+ }
1971
+ interface X402RecordInput extends ProtocolRecordGrant {
1888
1972
  amount: number;
1889
1973
  currency?: string;
1890
1974
  recipientAddress: string;
@@ -1908,7 +1992,7 @@ interface X402RecordInput {
1908
1992
  paymentId: string;
1909
1993
  }>;
1910
1994
  }
1911
- interface X402RecordResult {
1995
+ interface X402RecordResult extends ProtocolRecordGrantResult {
1912
1996
  recorded: true;
1913
1997
  confirmed: true;
1914
1998
  txHash: string;
@@ -1939,7 +2023,7 @@ interface MppPreAuthorizeResult extends ProtocolPreAuthorizeResult {
1939
2023
  sessionId?: string;
1940
2024
  };
1941
2025
  }
1942
- interface MppRecordInput {
2026
+ interface MppRecordInput extends ProtocolRecordGrant {
1943
2027
  amount: number;
1944
2028
  currency?: string;
1945
2029
  recipientAddress: string;
@@ -1965,7 +2049,7 @@ interface MppRecordInput {
1965
2049
  credentialId: string;
1966
2050
  }>;
1967
2051
  }
1968
- interface MppRecordResult {
2052
+ interface MppRecordResult extends ProtocolRecordGrantResult {
1969
2053
  recorded: true;
1970
2054
  txHash?: string;
1971
2055
  explorerUrl?: string;
@@ -2298,7 +2382,9 @@ declare class PaymentsClient {
2298
2382
  * Execute an approved payment.
2299
2383
  *
2300
2384
  * This sends the onchain transaction. Only works for payments
2301
- * with status 'APPROVED'.
2385
+ * with status 'APPROVED'. If an approver already executed the payment by
2386
+ * approving it in Conto, this returns the existing receipt with
2387
+ * `alreadyExecuted: true` and sends nothing.
2302
2388
  *
2303
2389
  * @param requestId - The requestId from a successful payment request
2304
2390
  *
@@ -2359,6 +2445,16 @@ declare class X402Client {
2359
2445
  private client;
2360
2446
  constructor(client: Conto);
2361
2447
  preAuthorize(input: X402PreAuthorizeInput): Promise<X402PreAuthorizeResult>;
2448
+ /**
2449
+ * Conto-signed x402 for Privy-managed EVM wallets. Conto evaluates the
2450
+ * payment exactly like preAuthorize() and, only when approved, signs the
2451
+ * EIP-3009 authorization for the approved payee and amount. Retry the
2452
+ * resource request with `paymentHeaderName: xPaymentHeader`, then call
2453
+ * record() with the returned grant. Not retried automatically: a grant is
2454
+ * signed at most once, and a repeat returns 409 GRANT_ALREADY_SIGNED.
2455
+ * External wallets get 409 MANAGED_SIGNING_UNAVAILABLE; use preAuthorize().
2456
+ */
2457
+ pay(input: X402PayInput): Promise<X402PayResult>;
2362
2458
  record(input: X402RecordInput): Promise<X402RecordResult>;
2363
2459
  budget(options?: {
2364
2460
  sessionId?: string;
@@ -2382,4 +2478,4 @@ declare class MppClient {
2382
2478
  }): Promise<ProtocolServicesResult>;
2383
2479
  }
2384
2480
 
2385
- export { type AdminExternalCardOverlayEnforcement, type Agent, type AgentCheckoutAction, type AgentCheckoutActionKind, type AgentExternalCard, type AgentSetupResult, type AgentStatus, type AgentType, type AgentWalletLink, type ApprovedExternalCardExecution, type AssignExternalCardInput, type AssignedPolicy, type AuthorizeCheckoutActionResult, type BeginCommerceExecutionInput, type BrowserActionClaimResult, type BrowserActionDispatchObservationInput, BrowserActionFinalizationPendingError, type BrowserActionFinalizeResult, type BrowserCheckoutAction, type BrowserCheckoutTargetResolver, type BrowserCheckoutTargetSnapshot, type BrowserCheckoutTargetVerificationCode, BrowserCheckoutTargetVerificationError, type CanonicalBrowserCheckoutTargetSnapshot, CardsClient, type ChainType, type CheckoutActionAuthorization, type CommerceCheckoutMethod, type CommerceContextRequirement, type CommerceExecution, type CommerceExecutionAdapterKind, type CommerceExecutionArtifactKind, type CommerceExecutionChannel, type CommerceExecutionConstraint, type CommerceExecutionConstraintCoverage, type CommerceExecutionConstraintCoverageLevel, type CommerceExecutionDeliveryMode, type CommerceExecutionEvidence, type CommerceExecutionProvider, type CommerceExecutionResult, type CommerceExecutionSourceKind, type CommerceExecutionStatus, type CommerceFactConfidence, type CommerceFactProvenanceInput, type CommerceFactSource, type CommerceFulfillmentInput, type CommerceLineItemInput, type CommerceProposalFactKey, type CommerceProposalMissingFact, type CommerceProposalResolution, type CommerceProposalState, type CommerceSettlementRail, type CommerceTotalInput, type CommerceTotalType, type ComparePolicyVersionsResponse, type ConnectedCardBrief, type ConnectedCardCredential, type ConnectedCardDrawInput, type ConnectedCardDrawMerchant, type ConnectedCardDrawResult, type ConnectedCardDrawable, type ConnectedCardListResult, type ConnectedCardMandate, type ConnectedCardMandateMerchant, type ConnectedCardReference, ConnectedCardsClient, Conto, ContoAdmin, type ContoAdminConfig, ContoAdminError, type ContoConfig, ContoError, type ContoRequestOptions, type ControlledExternalCardPaymentResult, ControlledExternalCardPaymentTool, type CreateAgentInput, type CreatePolicyInput, type CreatePolicyRuleInput, type CreateSdkKeyInput, type CreateSdkKeyResult, type CreateWalletInput, type CustodyType, type CustomerCustodyMode, type CustomerWalletControlModel, type CustomerWalletKeyAccess, type DelegationType, type ExecuteCommerceExecutionResult, type ExternalCard, type ExternalCardApprovalInput, type ExternalCardApprovalResult, type ExternalCardConfirmationInput, ExternalCardConfirmationPendingError, type ExternalCardConfirmationResult, type ExternalCardExecutionClaimResult, type ExternalCardExecutionResult, type ExternalCardExecutor, type ExternalCardOverlayEnforcement, type ExternalCardRequestStatusResult, type ExternalWalletApprovalInput, type ExternalWalletApprovalResult, type ExternalWalletConfirmationInput, type ExternalWalletConfirmationResult, type FreezeAgentInput, Conto as Giro, type ContoConfig as GiroConfig, ContoError as GiroError, type GuardCheckoutResult, type GuardedBrowserDispatchResult, type GuardedCheckoutInput, type LinkWalletInput, type ListAgentsParams, type ListAgentsResponse, type ListPoliciesParams, type ListPoliciesResponse, type ListPolicyVersionsResponse, type ListStripeLinkPaymentMethodsResult, type ListWalletsParams, type ListWalletsResponse, type MppBudgetResult, type MppPreAuthorizeInput, type MppPreAuthorizeResult, type MppRecordInput, type MppRecordResult, type NormalizeCommerceProposalInput, type OrganizationMember, type PaginatedResponse, type PaginationParams, type PauseExternalCardAssignmentResult, type PaymentExecuteResult, type PaymentRequestInput, type PaymentRequestResult, type PaymentStatusResult, type Policy, type PolicyRule, type PolicyType, type PolicyVersionChangeType, type PolicyVersionDetail, type PolicyVersionDiff, type PolicyVersionFieldChange, type PolicyVersionSnapshot, type PolicyVersionSnapshotRule, type PolicyVersionSummary, type PrivilegedBrowserCheckoutDriver, type ProtocolBudgetResult, type ProtocolPreAuthorizeResult, type ProtocolServiceSummary, type ProtocolServicesResult, type ProvisionWalletResult, type RefreshBalanceResult, type RegisterExternalCardInput, type RollbackPolicyVersionResponse, type RuleAction, type RuleOperator, type RuleType, type RunGuardedCheckoutResult, type SdkKey, type SdkKeyType, type StripeLinkCheckoutReadiness, type StripeLinkCheckoutReadinessResult, type StripeLinkCheckoutReadinessStatus, type StripeLinkCheckoutVerification, type StripeLinkPaymentMethod, type UnfreezeAgentInput, type UpdateAgentInput, type UpdateExternalCardAssignmentInput, type UpdatePolicyInput, type UpdatePolicyRuleInput, type UpdateWalletInput, type VerifiedBrowserCheckoutTarget, type Wallet, type WalletChainBalanceSnapshot, type WalletStatus, type WalletType, type X402BudgetResult, type X402PreAuthorizeInput, type X402PreAuthorizeResult, type X402RecordInput, type X402RecordResult, canonicalizeBrowserCheckoutTarget, createVerifiedBrowserCheckoutDriver, Conto as default, fingerprintBrowserCheckoutTarget };
2481
+ export { type AdminExternalCardOverlayEnforcement, type Agent, type AgentCheckoutAction, type AgentCheckoutActionKind, type AgentExternalCard, type AgentSetupResult, type AgentStatus, type AgentType, type AgentWalletLink, type ApprovedExternalCardExecution, type AssignExternalCardInput, type AssignedPolicy, type AuthorizeCheckoutActionResult, type BeginCommerceExecutionInput, type BrowserActionClaimResult, type BrowserActionDispatchObservationInput, BrowserActionFinalizationPendingError, type BrowserActionFinalizeResult, type BrowserCheckoutAction, type BrowserCheckoutTargetResolver, type BrowserCheckoutTargetSnapshot, type BrowserCheckoutTargetVerificationCode, BrowserCheckoutTargetVerificationError, type CanonicalBrowserCheckoutTargetSnapshot, CardsClient, type ChainType, type CheckoutActionAuthorization, type CommerceCheckoutMethod, type CommerceContextRequirement, type CommerceExecution, type CommerceExecutionAdapterKind, type CommerceExecutionArtifactKind, type CommerceExecutionChannel, type CommerceExecutionConstraint, type CommerceExecutionConstraintCoverage, type CommerceExecutionConstraintCoverageLevel, type CommerceExecutionDeliveryMode, type CommerceExecutionEvidence, type CommerceExecutionProvider, type CommerceExecutionResult, type CommerceExecutionSourceKind, type CommerceExecutionStatus, type CommerceFactConfidence, type CommerceFactProvenanceInput, type CommerceFactSource, type CommerceFulfillmentInput, type CommerceLineItemInput, type CommerceProposalFactKey, type CommerceProposalMissingFact, type CommerceProposalResolution, type CommerceProposalState, type CommerceSettlementRail, type CommerceTotalInput, type CommerceTotalType, type ComparePolicyVersionsResponse, type ConnectedCardBrief, type ConnectedCardCredential, type ConnectedCardDrawInput, type ConnectedCardDrawMerchant, type ConnectedCardDrawResult, type ConnectedCardDrawable, type ConnectedCardListResult, type ConnectedCardMandate, type ConnectedCardMandateMerchant, type ConnectedCardReference, ConnectedCardsClient, Conto, ContoAdmin, type ContoAdminConfig, ContoAdminError, type ContoConfig, ContoError, type ContoRequestOptions, type ControlledExternalCardPaymentResult, ControlledExternalCardPaymentTool, type CreateAgentInput, type CreatePolicyInput, type CreatePolicyRuleInput, type CreateSdkKeyInput, type CreateSdkKeyResult, type CreateWalletInput, type CustodyType, type CustomerCustodyMode, type CustomerWalletControlModel, type CustomerWalletKeyAccess, type DelegationType, type ExecuteCommerceExecutionResult, type ExternalCard, type ExternalCardApprovalInput, type ExternalCardApprovalResult, type ExternalCardConfirmationInput, ExternalCardConfirmationPendingError, type ExternalCardConfirmationResult, type ExternalCardExecutionClaimResult, type ExternalCardExecutionResult, type ExternalCardExecutor, type ExternalCardOverlayEnforcement, type ExternalCardRequestStatusResult, type ExternalWalletApprovalInput, type ExternalWalletApprovalResult, type ExternalWalletConfirmationInput, type ExternalWalletConfirmationResult, type FreezeAgentInput, Conto as Giro, type ContoConfig as GiroConfig, ContoError as GiroError, type GuardCheckoutResult, type GuardedBrowserDispatchResult, type GuardedCheckoutInput, type LinkWalletInput, type ListAgentsParams, type ListAgentsResponse, type ListPoliciesParams, type ListPoliciesResponse, type ListPolicyVersionsResponse, type ListStripeLinkPaymentMethodsResult, type ListWalletsParams, type ListWalletsResponse, type MppBudgetResult, type MppPreAuthorizeInput, type MppPreAuthorizeResult, type MppRecordInput, type MppRecordResult, type NormalizeCommerceProposalInput, type OrganizationMember, type PaginatedResponse, type PaginationParams, type PauseExternalCardAssignmentResult, type PaymentExecuteResult, type PaymentRequestInput, type PaymentRequestResult, type PaymentStatusResult, type Policy, type PolicyRule, type PolicyType, type PolicyVersionChangeType, type PolicyVersionDetail, type PolicyVersionDiff, type PolicyVersionFieldChange, type PolicyVersionSnapshot, type PolicyVersionSnapshotRule, type PolicyVersionSummary, type PrivilegedBrowserCheckoutDriver, type ProtocolBudgetResult, type ProtocolPreAuthorizeResult, type ProtocolRecordGrant, type ProtocolRecordGrantResult, type ProtocolServiceSummary, type ProtocolServicesResult, type ProvisionWalletResult, type RefreshBalanceResult, type RegisterExternalCardInput, type RollbackPolicyVersionResponse, type RuleAction, type RuleOperator, type RuleType, type RunGuardedCheckoutResult, type SdkKey, type SdkKeyType, type StripeLinkCheckoutReadiness, type StripeLinkCheckoutReadinessResult, type StripeLinkCheckoutReadinessStatus, type StripeLinkCheckoutVerification, type StripeLinkPaymentMethod, type UnfreezeAgentInput, type UpdateAgentInput, type UpdateExternalCardAssignmentInput, type UpdatePolicyInput, type UpdatePolicyRuleInput, type UpdateWalletInput, type VerifiedBrowserCheckoutTarget, type Wallet, type WalletChainBalanceSnapshot, type WalletStatus, type WalletType, type X402Authorization, type X402BudgetResult, type X402PayInput, type X402PayResult, type X402PaymentRequirements, type X402PreAuthorizeInput, type X402PreAuthorizeResult, type X402RecordInput, type X402RecordResult, canonicalizeBrowserCheckoutTarget, createVerifiedBrowserCheckoutDriver, Conto as default, fingerprintBrowserCheckoutTarget };
package/dist/index.d.ts CHANGED
@@ -65,7 +65,7 @@ interface PaginatedResponse<T> {
65
65
  limit: number;
66
66
  offset: number;
67
67
  }
68
- type AgentType = 'OPENAI_ASSISTANT' | 'ANTHROPIC_CLAUDE' | 'LANGCHAIN' | 'AUTOGPT' | 'CUSTOM';
68
+ type AgentType = 'OPENAI_ASSISTANT' | 'ANTHROPIC_CLAUDE' | 'AUTOGPT' | 'CUSTOM';
69
69
  type AgentStatus = 'ACTIVE' | 'PAUSED' | 'SUSPENDED' | 'REVOKED' | 'FROZEN' | 'DELETED';
70
70
  type AgentEnvironment = 'DEV' | 'STAGING' | 'PROD';
71
71
  type AgentRiskTier = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL';
@@ -1131,7 +1131,7 @@ interface PaymentRequestResult {
1131
1131
  /** Unique request ID - use this to execute or check status */
1132
1132
  requestId: string;
1133
1133
  /** Current status */
1134
- status: 'APPROVED' | 'DENIED' | 'REQUIRES_APPROVAL' | 'ACTION_REQUIRED' | 'PROCESSING';
1134
+ status: 'APPROVED' | 'DENIED' | 'REQUIRES_APPROVAL' | 'PROCESSING';
1135
1135
  /** Requested amount */
1136
1136
  amount: number;
1137
1137
  /** Currency selected for the payment */
@@ -1164,6 +1164,11 @@ interface PaymentRequestResult {
1164
1164
  interface PaymentExecuteResult {
1165
1165
  /** Payment request ID */
1166
1166
  requestId: string;
1167
+ /**
1168
+ * True when the payment had already been executed, for example by an
1169
+ * approver in Conto. The receipt is the existing one; nothing was sent again.
1170
+ */
1171
+ alreadyExecuted?: boolean;
1167
1172
  /** Customer-facing execution state */
1168
1173
  status: 'processing' | 'completed';
1169
1174
  /** Amount sent */
@@ -1187,7 +1192,7 @@ interface PaymentStatusResult {
1187
1192
  requestId: string;
1188
1193
  /** Unknown for legacy records without execution evidence, or before execution. */
1189
1194
  settlementMode: 'live' | 'test' | 'unknown';
1190
- status: 'approved' | 'declined' | 'review_required' | 'action_required' | 'reconciliation_required' | 'processing' | 'completed' | 'failed' | 'expired';
1195
+ status: 'approved' | 'declined' | 'review_required' | 'reconciliation_required' | 'processing' | 'completed' | 'failed' | 'expired';
1191
1196
  amount: number;
1192
1197
  currency: string;
1193
1198
  recipient: string;
@@ -1196,10 +1201,9 @@ interface PaymentStatusResult {
1196
1201
  category: string | null;
1197
1202
  expiresAt: string | null;
1198
1203
  createdAt: string;
1199
- action: {
1200
- type: 'complete_verification';
1201
- url: string;
1202
- } | null;
1204
+ /** Customer-facing reasons for a declined payment or a pending review. */
1205
+ reasons?: string[];
1206
+ action: null;
1203
1207
  transaction: {
1204
1208
  /** Stable Conto transaction ID */
1205
1209
  id: string;
@@ -1858,6 +1862,38 @@ interface ProtocolPreAuthorizeResult {
1858
1862
  authorized: boolean;
1859
1863
  decision: 'approved' | 'declined' | 'review_required';
1860
1864
  message: string;
1865
+ /**
1866
+ * Present when not authorized. Fixed reasons the agent can act on, such as a
1867
+ * spending limit or a service that is not allowed. Never includes rule values.
1868
+ */
1869
+ reasons?: string[];
1870
+ /** Present when not authorized. Codes for `reasons`, for example `SPENDING_LIMIT`. */
1871
+ reasonCodes?: string[];
1872
+ /**
1873
+ * Present when authorized. Pass grantId and grantSignature to record(). A
1874
+ * record without a valid, unexpired grant is accepted but treated as a policy
1875
+ * bypass: the payment is flagged and the owner is alerted. The organization
1876
+ * can also have the agent frozen automatically.
1877
+ */
1878
+ grantId?: string;
1879
+ grantSignature?: string;
1880
+ /** ISO timestamp. Record the payment before this time. */
1881
+ grantExpiresAt?: string;
1882
+ }
1883
+ interface ProtocolRecordGrant {
1884
+ /** grantId from the approved preAuthorize() response. */
1885
+ grantId?: string;
1886
+ /** grantSignature from the approved preAuthorize() response. */
1887
+ grantSignature?: string;
1888
+ }
1889
+ interface ProtocolRecordGrantResult {
1890
+ /** Grant consumed by this record. */
1891
+ grantId?: string;
1892
+ /** True when the payment was recorded without a valid grant. */
1893
+ policyBypass?: true;
1894
+ bypassReason?: 'GRANT_MISSING' | 'GRANT_INVALID' | 'GRANT_EXPIRED';
1895
+ /** True when the organization freezes agents on bypass and this record froze it. */
1896
+ agentFrozen?: boolean;
1861
1897
  }
1862
1898
  interface X402PreAuthorizeInput {
1863
1899
  amount: number;
@@ -1884,7 +1920,55 @@ interface X402PreAuthorizeResult extends ProtocolPreAuthorizeResult {
1884
1920
  sessionId?: string;
1885
1921
  };
1886
1922
  }
1887
- interface X402RecordInput {
1923
+ /** The accepted entry from a 402 challenge (x402 "exact" scheme on EVM). */
1924
+ interface X402PaymentRequirements {
1925
+ scheme: 'exact' | (string & {});
1926
+ /** Network as the challenge sent it: CAIP-2 (eip155:8453) or an x402 v1 name (base). */
1927
+ network: string;
1928
+ /** v1: amount in token base units, as an integer string. */
1929
+ maxAmountRequired?: string;
1930
+ /** v2: amount in token base units, as an integer string. */
1931
+ amount?: string;
1932
+ /** Token contract. Conto signs only for managed USDC. */
1933
+ asset: string;
1934
+ payTo: string;
1935
+ maxTimeoutSeconds: number;
1936
+ resource?: string;
1937
+ /** EIP-712 domain of the token. */
1938
+ extra?: {
1939
+ name?: string;
1940
+ version?: string;
1941
+ [key: string]: unknown;
1942
+ };
1943
+ [key: string]: unknown;
1944
+ }
1945
+ interface X402PayInput extends X402PreAuthorizeInput {
1946
+ /** x402 protocol version of the challenge. Defaults to 1. */
1947
+ x402Version?: 1 | 2;
1948
+ paymentRequirements: X402PaymentRequirements;
1949
+ }
1950
+ interface X402Authorization {
1951
+ from: string;
1952
+ to: string;
1953
+ value: string;
1954
+ validAfter: string;
1955
+ validBefore: string;
1956
+ nonce: string;
1957
+ }
1958
+ interface X402PayResult extends ProtocolPreAuthorizeResult {
1959
+ x402: {
1960
+ serviceDomain?: string;
1961
+ amount: number;
1962
+ sessionId?: string;
1963
+ };
1964
+ /** Present when authorized: send as this header when retrying the resource request. */
1965
+ paymentHeaderName?: 'X-PAYMENT' | 'PAYMENT-SIGNATURE';
1966
+ /** Present when authorized: base64 payment payload signed by Conto. */
1967
+ xPaymentHeader?: string;
1968
+ /** Present when authorized: the EIP-3009 authorization Conto signed. */
1969
+ authorization?: X402Authorization;
1970
+ }
1971
+ interface X402RecordInput extends ProtocolRecordGrant {
1888
1972
  amount: number;
1889
1973
  currency?: string;
1890
1974
  recipientAddress: string;
@@ -1908,7 +1992,7 @@ interface X402RecordInput {
1908
1992
  paymentId: string;
1909
1993
  }>;
1910
1994
  }
1911
- interface X402RecordResult {
1995
+ interface X402RecordResult extends ProtocolRecordGrantResult {
1912
1996
  recorded: true;
1913
1997
  confirmed: true;
1914
1998
  txHash: string;
@@ -1939,7 +2023,7 @@ interface MppPreAuthorizeResult extends ProtocolPreAuthorizeResult {
1939
2023
  sessionId?: string;
1940
2024
  };
1941
2025
  }
1942
- interface MppRecordInput {
2026
+ interface MppRecordInput extends ProtocolRecordGrant {
1943
2027
  amount: number;
1944
2028
  currency?: string;
1945
2029
  recipientAddress: string;
@@ -1965,7 +2049,7 @@ interface MppRecordInput {
1965
2049
  credentialId: string;
1966
2050
  }>;
1967
2051
  }
1968
- interface MppRecordResult {
2052
+ interface MppRecordResult extends ProtocolRecordGrantResult {
1969
2053
  recorded: true;
1970
2054
  txHash?: string;
1971
2055
  explorerUrl?: string;
@@ -2298,7 +2382,9 @@ declare class PaymentsClient {
2298
2382
  * Execute an approved payment.
2299
2383
  *
2300
2384
  * This sends the onchain transaction. Only works for payments
2301
- * with status 'APPROVED'.
2385
+ * with status 'APPROVED'. If an approver already executed the payment by
2386
+ * approving it in Conto, this returns the existing receipt with
2387
+ * `alreadyExecuted: true` and sends nothing.
2302
2388
  *
2303
2389
  * @param requestId - The requestId from a successful payment request
2304
2390
  *
@@ -2359,6 +2445,16 @@ declare class X402Client {
2359
2445
  private client;
2360
2446
  constructor(client: Conto);
2361
2447
  preAuthorize(input: X402PreAuthorizeInput): Promise<X402PreAuthorizeResult>;
2448
+ /**
2449
+ * Conto-signed x402 for Privy-managed EVM wallets. Conto evaluates the
2450
+ * payment exactly like preAuthorize() and, only when approved, signs the
2451
+ * EIP-3009 authorization for the approved payee and amount. Retry the
2452
+ * resource request with `paymentHeaderName: xPaymentHeader`, then call
2453
+ * record() with the returned grant. Not retried automatically: a grant is
2454
+ * signed at most once, and a repeat returns 409 GRANT_ALREADY_SIGNED.
2455
+ * External wallets get 409 MANAGED_SIGNING_UNAVAILABLE; use preAuthorize().
2456
+ */
2457
+ pay(input: X402PayInput): Promise<X402PayResult>;
2362
2458
  record(input: X402RecordInput): Promise<X402RecordResult>;
2363
2459
  budget(options?: {
2364
2460
  sessionId?: string;
@@ -2382,4 +2478,4 @@ declare class MppClient {
2382
2478
  }): Promise<ProtocolServicesResult>;
2383
2479
  }
2384
2480
 
2385
- export { type AdminExternalCardOverlayEnforcement, type Agent, type AgentCheckoutAction, type AgentCheckoutActionKind, type AgentExternalCard, type AgentSetupResult, type AgentStatus, type AgentType, type AgentWalletLink, type ApprovedExternalCardExecution, type AssignExternalCardInput, type AssignedPolicy, type AuthorizeCheckoutActionResult, type BeginCommerceExecutionInput, type BrowserActionClaimResult, type BrowserActionDispatchObservationInput, BrowserActionFinalizationPendingError, type BrowserActionFinalizeResult, type BrowserCheckoutAction, type BrowserCheckoutTargetResolver, type BrowserCheckoutTargetSnapshot, type BrowserCheckoutTargetVerificationCode, BrowserCheckoutTargetVerificationError, type CanonicalBrowserCheckoutTargetSnapshot, CardsClient, type ChainType, type CheckoutActionAuthorization, type CommerceCheckoutMethod, type CommerceContextRequirement, type CommerceExecution, type CommerceExecutionAdapterKind, type CommerceExecutionArtifactKind, type CommerceExecutionChannel, type CommerceExecutionConstraint, type CommerceExecutionConstraintCoverage, type CommerceExecutionConstraintCoverageLevel, type CommerceExecutionDeliveryMode, type CommerceExecutionEvidence, type CommerceExecutionProvider, type CommerceExecutionResult, type CommerceExecutionSourceKind, type CommerceExecutionStatus, type CommerceFactConfidence, type CommerceFactProvenanceInput, type CommerceFactSource, type CommerceFulfillmentInput, type CommerceLineItemInput, type CommerceProposalFactKey, type CommerceProposalMissingFact, type CommerceProposalResolution, type CommerceProposalState, type CommerceSettlementRail, type CommerceTotalInput, type CommerceTotalType, type ComparePolicyVersionsResponse, type ConnectedCardBrief, type ConnectedCardCredential, type ConnectedCardDrawInput, type ConnectedCardDrawMerchant, type ConnectedCardDrawResult, type ConnectedCardDrawable, type ConnectedCardListResult, type ConnectedCardMandate, type ConnectedCardMandateMerchant, type ConnectedCardReference, ConnectedCardsClient, Conto, ContoAdmin, type ContoAdminConfig, ContoAdminError, type ContoConfig, ContoError, type ContoRequestOptions, type ControlledExternalCardPaymentResult, ControlledExternalCardPaymentTool, type CreateAgentInput, type CreatePolicyInput, type CreatePolicyRuleInput, type CreateSdkKeyInput, type CreateSdkKeyResult, type CreateWalletInput, type CustodyType, type CustomerCustodyMode, type CustomerWalletControlModel, type CustomerWalletKeyAccess, type DelegationType, type ExecuteCommerceExecutionResult, type ExternalCard, type ExternalCardApprovalInput, type ExternalCardApprovalResult, type ExternalCardConfirmationInput, ExternalCardConfirmationPendingError, type ExternalCardConfirmationResult, type ExternalCardExecutionClaimResult, type ExternalCardExecutionResult, type ExternalCardExecutor, type ExternalCardOverlayEnforcement, type ExternalCardRequestStatusResult, type ExternalWalletApprovalInput, type ExternalWalletApprovalResult, type ExternalWalletConfirmationInput, type ExternalWalletConfirmationResult, type FreezeAgentInput, Conto as Giro, type ContoConfig as GiroConfig, ContoError as GiroError, type GuardCheckoutResult, type GuardedBrowserDispatchResult, type GuardedCheckoutInput, type LinkWalletInput, type ListAgentsParams, type ListAgentsResponse, type ListPoliciesParams, type ListPoliciesResponse, type ListPolicyVersionsResponse, type ListStripeLinkPaymentMethodsResult, type ListWalletsParams, type ListWalletsResponse, type MppBudgetResult, type MppPreAuthorizeInput, type MppPreAuthorizeResult, type MppRecordInput, type MppRecordResult, type NormalizeCommerceProposalInput, type OrganizationMember, type PaginatedResponse, type PaginationParams, type PauseExternalCardAssignmentResult, type PaymentExecuteResult, type PaymentRequestInput, type PaymentRequestResult, type PaymentStatusResult, type Policy, type PolicyRule, type PolicyType, type PolicyVersionChangeType, type PolicyVersionDetail, type PolicyVersionDiff, type PolicyVersionFieldChange, type PolicyVersionSnapshot, type PolicyVersionSnapshotRule, type PolicyVersionSummary, type PrivilegedBrowserCheckoutDriver, type ProtocolBudgetResult, type ProtocolPreAuthorizeResult, type ProtocolServiceSummary, type ProtocolServicesResult, type ProvisionWalletResult, type RefreshBalanceResult, type RegisterExternalCardInput, type RollbackPolicyVersionResponse, type RuleAction, type RuleOperator, type RuleType, type RunGuardedCheckoutResult, type SdkKey, type SdkKeyType, type StripeLinkCheckoutReadiness, type StripeLinkCheckoutReadinessResult, type StripeLinkCheckoutReadinessStatus, type StripeLinkCheckoutVerification, type StripeLinkPaymentMethod, type UnfreezeAgentInput, type UpdateAgentInput, type UpdateExternalCardAssignmentInput, type UpdatePolicyInput, type UpdatePolicyRuleInput, type UpdateWalletInput, type VerifiedBrowserCheckoutTarget, type Wallet, type WalletChainBalanceSnapshot, type WalletStatus, type WalletType, type X402BudgetResult, type X402PreAuthorizeInput, type X402PreAuthorizeResult, type X402RecordInput, type X402RecordResult, canonicalizeBrowserCheckoutTarget, createVerifiedBrowserCheckoutDriver, Conto as default, fingerprintBrowserCheckoutTarget };
2481
+ export { type AdminExternalCardOverlayEnforcement, type Agent, type AgentCheckoutAction, type AgentCheckoutActionKind, type AgentExternalCard, type AgentSetupResult, type AgentStatus, type AgentType, type AgentWalletLink, type ApprovedExternalCardExecution, type AssignExternalCardInput, type AssignedPolicy, type AuthorizeCheckoutActionResult, type BeginCommerceExecutionInput, type BrowserActionClaimResult, type BrowserActionDispatchObservationInput, BrowserActionFinalizationPendingError, type BrowserActionFinalizeResult, type BrowserCheckoutAction, type BrowserCheckoutTargetResolver, type BrowserCheckoutTargetSnapshot, type BrowserCheckoutTargetVerificationCode, BrowserCheckoutTargetVerificationError, type CanonicalBrowserCheckoutTargetSnapshot, CardsClient, type ChainType, type CheckoutActionAuthorization, type CommerceCheckoutMethod, type CommerceContextRequirement, type CommerceExecution, type CommerceExecutionAdapterKind, type CommerceExecutionArtifactKind, type CommerceExecutionChannel, type CommerceExecutionConstraint, type CommerceExecutionConstraintCoverage, type CommerceExecutionConstraintCoverageLevel, type CommerceExecutionDeliveryMode, type CommerceExecutionEvidence, type CommerceExecutionProvider, type CommerceExecutionResult, type CommerceExecutionSourceKind, type CommerceExecutionStatus, type CommerceFactConfidence, type CommerceFactProvenanceInput, type CommerceFactSource, type CommerceFulfillmentInput, type CommerceLineItemInput, type CommerceProposalFactKey, type CommerceProposalMissingFact, type CommerceProposalResolution, type CommerceProposalState, type CommerceSettlementRail, type CommerceTotalInput, type CommerceTotalType, type ComparePolicyVersionsResponse, type ConnectedCardBrief, type ConnectedCardCredential, type ConnectedCardDrawInput, type ConnectedCardDrawMerchant, type ConnectedCardDrawResult, type ConnectedCardDrawable, type ConnectedCardListResult, type ConnectedCardMandate, type ConnectedCardMandateMerchant, type ConnectedCardReference, ConnectedCardsClient, Conto, ContoAdmin, type ContoAdminConfig, ContoAdminError, type ContoConfig, ContoError, type ContoRequestOptions, type ControlledExternalCardPaymentResult, ControlledExternalCardPaymentTool, type CreateAgentInput, type CreatePolicyInput, type CreatePolicyRuleInput, type CreateSdkKeyInput, type CreateSdkKeyResult, type CreateWalletInput, type CustodyType, type CustomerCustodyMode, type CustomerWalletControlModel, type CustomerWalletKeyAccess, type DelegationType, type ExecuteCommerceExecutionResult, type ExternalCard, type ExternalCardApprovalInput, type ExternalCardApprovalResult, type ExternalCardConfirmationInput, ExternalCardConfirmationPendingError, type ExternalCardConfirmationResult, type ExternalCardExecutionClaimResult, type ExternalCardExecutionResult, type ExternalCardExecutor, type ExternalCardOverlayEnforcement, type ExternalCardRequestStatusResult, type ExternalWalletApprovalInput, type ExternalWalletApprovalResult, type ExternalWalletConfirmationInput, type ExternalWalletConfirmationResult, type FreezeAgentInput, Conto as Giro, type ContoConfig as GiroConfig, ContoError as GiroError, type GuardCheckoutResult, type GuardedBrowserDispatchResult, type GuardedCheckoutInput, type LinkWalletInput, type ListAgentsParams, type ListAgentsResponse, type ListPoliciesParams, type ListPoliciesResponse, type ListPolicyVersionsResponse, type ListStripeLinkPaymentMethodsResult, type ListWalletsParams, type ListWalletsResponse, type MppBudgetResult, type MppPreAuthorizeInput, type MppPreAuthorizeResult, type MppRecordInput, type MppRecordResult, type NormalizeCommerceProposalInput, type OrganizationMember, type PaginatedResponse, type PaginationParams, type PauseExternalCardAssignmentResult, type PaymentExecuteResult, type PaymentRequestInput, type PaymentRequestResult, type PaymentStatusResult, type Policy, type PolicyRule, type PolicyType, type PolicyVersionChangeType, type PolicyVersionDetail, type PolicyVersionDiff, type PolicyVersionFieldChange, type PolicyVersionSnapshot, type PolicyVersionSnapshotRule, type PolicyVersionSummary, type PrivilegedBrowserCheckoutDriver, type ProtocolBudgetResult, type ProtocolPreAuthorizeResult, type ProtocolRecordGrant, type ProtocolRecordGrantResult, type ProtocolServiceSummary, type ProtocolServicesResult, type ProvisionWalletResult, type RefreshBalanceResult, type RegisterExternalCardInput, type RollbackPolicyVersionResponse, type RuleAction, type RuleOperator, type RuleType, type RunGuardedCheckoutResult, type SdkKey, type SdkKeyType, type StripeLinkCheckoutReadiness, type StripeLinkCheckoutReadinessResult, type StripeLinkCheckoutReadinessStatus, type StripeLinkCheckoutVerification, type StripeLinkPaymentMethod, type UnfreezeAgentInput, type UpdateAgentInput, type UpdateExternalCardAssignmentInput, type UpdatePolicyInput, type UpdatePolicyRuleInput, type UpdateWalletInput, type VerifiedBrowserCheckoutTarget, type Wallet, type WalletChainBalanceSnapshot, type WalletStatus, type WalletType, type X402Authorization, type X402BudgetResult, type X402PayInput, type X402PayResult, type X402PaymentRequirements, type X402PreAuthorizeInput, type X402PreAuthorizeResult, type X402RecordInput, type X402RecordResult, canonicalizeBrowserCheckoutTarget, createVerifiedBrowserCheckoutDriver, Conto as default, fingerprintBrowserCheckoutTarget };
package/dist/index.js CHANGED
@@ -39,7 +39,7 @@ var require_package = __commonJS({
39
39
  "package.json"(exports2, module2) {
40
40
  module2.exports = {
41
41
  name: "@conto_finance/sdk",
42
- version: "0.4.0",
42
+ version: "0.5.1",
43
43
  description: "Conto SDK for AI agent payment authorization",
44
44
  main: "./dist/index.js",
45
45
  module: "./dist/index.mjs",
@@ -172,7 +172,10 @@ var PUBLIC_PAYMENT_REASONS = /* @__PURE__ */ new Set([
172
172
  "This payment is outside the permitted schedule.",
173
173
  "The available payment budget is insufficient.",
174
174
  "This payment does not meet the current payment controls.",
175
- "This payment requires approval before it can proceed."
175
+ "This payment requires approval before it can proceed.",
176
+ "No usable wallet is linked to this agent.",
177
+ "This payee needs review before payments to it can proceed automatically.",
178
+ "A reviewer declined this payment."
176
179
  ]);
177
180
  function customerPaymentReasons(value) {
178
181
  return Array.isArray(value) ? [
@@ -352,9 +355,11 @@ function responseErrorMetadata(response, data) {
352
355
  const body = record(data);
353
356
  const code = safeErrorCode(body.code, response.status);
354
357
  const bodyRetryAfter = typeof body.retryAfter === "number" || typeof body.retryAfter === "string" ? parseRetryAfter(String(body.retryAfter)) : void 0;
358
+ const reasons = customerPaymentReasons(body.reasons);
355
359
  return {
356
360
  code,
357
361
  status: response.status,
362
+ ...reasons.length > 0 ? { reasons } : {},
358
363
  fieldErrors: customerFieldErrors(body, response.status),
359
364
  requestId: safeRequestId(
360
365
  response.headers.get("x-request-id"),
@@ -1705,6 +1710,27 @@ var ConnectedCardsClient = class {
1705
1710
  return this.client.request("GET", "/api/sdk/connected-cards");
1706
1711
  }
1707
1712
  };
1713
+ function approvalRetryGuidance(requestId) {
1714
+ const id = JSON.stringify(requestId);
1715
+ return `An approver in Conto executes the payment when they approve it. After approval, call payments.execute(${id}) or payments.status(${id}) to get the receipt. Do not request the payment again.`;
1716
+ }
1717
+ function executeRetryGuidance(code, requestId) {
1718
+ const id = JSON.stringify(requestId);
1719
+ switch (code) {
1720
+ case "APPROVAL_PENDING":
1721
+ return approvalRetryGuidance(requestId);
1722
+ case "POLICY_DENIED_AT_EXECUTION":
1723
+ case "PAYMENT_DENIED":
1724
+ return "This payment was declined and will not execute. Do not retry it; review the reasons before requesting a new payment.";
1725
+ case "POLICY_REAPPROVAL_REQUIRED":
1726
+ return "This payment now needs approval and will not execute. Request a new payment and wait for approval.";
1727
+ case "PAYMENT_PROCESSING":
1728
+ case "NEEDS_RECONCILIATION":
1729
+ return `Do not execute again. Check payments.status(${id}) for the outcome.`;
1730
+ default:
1731
+ return void 0;
1732
+ }
1733
+ }
1708
1734
  var PaymentsClient = class {
1709
1735
  constructor(client) {
1710
1736
  this.client = client;
@@ -1778,7 +1804,9 @@ var PaymentsClient = class {
1778
1804
  * Execute an approved payment.
1779
1805
  *
1780
1806
  * This sends the onchain transaction. Only works for payments
1781
- * with status 'APPROVED'.
1807
+ * with status 'APPROVED'. If an approver already executed the payment by
1808
+ * approving it in Conto, this returns the existing receipt with
1809
+ * `alreadyExecuted: true` and sends nothing.
1782
1810
  *
1783
1811
  * @param requestId - The requestId from a successful payment request
1784
1812
  *
@@ -1800,18 +1828,17 @@ var PaymentsClient = class {
1800
1828
  {}
1801
1829
  );
1802
1830
  } catch (error) {
1803
- if (error instanceof ContoError && error.status === 0) {
1804
- throw new ContoError(error.message, {
1805
- code: error.code,
1806
- status: error.status,
1807
- requestId: error.requestId,
1808
- retryAfter: error.retryAfter,
1809
- retryGuidance: `Check payments.status(${JSON.stringify(
1810
- requestId
1811
- )}) before attempting execution again.`
1812
- });
1813
- }
1814
- throw error;
1831
+ if (!(error instanceof ContoError)) throw error;
1832
+ const retryGuidance = error.status === 0 ? `Check payments.status(${JSON.stringify(requestId)}) before attempting execution again.` : executeRetryGuidance(error.code, requestId);
1833
+ if (!retryGuidance) throw error;
1834
+ throw new ContoError(error.message, {
1835
+ code: error.code,
1836
+ status: error.status,
1837
+ requestId: error.requestId,
1838
+ retryAfter: error.retryAfter,
1839
+ reasons: error.reasons,
1840
+ retryGuidance
1841
+ });
1815
1842
  }
1816
1843
  }
1817
1844
  /**
@@ -1876,17 +1903,9 @@ var PaymentsClient = class {
1876
1903
  throw new ContoError("Payment requires manual approval", {
1877
1904
  code: "REQUIRES_APPROVAL",
1878
1905
  status: 202,
1906
+ reasons: customerPaymentReasons(request.reasons),
1879
1907
  requestId: request.requestId,
1880
- retryGuidance: "Wait for approval, then execute the same request ID."
1881
- });
1882
- }
1883
- if (request.status === "ACTION_REQUIRED") {
1884
- throw new ContoError("Payment requires an additional action", {
1885
- code: "ACTION_REQUIRED",
1886
- status: 402,
1887
- requestId: request.requestId,
1888
- actionUrl: request.actionUrl,
1889
- retryGuidance: request.actionUrl ? `Complete the required action at ${request.actionUrl}, then check the payment status.` : "Complete the required action, then check the payment status."
1908
+ retryGuidance: approvalRetryGuidance(request.requestId)
1890
1909
  });
1891
1910
  }
1892
1911
  if (request.status === "PROCESSING") {
@@ -1912,6 +1931,22 @@ var X402Client = class {
1912
1931
  { idempotent: true }
1913
1932
  );
1914
1933
  }
1934
+ /**
1935
+ * Conto-signed x402 for Privy-managed EVM wallets. Conto evaluates the
1936
+ * payment exactly like preAuthorize() and, only when approved, signs the
1937
+ * EIP-3009 authorization for the approved payee and amount. Retry the
1938
+ * resource request with `paymentHeaderName: xPaymentHeader`, then call
1939
+ * record() with the returned grant. Not retried automatically: a grant is
1940
+ * signed at most once, and a repeat returns 409 GRANT_ALREADY_SIGNED.
1941
+ * External wallets get 409 MANAGED_SIGNING_UNAVAILABLE; use preAuthorize().
1942
+ */
1943
+ async pay(input) {
1944
+ return this.client.request(
1945
+ "POST",
1946
+ "/api/sdk/x402/pay",
1947
+ input
1948
+ );
1949
+ }
1915
1950
  async record(input) {
1916
1951
  const paymentId = requireFinancialIdentifier(input.paymentId, "paymentId");
1917
1952
  const requestInput = {
package/dist/index.mjs CHANGED
@@ -14,7 +14,7 @@ var require_package = __commonJS({
14
14
  "package.json"(exports, module) {
15
15
  module.exports = {
16
16
  name: "@conto_finance/sdk",
17
- version: "0.4.0",
17
+ version: "0.5.1",
18
18
  description: "Conto SDK for AI agent payment authorization",
19
19
  main: "./dist/index.js",
20
20
  module: "./dist/index.mjs",
@@ -128,7 +128,10 @@ var PUBLIC_PAYMENT_REASONS = /* @__PURE__ */ new Set([
128
128
  "This payment is outside the permitted schedule.",
129
129
  "The available payment budget is insufficient.",
130
130
  "This payment does not meet the current payment controls.",
131
- "This payment requires approval before it can proceed."
131
+ "This payment requires approval before it can proceed.",
132
+ "No usable wallet is linked to this agent.",
133
+ "This payee needs review before payments to it can proceed automatically.",
134
+ "A reviewer declined this payment."
132
135
  ]);
133
136
  function customerPaymentReasons(value) {
134
137
  return Array.isArray(value) ? [
@@ -308,9 +311,11 @@ function responseErrorMetadata(response, data) {
308
311
  const body = record(data);
309
312
  const code = safeErrorCode(body.code, response.status);
310
313
  const bodyRetryAfter = typeof body.retryAfter === "number" || typeof body.retryAfter === "string" ? parseRetryAfter(String(body.retryAfter)) : void 0;
314
+ const reasons = customerPaymentReasons(body.reasons);
311
315
  return {
312
316
  code,
313
317
  status: response.status,
318
+ ...reasons.length > 0 ? { reasons } : {},
314
319
  fieldErrors: customerFieldErrors(body, response.status),
315
320
  requestId: safeRequestId(
316
321
  response.headers.get("x-request-id"),
@@ -1544,6 +1549,27 @@ var ConnectedCardsClient = class {
1544
1549
  return this.client.request("GET", "/api/sdk/connected-cards");
1545
1550
  }
1546
1551
  };
1552
+ function approvalRetryGuidance(requestId) {
1553
+ const id = JSON.stringify(requestId);
1554
+ return `An approver in Conto executes the payment when they approve it. After approval, call payments.execute(${id}) or payments.status(${id}) to get the receipt. Do not request the payment again.`;
1555
+ }
1556
+ function executeRetryGuidance(code, requestId) {
1557
+ const id = JSON.stringify(requestId);
1558
+ switch (code) {
1559
+ case "APPROVAL_PENDING":
1560
+ return approvalRetryGuidance(requestId);
1561
+ case "POLICY_DENIED_AT_EXECUTION":
1562
+ case "PAYMENT_DENIED":
1563
+ return "This payment was declined and will not execute. Do not retry it; review the reasons before requesting a new payment.";
1564
+ case "POLICY_REAPPROVAL_REQUIRED":
1565
+ return "This payment now needs approval and will not execute. Request a new payment and wait for approval.";
1566
+ case "PAYMENT_PROCESSING":
1567
+ case "NEEDS_RECONCILIATION":
1568
+ return `Do not execute again. Check payments.status(${id}) for the outcome.`;
1569
+ default:
1570
+ return void 0;
1571
+ }
1572
+ }
1547
1573
  var PaymentsClient = class {
1548
1574
  constructor(client) {
1549
1575
  this.client = client;
@@ -1617,7 +1643,9 @@ var PaymentsClient = class {
1617
1643
  * Execute an approved payment.
1618
1644
  *
1619
1645
  * This sends the onchain transaction. Only works for payments
1620
- * with status 'APPROVED'.
1646
+ * with status 'APPROVED'. If an approver already executed the payment by
1647
+ * approving it in Conto, this returns the existing receipt with
1648
+ * `alreadyExecuted: true` and sends nothing.
1621
1649
  *
1622
1650
  * @param requestId - The requestId from a successful payment request
1623
1651
  *
@@ -1639,18 +1667,17 @@ var PaymentsClient = class {
1639
1667
  {}
1640
1668
  );
1641
1669
  } catch (error) {
1642
- if (error instanceof ContoError && error.status === 0) {
1643
- throw new ContoError(error.message, {
1644
- code: error.code,
1645
- status: error.status,
1646
- requestId: error.requestId,
1647
- retryAfter: error.retryAfter,
1648
- retryGuidance: `Check payments.status(${JSON.stringify(
1649
- requestId
1650
- )}) before attempting execution again.`
1651
- });
1652
- }
1653
- throw error;
1670
+ if (!(error instanceof ContoError)) throw error;
1671
+ const retryGuidance = error.status === 0 ? `Check payments.status(${JSON.stringify(requestId)}) before attempting execution again.` : executeRetryGuidance(error.code, requestId);
1672
+ if (!retryGuidance) throw error;
1673
+ throw new ContoError(error.message, {
1674
+ code: error.code,
1675
+ status: error.status,
1676
+ requestId: error.requestId,
1677
+ retryAfter: error.retryAfter,
1678
+ reasons: error.reasons,
1679
+ retryGuidance
1680
+ });
1654
1681
  }
1655
1682
  }
1656
1683
  /**
@@ -1715,17 +1742,9 @@ var PaymentsClient = class {
1715
1742
  throw new ContoError("Payment requires manual approval", {
1716
1743
  code: "REQUIRES_APPROVAL",
1717
1744
  status: 202,
1745
+ reasons: customerPaymentReasons(request.reasons),
1718
1746
  requestId: request.requestId,
1719
- retryGuidance: "Wait for approval, then execute the same request ID."
1720
- });
1721
- }
1722
- if (request.status === "ACTION_REQUIRED") {
1723
- throw new ContoError("Payment requires an additional action", {
1724
- code: "ACTION_REQUIRED",
1725
- status: 402,
1726
- requestId: request.requestId,
1727
- actionUrl: request.actionUrl,
1728
- retryGuidance: request.actionUrl ? `Complete the required action at ${request.actionUrl}, then check the payment status.` : "Complete the required action, then check the payment status."
1747
+ retryGuidance: approvalRetryGuidance(request.requestId)
1729
1748
  });
1730
1749
  }
1731
1750
  if (request.status === "PROCESSING") {
@@ -1751,6 +1770,22 @@ var X402Client = class {
1751
1770
  { idempotent: true }
1752
1771
  );
1753
1772
  }
1773
+ /**
1774
+ * Conto-signed x402 for Privy-managed EVM wallets. Conto evaluates the
1775
+ * payment exactly like preAuthorize() and, only when approved, signs the
1776
+ * EIP-3009 authorization for the approved payee and amount. Retry the
1777
+ * resource request with `paymentHeaderName: xPaymentHeader`, then call
1778
+ * record() with the returned grant. Not retried automatically: a grant is
1779
+ * signed at most once, and a repeat returns 409 GRANT_ALREADY_SIGNED.
1780
+ * External wallets get 409 MANAGED_SIGNING_UNAVAILABLE; use preAuthorize().
1781
+ */
1782
+ async pay(input) {
1783
+ return this.client.request(
1784
+ "POST",
1785
+ "/api/sdk/x402/pay",
1786
+ input
1787
+ );
1788
+ }
1754
1789
  async record(input) {
1755
1790
  const paymentId = requireFinancialIdentifier(input.paymentId, "paymentId");
1756
1791
  const requestInput = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conto_finance/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Conto SDK for AI agent payment authorization",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",