@conto_finance/sdk 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +357 -6
- package/dist/browserbase.d.mts +141 -0
- package/dist/browserbase.d.ts +141 -0
- package/dist/browserbase.js +1985 -0
- package/dist/browserbase.mjs +608 -0
- package/dist/checkout-verifier.d.mts +95 -0
- package/dist/checkout-verifier.d.ts +95 -0
- package/dist/checkout-verifier.js +400 -0
- package/dist/checkout-verifier.mjs +372 -0
- package/dist/chunk-B7F5QLE5.mjs +34 -0
- package/dist/chunk-HM4EG5MH.mjs +1256 -0
- package/dist/chunk-O5RAAB2U.mjs +123 -0
- package/dist/index.d.mts +1065 -14
- package/dist/index.d.ts +1065 -14
- package/dist/index.js +792 -59
- package/dist/index.mjs +676 -85
- package/dist/playwright.d.mts +255 -0
- package/dist/playwright.d.ts +255 -0
- package/dist/playwright.js +1394 -0
- package/dist/playwright.mjs +22 -0
- package/package.json +31 -6
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. Merchants do not install Conto.
|
|
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
|
|
|
@@ -19,6 +24,11 @@ npm install @conto_finance/sdk
|
|
|
19
24
|
An admin SDK key is still an agent SDK key. It keeps the `conto_agent_...` prefix, so it is not a
|
|
20
25
|
drop-in replacement for `ContoAdmin`.
|
|
21
26
|
|
|
27
|
+
## Verify the connection
|
|
28
|
+
|
|
29
|
+
Requires Node.js 20.19+. Call `await conto.setup()` to inspect your agent, linked wallets,
|
|
30
|
+
effective policies, and scopes without creating a payment.
|
|
31
|
+
|
|
22
32
|
## Agent SDK Quick Start
|
|
23
33
|
|
|
24
34
|
```typescript
|
|
@@ -113,7 +123,9 @@ const cardAccess = new ContoCardAccess({
|
|
|
113
123
|
Card Access claims each approved request exactly once before the executor can run. A
|
|
114
124
|
duplicate or uncertain claim cannot invoke the executor again. It remains
|
|
115
125
|
bypassable if another person or tool can access the card, and results are
|
|
116
|
-
self-reported rather than issuer-verified. The
|
|
126
|
+
self-reported rather than issuer-verified. The executor receives the normalized
|
|
127
|
+
purchase `idempotencyKey`; pass it to the payment processor so ambiguous
|
|
128
|
+
processor responses cannot create duplicate charges. The legacy `conto.cards.controlled()`
|
|
117
129
|
helper remains available for compatibility, but new customer-hosted enforcement
|
|
118
130
|
should use the standalone Card Access package. Use
|
|
119
131
|
`admin.cards.listRequests({ status: 'EXECUTING' })` for reconciliation and
|
|
@@ -137,14 +149,16 @@ const result = await conto.payments.pay({
|
|
|
137
149
|
```typescript
|
|
138
150
|
const paymentId = crypto.randomUUID();
|
|
139
151
|
|
|
140
|
-
await conto.x402.preAuthorize({
|
|
152
|
+
const decision = await conto.x402.preAuthorize({
|
|
141
153
|
amount: 0.01,
|
|
142
154
|
recipientAddress: '0x...',
|
|
143
155
|
resourceUrl: 'https://api.example.com/v1/search',
|
|
144
156
|
paymentId,
|
|
145
157
|
sessionId: 'session_123',
|
|
146
158
|
});
|
|
159
|
+
if (!decision.authorized) throw new Error(decision.message);
|
|
147
160
|
|
|
161
|
+
// Sign and settle the x402 payment, then record it with the grant.
|
|
148
162
|
await conto.x402.record({
|
|
149
163
|
amount: 0.01,
|
|
150
164
|
recipientAddress: '0x...',
|
|
@@ -152,13 +166,316 @@ await conto.x402.record({
|
|
|
152
166
|
paymentId,
|
|
153
167
|
txHash: '0x...',
|
|
154
168
|
sessionId: 'session_123',
|
|
169
|
+
grantId: decision.grantId,
|
|
170
|
+
grantSignature: decision.grantSignature,
|
|
155
171
|
});
|
|
156
172
|
|
|
157
173
|
const budget = await conto.x402.budget();
|
|
158
174
|
```
|
|
159
175
|
|
|
176
|
+
An approved `preAuthorize` returns a single-use grant (`grantId`, `grantSignature`,
|
|
177
|
+
`grantExpiresAt`) for that wallet, recipient, and amount, and reserves the amount against the
|
|
178
|
+
agent's spend limits for 10 minutes. Pass the grant to `record`. A record without a valid,
|
|
179
|
+
unexpired grant is still accepted because the payment already settled, but Conto flags it as a
|
|
180
|
+
policy bypass and raises a critical alert. Organizations can also have the agent frozen
|
|
181
|
+
automatically. The record response then includes `policyBypass: true`, `bypassReason`, and
|
|
182
|
+
`agentFrozen`.
|
|
183
|
+
|
|
184
|
+
For a Privy-managed EVM wallet, `conto.x402.pay` replaces `preAuthorize`. Pass the same fields
|
|
185
|
+
plus the accepted 402 requirements; when approved, Conto signs the payment and returns the header
|
|
186
|
+
to retry with:
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
const paid = await conto.x402.pay({
|
|
190
|
+
amount: 0.01,
|
|
191
|
+
recipientAddress: requirements.payTo,
|
|
192
|
+
resourceUrl: 'https://api.example.com/v1/search',
|
|
193
|
+
paymentId,
|
|
194
|
+
paymentRequirements: requirements, // accepted entry from the 402 challenge
|
|
195
|
+
});
|
|
196
|
+
if (!paid.authorized) throw new Error(paid.message);
|
|
197
|
+
|
|
198
|
+
const response = await fetch('https://api.example.com/v1/search', {
|
|
199
|
+
headers: { [paid.paymentHeaderName!]: paid.xPaymentHeader! },
|
|
200
|
+
});
|
|
201
|
+
// Then record with paid.grantId, paid.grantSignature, and the settlement txHash.
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`pay` is not retried automatically: each grant is signed once, and a repeat returns
|
|
205
|
+
`GRANT_ALREADY_SIGNED`. External wallets get `MANAGED_SIGNING_UNAVAILABLE`.
|
|
206
|
+
|
|
160
207
|
The MPP client mirrors the same shape with `conto.mpp.preAuthorize`, `conto.mpp.record`,
|
|
161
|
-
`conto.mpp.budget`, and `conto.mpp.services`.
|
|
208
|
+
`conto.mpp.budget`, and `conto.mpp.services`. An MPP session grant is a ceiling: several
|
|
209
|
+
`record` calls with the same `sessionId` may draw it down until it is used up or expires.
|
|
210
|
+
|
|
211
|
+
## Stripe Link Checkout Commerce (test only)
|
|
212
|
+
|
|
213
|
+
`LINK_CHECKOUT` is test-only and works only with a merchant enrolled with Conto. It is not a
|
|
214
|
+
general merchant integration. It evaluates policy before creating an ordinary Stripe-hosted
|
|
215
|
+
Checkout Session with card and Link enabled. It needs no private Link SDK permission,
|
|
216
|
+
Link connection, saved payment-method ID, SPT, or LPT.
|
|
217
|
+
|
|
218
|
+
Commerce execution responses separate the provider-neutral `executionChannel`, optional
|
|
219
|
+
`checkoutMethod`, and optional `settlementRail` from the legacy provider and adapter identifiers.
|
|
220
|
+
For dynamic hosted Checkout, `checkoutMethod` remains absent until settlement observes Link or the
|
|
221
|
+
card fallback; callers must not treat the adapter name as proof that Link was selected.
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
let { execution } = await conto.beginCommerceExecution({
|
|
225
|
+
executionMethod: 'LINK_CHECKOUT',
|
|
226
|
+
idempotencyKey: crypto.randomUUID(),
|
|
227
|
+
amountMinor: 6400,
|
|
228
|
+
currency: 'USD',
|
|
229
|
+
category: 'OFFICE_SUPPLIES',
|
|
230
|
+
purpose: 'Office supplies',
|
|
231
|
+
counterparty: {
|
|
232
|
+
canonicalId: 'conto-demo-office-supply',
|
|
233
|
+
},
|
|
234
|
+
cart: {
|
|
235
|
+
lineItems: [{ name: 'Office supplies', quantity: 1, unitAmountMinor: 6400 }],
|
|
236
|
+
totals: [{ type: 'total', label: 'Total', amountMinor: 6400 }],
|
|
237
|
+
},
|
|
238
|
+
providerPresentation: {
|
|
239
|
+
approvalSummary: 'Buy office supplies from the configured merchant',
|
|
240
|
+
lineItemLabels: ['Office supplies'],
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
if (execution.status !== 'ACTION_REQUIRED' || !execution.approvalUrl) {
|
|
245
|
+
throw new Error('Stripe Checkout was not created safely');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (execution.executionAdapter !== 'LINK_CHECKOUT') {
|
|
249
|
+
throw new Error('Unexpected commerce execution adapter');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Hand the temporary capability to a trusted interactive browser/UI. Do not log it.
|
|
253
|
+
await presentCheckoutActionSecurely(execution.approvalUrl);
|
|
254
|
+
|
|
255
|
+
while (execution.status === 'ACTION_REQUIRED' || execution.status === 'PROCESSING') {
|
|
256
|
+
({ execution } = await conto.refreshCommerceExecution(execution.id));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (execution.status !== 'SETTLED' || execution.evidence.actualPaymentMethod !== 'LINK') {
|
|
260
|
+
throw new Error('This execution did not settle with Link');
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Stripe decides whether Link appears and whether the customer chooses it. Card is an explicit
|
|
265
|
+
fallback, surfaced as `actualPaymentMethod: 'CARD'`; it is a valid payment but not Link evidence.
|
|
266
|
+
The read-only `getCommerceExecution` projection redacts action URLs; use the initial begin result or
|
|
267
|
+
the `payments:confirm` refresh path while action remains required.
|
|
268
|
+
The server resolves the exact merchant name, Stripe account, and return URLs from configuration, so
|
|
269
|
+
the caller cannot redirect the approved purchase. This path covers only that enrolled merchant's
|
|
270
|
+
Conto channel, not unrelated Checkout pages or the consumer's Link wallet. See
|
|
271
|
+
`docs/STRIPE_LINK_CHECKOUT_ADAPTER.md` for configuration, webhook, drill, and reconciliation
|
|
272
|
+
requirements.
|
|
273
|
+
|
|
274
|
+
## Agent checkout guard
|
|
275
|
+
|
|
276
|
+
For browser checkouts on supported rails (Link, card, Shop Pay, or PayPal), use
|
|
277
|
+
`runGuardedCheckout` with `executionMethod: 'BROWSER_CHECKOUT'`. Other rails and checkout flows are
|
|
278
|
+
not covered. It binds and atomically authorizes one exact Link, card,
|
|
279
|
+
Shop Pay, or PayPal browser action without requiring merchant or private provider integration. The
|
|
280
|
+
privileged browser executor must be available only through this wrapper; an unrestricted click or
|
|
281
|
+
payment tool would bypass the control. Persist its stable dispatch attempt before calling the helper; it owns authorization,
|
|
282
|
+
one-use claim, the privileged callback, and finalization. See `docs/AGENT_CHECKOUT_GUARD.md` for the
|
|
283
|
+
runtime boundary and example.
|
|
284
|
+
|
|
285
|
+
Isolated browser processes can implement `PrivilegedBrowserCheckoutDriver` and use
|
|
286
|
+
`runGuardedCheckoutWithDriver`; the agent model must receive only that guarded wrapper, never the
|
|
287
|
+
driver's `dispatch` primitive. Generate `action.targetFingerprint` with
|
|
288
|
+
`fingerprintBrowserCheckoutTarget` during inspection, then wrap the privileged target resolver with
|
|
289
|
+
`createVerifiedBrowserCheckoutDriver`. The wrapper re-hashes the current page, locator, accessible
|
|
290
|
+
name, destination, form action, and disabled state immediately before dispatch and refuses any
|
|
291
|
+
changed target without clicking it. Observed link and form destinations must be explicitly bound as
|
|
292
|
+
the action's `targetUrl`, allowing Conto's origin trust policy to evaluate them before the claim.
|
|
293
|
+
|
|
294
|
+
For Browserbase, use the first-class provider host. Its binding store must reject duplicate session
|
|
295
|
+
IDs and atomically revoke only an active record matching the supplied organization, agent, and
|
|
296
|
+
project. Store the credential-free binding durably; never add the provider `connectUrl` to it.
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
import {
|
|
300
|
+
createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost,
|
|
301
|
+
createBrowserbaseSessionHandoffAssertion,
|
|
302
|
+
} from '@conto_finance/sdk/browserbase';
|
|
303
|
+
import { chromium } from 'playwright-core';
|
|
304
|
+
|
|
305
|
+
const host = createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost({
|
|
306
|
+
conto,
|
|
307
|
+
browserbase: {
|
|
308
|
+
apiKey: process.env.BROWSERBASE_API_KEY!,
|
|
309
|
+
projectId: process.env.BROWSERBASE_PROJECT_ID!,
|
|
310
|
+
organizationId,
|
|
311
|
+
agentId,
|
|
312
|
+
bindingStore: browserbaseSessionBindings,
|
|
313
|
+
contextId: process.env.BROWSERBASE_CONTEXT_ID,
|
|
314
|
+
handoffKey: Buffer.from(process.env.CONTO_BROWSER_HANDOFF_KEY!, 'base64'),
|
|
315
|
+
},
|
|
316
|
+
connectOverCDP: (connectUrl) => chromium.connectOverCDP(connectUrl),
|
|
317
|
+
targetStore: {
|
|
318
|
+
encryptionKey: Buffer.from(process.env.CONTO_BROWSER_TARGET_KEY!, 'base64'),
|
|
319
|
+
blobStore: durableTargetBlobs,
|
|
320
|
+
},
|
|
321
|
+
dispatchAttemptFor: ({ idempotencyKey }) => attempts.loadOrCreate(idempotencyKey),
|
|
322
|
+
token: process.env.CONTO_BROWSER_RUNTIME_TOKEN!,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const browser = await host.createSession();
|
|
326
|
+
// Give browser.browserSessionId, never a provider connection URL, to the guarded agent runtime.
|
|
327
|
+
|
|
328
|
+
// Or attach a session created by the customer's trusted Browserbase backend.
|
|
329
|
+
const browserSessionId = customerBrowserbaseSession.id;
|
|
330
|
+
const expiresAt = new Date(Date.now() + 60_000).toISOString();
|
|
331
|
+
const handoffAssertion = createBrowserbaseSessionHandoffAssertion(
|
|
332
|
+
{
|
|
333
|
+
browserSessionId,
|
|
334
|
+
projectId: process.env.BROWSERBASE_PROJECT_ID!,
|
|
335
|
+
organizationId,
|
|
336
|
+
agentId,
|
|
337
|
+
expiresAt,
|
|
338
|
+
},
|
|
339
|
+
Buffer.from(process.env.CONTO_BROWSER_HANDOFF_KEY!, 'base64')
|
|
340
|
+
);
|
|
341
|
+
await host.attachSession({ browserSessionId, handoffAssertion });
|
|
342
|
+
export const POST = host.handler;
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
The Browserbase host exposes `handler`, `createSession`, `attachSession`, `observeSession`,
|
|
346
|
+
`liveViewForSession`, `releaseSession`, `detachSession`, and `close`. `observeSession` returns only a
|
|
347
|
+
bounded page origin/title and visible
|
|
348
|
+
link/button outline; it excludes full page text, DOM, form values, URL paths and queries,
|
|
349
|
+
screenshots, cookies, storage, and provider capabilities. It rechecks ownership and page identity
|
|
350
|
+
after observing.
|
|
351
|
+
`createSession` returns a session ID, active status, and expiry without a connection URL.
|
|
352
|
+
`liveViewForSession` is a privileged operator capability: expose it only behind separate human
|
|
353
|
+
authentication, never as an agent tool. A configured Context persists login state but must remain
|
|
354
|
+
server-side; its durable binding store should prevent concurrent sessions from sharing one Context.
|
|
355
|
+
`releaseSession` atomically revokes Conto ownership before closing the local connection and asking
|
|
356
|
+
Browserbase to release the keep-alive session. Call it when the agent session ends; `close` only
|
|
357
|
+
closes local Playwright connections. `attachSession` accepts only a five-minute HMAC assertion
|
|
358
|
+
binding the exact provider project, Conto organization, agent, session, and expiry. Its matching
|
|
359
|
+
`detachSession` revokes Conto access and closes the local connection without releasing the
|
|
360
|
+
agent-host-owned provider session. Keep the independent 32-byte handoff key and assertions outside
|
|
361
|
+
the model and browser page.
|
|
362
|
+
|
|
363
|
+
For another Playwright or secure CDP provider, use
|
|
364
|
+
`createGuardedPlaywrightCheckoutRuntimeHost` from `@conto_finance/sdk/playwright`. The generic host
|
|
365
|
+
exposes only `handler`, `observeSession`, `closeSession`, and `close`, keeping discovery, mutation
|
|
366
|
+
primitives, the target store, the Playwright page, and raw dispatch private.
|
|
367
|
+
Lower-level integrations can still compose `createGuardedPlaywrightCheckoutRuntime`, whose façade
|
|
368
|
+
exposes only `discover` and `run`; the raw driver is not returned. Target
|
|
369
|
+
registrations expire after ten minutes by default. The encrypted store persists only ciphertext
|
|
370
|
+
through a small durable blob port, so a runtime restart does not lose an approved
|
|
371
|
+
target or disclose its locator. `dispatchAttemptFor` must atomically return the same persisted ID for
|
|
372
|
+
the same checkout intent. The dispatch result classifies the browser outcome as `NEW_PAGE`,
|
|
373
|
+
`PAGE_NAVIGATION`, or `SAME_PAGE`, but always reports settlement as `UNVERIFIED`; only merchant or
|
|
374
|
+
provider evidence can prove payment. Never expose the page, target store, persisted registrations,
|
|
375
|
+
or provider-derived locator state to the model. The inert positional reference returned by
|
|
376
|
+
`observeSession` is the only locator intended for the model.
|
|
377
|
+
|
|
378
|
+
The generic CDP registry accepts connection URLs only from exact secure origins and rechecks
|
|
379
|
+
`connectUrlForSession` ownership on every lookup. Revocation closes a cached connection. It caches
|
|
380
|
+
one connection per owned session and requires exactly one open page unless the runtime supplies
|
|
381
|
+
an exact `selectPage` callback. Keep Browserbase API keys and `connectUrl` values in the privileged process.
|
|
382
|
+
Call `closeSession` only when the agent session is finished because closing the Playwright browser
|
|
383
|
+
may end the provider session.
|
|
384
|
+
|
|
385
|
+
### Verify the exclusive checkout path
|
|
386
|
+
|
|
387
|
+
Use `@conto_finance/sdk/checkout-verifier` during agent-host onboarding and whenever its tool
|
|
388
|
+
registry changes. The manifest inventories every capability exposed to the model, identifies the
|
|
389
|
+
session ownership boundary, and names the supported checkout methods. The verifier reports
|
|
390
|
+
`ADVISORY` when an unrestricted payment-capable browser tool remains available and `UNVERIFIED`
|
|
391
|
+
when active probes have not run. It reports `ENFORCEABLE` and `canBypass: false` only after the
|
|
392
|
+
complete inventory is isolated and all denial, replay, tamper, alternate-path, and
|
|
393
|
+
ambiguous-dispatch probes pass.
|
|
394
|
+
|
|
395
|
+
The probe runner belongs to the trusted integration host and must execute against an isolated
|
|
396
|
+
fixture session. A report does not remotely attest an untrusted host or discover tools omitted from
|
|
397
|
+
its inventory. See `docs/CHECKOUT_INTEGRATION_VERIFIER.md` for the manifest, probe, and status
|
|
398
|
+
contract.
|
|
399
|
+
|
|
400
|
+
The HTTP handler implements the authenticated endpoint consumed by the optional
|
|
401
|
+
`guarded_browser_checkout` MCP tool. It accepts Web `Request` objects, so it can be mounted directly
|
|
402
|
+
in a compatible route or adapted to a Node server. It authenticates before reading the body,
|
|
403
|
+
rejects unknown fields and mismatched cart totals, performs discovery and guarded execution in one
|
|
404
|
+
request, and returns only minimized browser evidence. Use a dedicated random token of at least 32
|
|
405
|
+
characters; the handler rejects Conto API keys.
|
|
406
|
+
|
|
407
|
+
Organization-specific proposal facts can be sent through the typed normalization call after an
|
|
408
|
+
owner or administrator registers the namespace schema:
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
const proposal = await conto.normalizeCommerceProposal({
|
|
412
|
+
proposalKey: 'office-toner-2026-09-02',
|
|
413
|
+
purpose: 'Purchase toner for operations',
|
|
414
|
+
extensions: [
|
|
415
|
+
{
|
|
416
|
+
namespace: 'acme.procurement.v1',
|
|
417
|
+
value: { costCenter: 'OPS', project: 'AP_AUTOMATION' },
|
|
418
|
+
},
|
|
419
|
+
],
|
|
420
|
+
});
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
Conto rejects unregistered namespaces and schema-invalid values before policy evaluation. Accepted
|
|
424
|
+
facts are bound to the schema revision and fingerprint returned on the normalized proposal.
|
|
425
|
+
|
|
426
|
+
## Stripe Link Sandbox Commerce
|
|
427
|
+
|
|
428
|
+
The gated Stripe Link sandbox surface uses the agent key for policy evaluation and execution. A
|
|
429
|
+
Link connection must first be created by its user and explicitly bound to the agent through the
|
|
430
|
+
authenticated session API. The agent SDK never receives the Link access token or payment artifact.
|
|
431
|
+
|
|
432
|
+
```typescript
|
|
433
|
+
const linkContext = await conto.listStripeLinkPaymentMethods(connectionId);
|
|
434
|
+
if (linkContext.organizationId !== expectedOrganizationId) {
|
|
435
|
+
throw new Error('Agent key belongs to the wrong Conto organization');
|
|
436
|
+
}
|
|
437
|
+
const { paymentMethods } = linkContext;
|
|
438
|
+
|
|
439
|
+
let { execution } = await conto.beginCommerceExecution({
|
|
440
|
+
connectionId,
|
|
441
|
+
paymentMethodId: paymentMethods[0].id,
|
|
442
|
+
executionMethod: 'STRIPE_PAYMENT_INTENT',
|
|
443
|
+
idempotencyKey: crypto.randomUUID(),
|
|
444
|
+
amountMinor: 6400,
|
|
445
|
+
currency: 'USD',
|
|
446
|
+
purpose: 'Office supplies',
|
|
447
|
+
counterparty: {
|
|
448
|
+
canonicalId: 'conto-demo-office-supply',
|
|
449
|
+
displayName: 'Conto Demo Office Supply',
|
|
450
|
+
},
|
|
451
|
+
cart: {
|
|
452
|
+
lineItems: [{ name: 'Office supplies', quantity: 1, unitAmountMinor: 6400 }],
|
|
453
|
+
totals: [{ type: 'total', label: 'Total', amountMinor: 6400 }],
|
|
454
|
+
},
|
|
455
|
+
providerPresentation: {
|
|
456
|
+
approvalSummary: 'Buy office supplies from Conto Demo Office Supply',
|
|
457
|
+
lineItemLabels: ['Office supplies'],
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
if (execution.status === 'AWAITING_APPROVAL') {
|
|
462
|
+
// Present execution.approvalUrl to the Link user, then poll with refresh.
|
|
463
|
+
({ execution } = await conto.refreshCommerceExecution(execution.id));
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
if (execution.status === 'READY') {
|
|
467
|
+
const result = await conto.executeCommerceExecution(execution.id);
|
|
468
|
+
console.log(result.execution.evidence, result.execution.evidenceFingerprint);
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Use `getCommerceExecution(id)` for read-only reconciliation and
|
|
473
|
+
`cancelCommerceExecution(id)` to cancel a nonterminal execution. `beginCommerceExecution` safely
|
|
474
|
+
retries with its stable idempotency key, and `refreshCommerceExecution` safely retries observation.
|
|
475
|
+
Checkout execution and cancellation are not transport-retried.
|
|
476
|
+
The Stripe account and Link business-network profile are resolved from server-owned configuration;
|
|
477
|
+
an agent cannot supply or replace them. Use `executionMethod: 'MPP'` only for the optional,
|
|
478
|
+
configured MPP compatibility transport.
|
|
162
479
|
|
|
163
480
|
## Admin SDK Quick Start
|
|
164
481
|
|
|
@@ -194,6 +511,27 @@ if (frozen) {
|
|
|
194
511
|
}
|
|
195
512
|
```
|
|
196
513
|
|
|
514
|
+
### Stripe Link Checkout readiness
|
|
515
|
+
|
|
516
|
+
Organization administrators can inspect the configured merchant Checkout adapter without calling
|
|
517
|
+
Stripe, then explicitly verify that Conto's configured credential resolves to its configured
|
|
518
|
+
merchant account:
|
|
519
|
+
|
|
520
|
+
```typescript
|
|
521
|
+
const { readiness } = await admin.paymentRails.getStripeLinkCheckoutReadiness();
|
|
522
|
+
|
|
523
|
+
if (readiness.canVerify && !readiness.checks.accountVerified) {
|
|
524
|
+
const verified = await admin.paymentRails.verifyStripeLinkCheckoutAccount();
|
|
525
|
+
console.log(verified.readiness.status, verified.readiness.verification);
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
The result contains only mode, booleans, safe status codes, timestamps, and scope statements. It
|
|
530
|
+
never contains merchant/account identifiers, URLs, credentials, hashes, Stripe objects, or raw
|
|
531
|
+
provider errors. Verification proves the configured account match only; Stripe still decides
|
|
532
|
+
whether Link is eligible, displayed, and selected at Checkout. The static GET is retry-safe; the
|
|
533
|
+
active POST verification is not automatically retried.
|
|
534
|
+
|
|
197
535
|
## What This Package Covers
|
|
198
536
|
|
|
199
537
|
- `Conto` for agent-scoped payment flows
|
|
@@ -207,7 +545,9 @@ The SDK automatically adds an idempotency key to wallet payment authorization
|
|
|
207
545
|
requests. Provide your own stable `idempotencyKey` when a retry may happen in
|
|
208
546
|
another process or job attempt. External-card approvals always require a stable
|
|
209
547
|
caller-supplied `idempotencyKey`; card approval and confirmation are safe to
|
|
210
|
-
retry. x402 and MPP pre-authorization calls
|
|
548
|
+
retry. x402 and MPP pre-authorization calls issue a grant and reserve spend. A retry
|
|
549
|
+
with the same `paymentId` (x402) or `challengeId`/`credentialId` (MPP) returns the
|
|
550
|
+
same live grant instead of reserving again.
|
|
211
551
|
Record calls require an explicit stable `paymentId` or `credentialId` so an
|
|
212
552
|
ambiguous failure can be reconciled safely.
|
|
213
553
|
|
|
@@ -235,8 +575,7 @@ try {
|
|
|
235
575
|
|
|
236
576
|
## What To Use Instead
|
|
237
577
|
|
|
238
|
-
- Use
|
|
239
|
-
external-wallet `approve -> transfer -> confirm` flows.
|
|
578
|
+
- Use `conto.payments.approve()` and `conto.payments.confirm()` for external wallets. Your own signer sends the transfer between those calls. Neither write retries automatically.
|
|
240
579
|
- Use the MCP server if a tool-calling assistant should operate Conto directly.
|
|
241
580
|
|
|
242
581
|
## Docs
|
|
@@ -250,3 +589,15 @@ try {
|
|
|
250
589
|
## License
|
|
251
590
|
|
|
252
591
|
MIT
|
|
592
|
+
|
|
593
|
+
Developer support: [support@conto.finance](mailto:support@conto.finance). Include the package version and request ID; never include API keys.
|
|
594
|
+
|
|
595
|
+
### Connected-card delivery
|
|
596
|
+
|
|
597
|
+
For an organization with connected cards enabled, `conto.connectedCards.draw()` returns a disposable
|
|
598
|
+
credential exactly once. Keep it in memory and use it at the mandate's merchant before
|
|
599
|
+
`credentialExpiresAt`. Never log or persist it. After receipt, call
|
|
600
|
+
`conto.connectedCards.acknowledgeDelivery(draw.requestId)`. Acknowledgement is idempotent and records
|
|
601
|
+
delivery only, not payment settlement. Replaying the original draw key cannot recover a lost
|
|
602
|
+
credential; check the original outcome before requesting a replacement. Issued capacity stays
|
|
603
|
+
consumed even when checkout fails.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Browser } from 'playwright-core';
|
|
2
|
+
import { GuardedPlaywrightCheckoutHttpHandler, PlaywrightSessionObservation, GuardedPlaywrightCheckoutClient, PlaywrightCdpSessionRegistryConfig, EncryptedPlaywrightCheckoutTargetStoreConfig, GuardedPlaywrightCheckoutRuntimeConfig } from './playwright.mjs';
|
|
3
|
+
import './index.mjs';
|
|
4
|
+
|
|
5
|
+
/** Exact provider endpoints verified against Browserbase's session API; never use a wildcard. */
|
|
6
|
+
declare const BROWSERBASE_CONNECT_ORIGINS: readonly string[];
|
|
7
|
+
type BrowserbaseSessionStatus = 'PENDING' | 'RUNNING' | 'ERROR' | 'TIMED_OUT' | 'COMPLETED';
|
|
8
|
+
type BrowserbaseSessionBindingState = 'ACTIVE' | 'REVOKED';
|
|
9
|
+
type BrowserbaseSessionLifecycleOwner = 'CONTO_RUNTIME' | 'AGENT_HOST';
|
|
10
|
+
/** Credential-free durable record. Never persist Browserbase connect URLs or API keys here. */
|
|
11
|
+
interface BrowserbaseSessionBinding {
|
|
12
|
+
browserSessionId: string;
|
|
13
|
+
organizationId: string;
|
|
14
|
+
agentId: string;
|
|
15
|
+
projectId: string;
|
|
16
|
+
/** Missing legacy values are treated as CONTO_RUNTIME. */
|
|
17
|
+
lifecycleOwner?: BrowserbaseSessionLifecycleOwner;
|
|
18
|
+
state: BrowserbaseSessionBindingState;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
expiresAt: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Durable ownership port for remote sessions. `create` must reject duplicate IDs and `revoke`
|
|
24
|
+
* must atomically transition only an ACTIVE record matching every supplied ownership field.
|
|
25
|
+
*/
|
|
26
|
+
interface BrowserbaseSessionBindingStore {
|
|
27
|
+
create(binding: BrowserbaseSessionBinding): Promise<boolean>;
|
|
28
|
+
get(browserSessionId: string): Promise<BrowserbaseSessionBinding | null>;
|
|
29
|
+
revoke(input: {
|
|
30
|
+
browserSessionId: string;
|
|
31
|
+
organizationId: string;
|
|
32
|
+
agentId: string;
|
|
33
|
+
projectId: string;
|
|
34
|
+
revokedAt: string;
|
|
35
|
+
}): Promise<boolean>;
|
|
36
|
+
/** Required with contextId. Release only after Browserbase confirms the provider session closed. */
|
|
37
|
+
releaseContextLease?(input: {
|
|
38
|
+
browserSessionId: string;
|
|
39
|
+
organizationId: string;
|
|
40
|
+
agentId: string;
|
|
41
|
+
projectId: string;
|
|
42
|
+
}): Promise<boolean>;
|
|
43
|
+
}
|
|
44
|
+
interface BrowserbaseSessionConfig {
|
|
45
|
+
/** Browserbase credential retained by the privileged runtime. Conto credentials are rejected. */
|
|
46
|
+
apiKey: string;
|
|
47
|
+
projectId: string;
|
|
48
|
+
organizationId: string;
|
|
49
|
+
agentId: string;
|
|
50
|
+
bindingStore: BrowserbaseSessionBindingStore;
|
|
51
|
+
/** Optional 32-byte server-only key required to attach sessions created by an agent host. */
|
|
52
|
+
handoffKey?: Uint8Array;
|
|
53
|
+
/** Optional server-only Browserbase Context used to persist Link or merchant authentication. */
|
|
54
|
+
contextId?: string;
|
|
55
|
+
/** Browserbase session timeout. Defaults to 900 seconds. */
|
|
56
|
+
timeoutSeconds?: number;
|
|
57
|
+
/** Browserbase API request timeout. Defaults to 10 seconds and may not exceed 60 seconds. */
|
|
58
|
+
requestTimeoutMs?: number;
|
|
59
|
+
/** Injected for tests or runtimes with an instrumented fetch implementation. */
|
|
60
|
+
fetch?: typeof fetch;
|
|
61
|
+
now?: () => Date;
|
|
62
|
+
}
|
|
63
|
+
interface BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig {
|
|
64
|
+
conto: GuardedPlaywrightCheckoutClient;
|
|
65
|
+
browserbase: BrowserbaseSessionConfig;
|
|
66
|
+
/** Usually `(url) => chromium.connectOverCDP(url)`. */
|
|
67
|
+
connectOverCDP(connectUrl: string): Promise<Browser>;
|
|
68
|
+
selectPage?: PlaywrightCdpSessionRegistryConfig['selectPage'];
|
|
69
|
+
maxSessions?: number;
|
|
70
|
+
targetStore: EncryptedPlaywrightCheckoutTargetStoreConfig;
|
|
71
|
+
dispatchAttemptFor: GuardedPlaywrightCheckoutRuntimeConfig['dispatchAttemptFor'];
|
|
72
|
+
/** Dedicated service credential. Conto and Browserbase API keys are rejected. */
|
|
73
|
+
token: string;
|
|
74
|
+
maxBodyBytes?: number;
|
|
75
|
+
clickTimeoutMs?: number;
|
|
76
|
+
popupTimeoutMs?: number;
|
|
77
|
+
targetTtlMs?: number;
|
|
78
|
+
now?: () => Date;
|
|
79
|
+
}
|
|
80
|
+
/** Safe session projection for the agent-facing browser launcher. */
|
|
81
|
+
interface BrowserbaseOwnedSession {
|
|
82
|
+
browserSessionId: string;
|
|
83
|
+
status: Extract<BrowserbaseSessionStatus, 'PENDING' | 'RUNNING'>;
|
|
84
|
+
expiresAt: string;
|
|
85
|
+
}
|
|
86
|
+
/** Proof-carrying request from a trusted agent host for an existing Browserbase session. */
|
|
87
|
+
interface BrowserbaseSessionHandoff {
|
|
88
|
+
browserSessionId: string;
|
|
89
|
+
handoffAssertion: string;
|
|
90
|
+
}
|
|
91
|
+
/** Safe projection for a session whose provider lifecycle remains owned by the agent host. */
|
|
92
|
+
interface BrowserbaseAttachedSession extends BrowserbaseOwnedSession {
|
|
93
|
+
lifecycleOwner: 'AGENT_HOST';
|
|
94
|
+
}
|
|
95
|
+
interface BrowserbaseSessionHandoffAssertionInput {
|
|
96
|
+
browserSessionId: string;
|
|
97
|
+
projectId: string;
|
|
98
|
+
organizationId: string;
|
|
99
|
+
agentId: string;
|
|
100
|
+
expiresAt: string;
|
|
101
|
+
}
|
|
102
|
+
/** Operator-only capability for a human authentication or challenge handoff. */
|
|
103
|
+
interface BrowserbaseOwnedLiveView {
|
|
104
|
+
browserSessionId: string;
|
|
105
|
+
liveViewUrl: string;
|
|
106
|
+
expiresAt: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Closed Browserbase lifecycle plus guarded checkout façade. It never exposes the provider API
|
|
110
|
+
* key, CDP connection URL, Playwright page, target store, discovery primitive, or raw dispatch.
|
|
111
|
+
*/
|
|
112
|
+
interface BrowserbaseGuardedPlaywrightCheckoutRuntimeHost {
|
|
113
|
+
handler: GuardedPlaywrightCheckoutHttpHandler;
|
|
114
|
+
createSession(): Promise<BrowserbaseOwnedSession>;
|
|
115
|
+
/** Attaches an existing agent-host session after verifying a short-lived server assertion. */
|
|
116
|
+
attachSession(input: BrowserbaseSessionHandoff): Promise<BrowserbaseAttachedSession>;
|
|
117
|
+
/** Read-only, bounded projection of the exact runtime-owned page. */
|
|
118
|
+
observeSession(browserSessionId: string): Promise<PlaywrightSessionObservation>;
|
|
119
|
+
/** Returns a short-lived provider capability only to a separately authenticated operator path. */
|
|
120
|
+
liveViewForSession(browserSessionId: string): Promise<BrowserbaseOwnedLiveView>;
|
|
121
|
+
/** Revokes Conto ownership first, closes the local connection, then releases Browserbase. */
|
|
122
|
+
releaseSession(browserSessionId: string): Promise<void>;
|
|
123
|
+
/** Revokes the Conto binding without ending the externally owned Browserbase session. */
|
|
124
|
+
detachSession(browserSessionId: string): Promise<void>;
|
|
125
|
+
/** Closes local Playwright connections. Call releaseSession for each keep-alive provider session. */
|
|
126
|
+
close(): Promise<void>;
|
|
127
|
+
}
|
|
128
|
+
type BrowserbaseSessionErrorCode = 'BROWSERBASE_CONFIG_INVALID' | 'BROWSERBASE_PROVIDER_UNAVAILABLE' | 'BROWSERBASE_PROVIDER_RESPONSE_INVALID' | 'BROWSERBASE_SESSION_BINDING_FAILED' | 'BROWSERBASE_SESSION_HANDOFF_DISABLED' | 'BROWSERBASE_SESSION_HANDOFF_INVALID' | 'BROWSERBASE_LIVE_VIEW_UNAVAILABLE' | 'BROWSERBASE_SESSION_NOT_OWNED' | 'BROWSERBASE_SESSION_RELEASE_FAILED';
|
|
129
|
+
declare class BrowserbaseSessionError extends Error {
|
|
130
|
+
readonly code: BrowserbaseSessionErrorCode;
|
|
131
|
+
constructor(code: BrowserbaseSessionErrorCode, message: string);
|
|
132
|
+
}
|
|
133
|
+
/** Creates a short-lived assertion after the trusted agent host creates its Browserbase session. */
|
|
134
|
+
declare function createBrowserbaseSessionHandoffAssertion(input: BrowserbaseSessionHandoffAssertionInput, keyValue: Uint8Array): string;
|
|
135
|
+
/**
|
|
136
|
+
* Creates the recommended Browserbase deployment boundary. Provider lifecycle, ownership checks,
|
|
137
|
+
* remote connection resolution, guarded execution, and cleanup remain in one privileged object.
|
|
138
|
+
*/
|
|
139
|
+
declare function createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost(config: BrowserbaseGuardedPlaywrightCheckoutRuntimeHostConfig): BrowserbaseGuardedPlaywrightCheckoutRuntimeHost;
|
|
140
|
+
|
|
141
|
+
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 BrowserbaseSessionStatus, createBrowserbaseGuardedPlaywrightCheckoutRuntimeHost, createBrowserbaseSessionHandoffAssertion };
|