@conto_finance/sdk 0.6.0-beta.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
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.
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
5
  See [buyer-side control](https://conto.finance/docs/introduction/concepts) for the authorization
6
6
  and execution boundary.
7
7
 
@@ -60,74 +60,52 @@ if (request.status === 'APPROVED') {
60
60
  }
61
61
  ```
62
62
 
63
- ## Link Pay Token checkout pilot
63
+ ## Checkout checkpoints
64
64
 
65
- Install the Link pilot with `npm install @conto_finance/sdk@0.6.0-beta.1` (the `beta` channel).
66
- For a credential-free local workflow test:
65
+ Use `conto.checkout` when your agent runs its own checkout. Call Conto right before the payment
66
+ method opens and again right before the payment is submitted. Conto checks the agent's rules at
67
+ both points and holds the spend in between. Your checkout must stop whenever a call fails.
67
68
 
68
- ```typescript
69
- import { createLinkTestClient } from '@conto_finance/sdk/link-testing';
70
- const test = createLinkTestClient({ scenario: 'approved' });
71
- // Use the purchase shape below, then simulate the owner's approval explicitly.
72
- const payment = await test.link.pay(purchase);
73
- await test.link.approve(payment.executionId);
74
- const result = await test.link.resume(payment.executionId);
75
- // result.mode === 'SIMULATED'; result.settlementVerified === false
76
- ```
77
-
78
- Scenarios include `approved`, `denied`, `expired`, and `interrupted`. This in-memory simulator
79
- makes no network calls and does not validate real policy, credentials, checkout, or settlement.
80
- It uses the same SDK workflow helper; the live client has no `approve()` method.
81
-
82
-
83
- SDK 0.6.0-beta.1 adds a one-call payment helper for configured live Link checkouts. The stable
84
- 0.5.5 package does not include this helper.
85
- This remains an assisted pilot: an operator configures the checkout profile and a signed-in owner
86
- connects Link and binds it to your agent. Only self-contained USD digital-goods checkouts are
87
- supported. See the [runnable example](../../examples/link-checkout-sdk/README.md) for package
88
- installation and the [operator setup](../../docs/STRIPE_LINK_PAY_TOKEN_RUNTIME.md) for prerequisites.
69
+ Checkout checkpoints need SDK 0.6.0 or later.
89
70
 
90
71
  ```typescript
91
- const conto = new Conto({
92
- apiKey: process.env.CONTO_API_KEY!,
93
- link: { connectionId: 'owner_connection_id', paymentMethodId: 'selected_payment_method_id' },
72
+ let checkpoint = await conto.checkout.begin({
73
+ idempotencyKey: order.id,
74
+ merchant: { id: 'acme-retail', name: 'ACME Retail', checkoutUrl: page.url() },
75
+ amountMinor: 7900,
76
+ purpose: 'Drip coffee maker the shopper chose',
77
+ lineItems: [{ name: 'Drip coffee maker', quantity: 1, unitAmountMinor: 7900 }],
78
+ });
79
+ if (checkpoint.stage === 'AWAITING_APPROVAL') {
80
+ // The agent's rules need the owner. Throws if the owner rejects or the approval expires.
81
+ checkpoint = await conto.checkout.waitForApproval(checkpoint, { timeoutMs: 15 * 60_000 });
82
+ }
83
+ // Open Link. The buyer signs in and the final total appears.
84
+
85
+ const confirmed = await conto.checkout.confirm(checkpoint, {
86
+ amountMinor: finalTotal,
87
+ totals: finalTotals, // tax and shipping, if the total changed
94
88
  });
89
+ // Submit the payment, then report what happened.
95
90
 
96
- // Save one idempotency key per purchase before sending. These are illustrative cart values.
97
- const purchase = {
98
- idempotencyKey: 'persisted_order_123',
99
- merchantId: 'configured_checkout_profile',
100
- checkoutUrl: 'https://shop.example/checkout/order_123',
101
- amountMinor: 1200,
102
- purpose: 'Purchase a digital report',
103
- lineItems: [{ name: 'Digital report', quantity: 1, unitAmountMinor: 1200 }],
104
- };
105
- const payment = await conto.link.pay(purchase);
91
+ await conto.checkout.reportOutcome(confirmed.id, { outcome: 'PAID', reference: orderNumber });
106
92
  ```
107
93
 
108
- Before paying, call `await conto.link.setup({ merchantId: purchase.merchantId })` with an
109
- `agents:read` key. It returns versioned checks with the responsible actor and missing payment
110
- scopes, including owner binding/expiry, deployment profiles, runtime configuration, and the
111
- active wallet assignment currently required for budget reservations. It runs while the execution
112
- gate is off, reads metadata only, and never authorizes a purchase. `configurationStatus:
113
- 'CONFIGURED'` is not proof of provider connectivity, policy approval, available funds, or settlement.
114
-
115
- Persist `payment.executionId`. When `nextAction` is `APPROVE_IN_LINK`, show `payment.approvalUrl`
116
- to the owner. After approval, call `await conto.link.resume(payment.executionId)` to continue that
117
- same purchase. `await conto.link.status(payment.executionId)` refreshes evidence without paying;
118
- `cancel(id)` requests cancellation. `paymentMethods()` lists masked LIVE funding sources using
119
- the configured connection. No method returns a Link credential.
120
-
121
- `pay()` executes immediately only when the server returns READY. It never polls indefinitely or
122
- retries an execution write. Policy denial and pending Conto approval throw `ContoError` before
123
- Link is called. An execution/cancellation error is a `LinkPaymentExecutionError` with the original
124
- `executionId` and `nextAction: 'RECONCILE'`; inspect `link.status(error.executionId)` before any
125
- further payment action. Do not create another purchase to recover from an uncertain result.
126
-
127
- Supply `totals` when tax, fees, or discounts change the amount from the line-item sum. Server
128
- checkout verification remains authoritative. `PROCESSING` or `COMPLETED` does not prove
129
- settlement. The helper simplifies SDK calls; owner login, profile setup, and live validation are
130
- still required, and separate unrestricted payment tools remain outside this flow.
94
+ - Open the payment method only when the stage is `APPROVED`. When the rules require approval,
95
+ `begin()` returns `AWAITING_APPROVAL`, holds the spend, and asks the owner.
96
+ `waitForApproval()` resolves to the approved checkpoint, whose 30 minutes to confirm start at
97
+ the approval. It throws `CheckoutApprovalDeniedError`, `CheckoutApprovalExpiredError`, or
98
+ `CheckoutApprovalTimeoutError`. After a timeout the spend stays held until you cancel.
99
+ - If the final total differs from the approved one, `confirm()` starts a new checkpoint at the
100
+ final total, so the rules check the amount actually paid. If that total needs approval,
101
+ `confirm()` throws `CheckoutApprovalPendingError`: wait with
102
+ `waitForApproval(error.checkpoint)`, then confirm the checkpoint it returns.
103
+ - `begin()` throws `CheckoutCheckpointClosedError` when its idempotency key belongs to a
104
+ checkpoint that already closed. Start a new purchase with a new key.
105
+ - `reportOutcome()` accepts `PAID`, `NOT_PAID`, or `UNKNOWN`. Until an outcome arrives, the spend
106
+ stays counted. Cancel an unconfirmed checkpoint with `conto.checkout.cancel(id)`.
107
+ - Conto records what your checkout reports and does not see the charge. For control at the
108
+ moment of payment, pay with a Conto-managed wallet or a card Conto authorizes.
131
109
 
132
110
  ## External-card Policy Overlay
133
111
 
@@ -189,6 +167,16 @@ const result = await conto.payments.pay({
189
167
  });
190
168
  ```
191
169
 
170
+ ## Connected-card delivery
171
+
172
+ For an organization with connected cards enabled, `conto.connectedCards.draw()` returns a disposable
173
+ credential exactly once. Keep it in memory and use it at the mandate's merchant before
174
+ `credentialExpiresAt`. Never log or persist it. After receipt, call
175
+ `conto.connectedCards.acknowledgeDelivery(draw.requestId)`. Acknowledgement is idempotent and records
176
+ delivery only, not payment settlement. Replaying the original draw key cannot recover a lost
177
+ credential. Check the original outcome before requesting a replacement. Issued capacity stays
178
+ consumed even when checkout fails.
179
+
192
180
  ## Protocol Clients
193
181
 
194
182
  `Conto` also exposes typed helpers for x402 and MPP service payments:
@@ -229,7 +217,7 @@ automatically. The record response then includes `policyBypass: true`, `bypassRe
229
217
  `agentFrozen`.
230
218
 
231
219
  For a Privy-managed EVM wallet, `conto.x402.pay` replaces `preAuthorize`. Pass the same fields
232
- plus the accepted 402 requirements; when approved, Conto signs the payment and returns the header
220
+ plus the accepted 402 requirements. When approved, Conto signs the payment and returns the header
233
221
  to retry with:
234
222
 
235
223
  ```typescript
@@ -255,82 +243,21 @@ The MPP client mirrors the same shape with `conto.mpp.preAuthorize`, `conto.mpp.
255
243
  `conto.mpp.budget`, and `conto.mpp.services`. An MPP session grant is a ceiling: several
256
244
  `record` calls with the same `sessionId` may draw it down until it is used up or expires.
257
245
 
258
- ## Stripe Link Checkout Commerce (test only)
259
-
260
- `LINK_CHECKOUT` is test-only and works only with a merchant enrolled with Conto. It is not a
261
- general merchant integration. It evaluates policy before creating an ordinary Stripe-hosted
262
- Checkout Session with card and Link enabled. It needs no private Link SDK permission,
263
- Link connection, saved payment-method ID, SPT, or LPT.
264
-
265
- Commerce execution responses separate the provider-neutral `executionChannel`, optional
266
- `checkoutMethod`, and optional `settlementRail` from the legacy provider and adapter identifiers.
267
- For dynamic hosted Checkout, `checkoutMethod` remains absent until settlement observes Link or the
268
- card fallback; callers must not treat the adapter name as proof that Link was selected.
269
-
270
- ```typescript
271
- let { execution } = await conto.beginCommerceExecution({
272
- executionMethod: 'LINK_CHECKOUT',
273
- idempotencyKey: crypto.randomUUID(),
274
- amountMinor: 6400,
275
- currency: 'USD',
276
- category: 'OFFICE_SUPPLIES',
277
- purpose: 'Office supplies',
278
- counterparty: {
279
- canonicalId: 'conto-demo-office-supply',
280
- },
281
- cart: {
282
- lineItems: [{ name: 'Office supplies', quantity: 1, unitAmountMinor: 6400 }],
283
- totals: [{ type: 'total', label: 'Total', amountMinor: 6400 }],
284
- },
285
- providerPresentation: {
286
- approvalSummary: 'Buy office supplies from the configured merchant',
287
- lineItemLabels: ['Office supplies'],
288
- },
289
- });
290
-
291
- if (execution.status !== 'ACTION_REQUIRED' || !execution.approvalUrl) {
292
- throw new Error('Stripe Checkout was not created safely');
293
- }
294
-
295
- if (execution.executionAdapter !== 'LINK_CHECKOUT') {
296
- throw new Error('Unexpected commerce execution adapter');
297
- }
298
-
299
- // Hand the temporary capability to a trusted interactive browser/UI. Do not log it.
300
- await presentCheckoutActionSecurely(execution.approvalUrl);
301
-
302
- while (execution.status === 'ACTION_REQUIRED' || execution.status === 'PROCESSING') {
303
- ({ execution } = await conto.refreshCommerceExecution(execution.id));
304
- }
305
-
306
- if (execution.status !== 'SETTLED' || execution.evidence.actualPaymentMethod !== 'LINK') {
307
- throw new Error('This execution did not settle with Link');
308
- }
309
- ```
310
-
311
- Stripe decides whether Link appears and whether the customer chooses it. Card is an explicit
312
- fallback, surfaced as `actualPaymentMethod: 'CARD'`; it is a valid payment but not Link evidence.
313
- The read-only `getCommerceExecution` projection redacts action URLs; use the initial begin result or
314
- the `payments:confirm` refresh path while action remains required.
315
- The server resolves the exact merchant name, Stripe account, and return URLs from configuration, so
316
- the caller cannot redirect the approved purchase. This path covers only that enrolled merchant's
317
- Conto channel, not unrelated Checkout pages or the consumer's Link wallet. See
318
- `docs/STRIPE_LINK_CHECKOUT_ADAPTER.md` for configuration, webhook, drill, and reconciliation
319
- requirements.
320
-
321
246
  ## Agent checkout guard
322
247
 
323
248
  For browser checkouts on supported rails (Link, card, Shop Pay, or PayPal), use
324
249
  `runGuardedCheckout` with `executionMethod: 'BROWSER_CHECKOUT'`. Other rails and checkout flows are
325
250
  not covered. It binds and atomically authorizes one exact Link, card,
326
251
  Shop Pay, or PayPal browser action without requiring private provider integration. The
327
- privileged browser executor must be available only through this wrapper; an unrestricted click or
328
- payment tool would bypass the control. Persist its stable dispatch attempt before calling the helper; it owns authorization,
329
- one-use claim, the privileged callback, and finalization. See `docs/AGENT_CHECKOUT_GUARD.md` for the
330
- runtime boundary and example.
252
+ privileged browser executor must be available only through this wrapper. An unrestricted click or
253
+ payment tool would bypass the control. Persist its stable dispatch attempt before calling the
254
+ helper. The helper owns authorization, one-use claim, the privileged callback, and finalization.
255
+ The
256
+ [Stripe Link guide](https://conto.finance/docs/guides/stripe-link#make-the-check-enforceable)
257
+ describes the runtime boundary and includes an example.
331
258
 
332
259
  Isolated browser processes can implement `PrivilegedBrowserCheckoutDriver` and use
333
- `runGuardedCheckoutWithDriver`; the agent model must receive only that guarded wrapper, never the
260
+ `runGuardedCheckoutWithDriver`. The agent model must receive only that guarded wrapper, never the
334
261
  driver's `dispatch` primitive. Generate `action.targetFingerprint` with
335
262
  `fingerprintBrowserCheckoutTarget` during inspection, then wrap the privileged target resolver with
336
263
  `createVerifiedBrowserCheckoutDriver`. The wrapper re-hashes the current page, locator, accessible
@@ -340,7 +267,7 @@ the action's `targetUrl`, allowing Conto's origin trust policy to evaluate them
340
267
 
341
268
  For Browserbase, use the first-class provider host. Its binding store must reject duplicate session
342
269
  IDs and atomically revoke only an active record matching the supplied organization, agent, and
343
- project. Store the credential-free binding durably; never add the provider `connectUrl` to it.
270
+ project. Store the credential-free binding durably, and never add the provider `connectUrl` to it.
344
271
 
345
272
  ```typescript
346
273
  import {
@@ -392,15 +319,15 @@ export const POST = host.handler;
392
319
  The Browserbase host exposes `handler`, `createSession`, `attachSession`, `observeSession`,
393
320
  `liveViewForSession`, `releaseSession`, `detachSession`, and `close`. `observeSession` returns only a
394
321
  bounded page origin/title and visible
395
- link/button outline; it excludes full page text, DOM, form values, URL paths and queries,
322
+ link/button outline. It excludes full page text, DOM, form values, URL paths and queries,
396
323
  screenshots, cookies, storage, and provider capabilities. It rechecks ownership and page identity
397
324
  after observing.
398
325
  `createSession` returns a session ID, active status, and expiry without a connection URL.
399
326
  `liveViewForSession` is a privileged operator capability: expose it only behind separate human
400
327
  authentication, never as an agent tool. A configured Context persists login state but must remain
401
- server-side; its durable binding store should prevent concurrent sessions from sharing one Context.
328
+ server-side. Its durable binding store should prevent concurrent sessions from sharing one Context.
402
329
  `releaseSession` atomically revokes Conto ownership before closing the local connection and asking
403
- Browserbase to release the keep-alive session. Call it when the agent session ends; `close` only
330
+ Browserbase to release the keep-alive session. Call it when the agent session ends. `close` only
404
331
  closes local Playwright connections. `attachSession` accepts only a five-minute HMAC assertion
405
332
  binding the exact provider project, Conto organization, agent, session, and expiry. Its matching
406
333
  `detachSession` revokes Conto access and closes the local connection without releasing the
@@ -412,12 +339,12 @@ For another Playwright or secure CDP provider, use
412
339
  exposes only `handler`, `observeSession`, `closeSession`, and `close`, keeping discovery, mutation
413
340
  primitives, the target store, the Playwright page, and raw dispatch private.
414
341
  Lower-level integrations can still compose `createGuardedPlaywrightCheckoutRuntime`, whose façade
415
- exposes only `discover` and `run`; the raw driver is not returned. Target
342
+ exposes only `discover` and `run`. The raw driver is not returned. Target
416
343
  registrations expire after ten minutes by default. The encrypted store persists only ciphertext
417
344
  through a small durable blob port, so a runtime restart does not lose an approved
418
345
  target or disclose its locator. `dispatchAttemptFor` must atomically return the same persisted ID for
419
346
  the same checkout intent. The dispatch result classifies the browser outcome as `NEW_PAGE`,
420
- `PAGE_NAVIGATION`, or `SAME_PAGE`, but always reports settlement as `UNVERIFIED`; only merchant or
347
+ `PAGE_NAVIGATION`, or `SAME_PAGE`, but always reports settlement as `UNVERIFIED`. Only merchant or
421
348
  provider evidence can prove payment. Never expose the page, target store, persisted registrations,
422
349
  or provider-derived locator state to the model. The inert positional reference returned by
423
350
  `observeSession` is the only locator intended for the model.
@@ -441,15 +368,15 @@ ambiguous-dispatch probes pass.
441
368
 
442
369
  The probe runner belongs to the trusted integration host and must execute against an isolated
443
370
  fixture session. A report does not remotely attest an untrusted host or discover tools omitted from
444
- its inventory. See `docs/CHECKOUT_INTEGRATION_VERIFIER.md` for the manifest, probe, and status
445
- contract.
371
+ its inventory. The types exported from `@conto_finance/sdk/checkout-verifier` define the
372
+ manifest, probe, and status contract.
446
373
 
447
374
  The HTTP handler implements the authenticated endpoint consumed by the optional
448
375
  `guarded_browser_checkout` MCP tool. It accepts Web `Request` objects, so it can be mounted directly
449
376
  in a compatible route or adapted to a Node server. It authenticates before reading the body,
450
377
  rejects unknown fields and mismatched cart totals, performs discovery and guarded execution in one
451
378
  request, and returns only minimized browser evidence. Use a dedicated random token of at least 32
452
- characters; the handler rejects Conto API keys.
379
+ characters. The handler rejects Conto API keys.
453
380
 
454
381
  Organization-specific proposal facts can be sent through the typed normalization call after an
455
382
  owner or administrator registers the namespace schema:
@@ -470,60 +397,6 @@ const proposal = await conto.normalizeCommerceProposal({
470
397
  Conto rejects unregistered namespaces and schema-invalid values before policy evaluation. Accepted
471
398
  facts are bound to the schema revision and fingerprint returned on the normalized proposal.
472
399
 
473
- ## Stripe Link Sandbox Commerce
474
-
475
- The gated Stripe Link sandbox surface uses the agent key for policy evaluation and execution. A
476
- Link connection must first be created by its user and explicitly bound to the agent through the
477
- authenticated session API. The agent SDK never receives the Link access token or payment artifact.
478
-
479
- ```typescript
480
- const linkContext = await conto.listStripeLinkPaymentMethods(connectionId);
481
- if (linkContext.organizationId !== expectedOrganizationId) {
482
- throw new Error('Agent key belongs to the wrong Conto organization');
483
- }
484
- const { paymentMethods } = linkContext;
485
-
486
- let { execution } = await conto.beginCommerceExecution({
487
- connectionId,
488
- paymentMethodId: paymentMethods[0].id,
489
- executionMethod: 'STRIPE_PAYMENT_INTENT',
490
- idempotencyKey: crypto.randomUUID(),
491
- amountMinor: 6400,
492
- currency: 'USD',
493
- purpose: 'Office supplies',
494
- counterparty: {
495
- canonicalId: 'conto-demo-office-supply',
496
- displayName: 'Conto Demo Office Supply',
497
- },
498
- cart: {
499
- lineItems: [{ name: 'Office supplies', quantity: 1, unitAmountMinor: 6400 }],
500
- totals: [{ type: 'total', label: 'Total', amountMinor: 6400 }],
501
- },
502
- providerPresentation: {
503
- approvalSummary: 'Buy office supplies from Conto Demo Office Supply',
504
- lineItemLabels: ['Office supplies'],
505
- },
506
- });
507
-
508
- if (execution.status === 'AWAITING_APPROVAL') {
509
- // Present execution.approvalUrl to the Link user, then poll with refresh.
510
- ({ execution } = await conto.refreshCommerceExecution(execution.id));
511
- }
512
-
513
- if (execution.status === 'READY') {
514
- const result = await conto.executeCommerceExecution(execution.id);
515
- console.log(result.execution.evidence, result.execution.evidenceFingerprint);
516
- }
517
- ```
518
-
519
- Use `getCommerceExecution(id)` for read-only reconciliation and
520
- `cancelCommerceExecution(id)` to cancel a nonterminal execution. `beginCommerceExecution` safely
521
- retries with its stable idempotency key, and `refreshCommerceExecution` safely retries observation.
522
- Checkout execution and cancellation are not transport-retried.
523
- The Stripe account and Link business-network profile are resolved from server-owned configuration;
524
- an agent cannot supply or replace them. Use `executionMethod: 'MPP'` only for the optional,
525
- configured MPP compatibility transport.
526
-
527
400
  ## Admin SDK Quick Start
528
401
 
529
402
  `ContoAdmin` uses an organization API key (`conto_xxx...`), not an agent SDK key.
@@ -558,27 +431,6 @@ if (frozen) {
558
431
  }
559
432
  ```
560
433
 
561
- ### Stripe Link Checkout readiness
562
-
563
- Organization administrators can inspect the configured merchant Checkout adapter without calling
564
- Stripe, then explicitly verify that Conto's configured credential resolves to its configured
565
- merchant account:
566
-
567
- ```typescript
568
- const { readiness } = await admin.paymentRails.getStripeLinkCheckoutReadiness();
569
-
570
- if (readiness.canVerify && !readiness.checks.accountVerified) {
571
- const verified = await admin.paymentRails.verifyStripeLinkCheckoutAccount();
572
- console.log(verified.readiness.status, verified.readiness.verification);
573
- }
574
- ```
575
-
576
- The result contains only mode, booleans, safe status codes, timestamps, and scope statements. It
577
- never contains merchant/account identifiers, URLs, credentials, hashes, Stripe objects, or raw
578
- provider errors. Verification proves the configured account match only; Stripe still decides
579
- whether Link is eligible, displayed, and selected at Checkout. The static GET is retry-safe; the
580
- active POST verification is not automatically retried.
581
-
582
434
  ## What This Package Covers
583
435
 
584
436
  - `Conto` for agent-scoped payment flows
@@ -591,7 +443,7 @@ active POST verification is not automatically retried.
591
443
  The SDK automatically adds an idempotency key to wallet payment authorization
592
444
  requests. Provide your own stable `idempotencyKey` when a retry may happen in
593
445
  another process or job attempt. External-card approvals always require a stable
594
- caller-supplied `idempotencyKey`; card approval and confirmation are safe to
446
+ caller-supplied `idempotencyKey`. Card approval and confirmation are safe to
595
447
  retry. x402 and MPP pre-authorization calls issue a grant and reserve spend. A retry
596
448
  with the same `paymentId` (x402) or `challengeId`/`credentialId` (MPP) returns the
597
449
  same live grant instead of reserving again.
@@ -601,7 +453,7 @@ ambiguous failure can be reconciled safely.
601
453
  Read-only calls retry transient network failures, `429`, and `5xx` responses. Financial execution
602
454
  and other non-idempotent mutations are never retried automatically. If execution times out, call
603
455
  `conto.payments.status(requestId)` before attempting it again. A
604
- `reconciliation_required` status means the execution outcome is ambiguous; do not resend the
456
+ `reconciliation_required` status means the execution outcome is ambiguous. Do not resend the
605
457
  payment until an operator has resolved it.
606
458
 
607
459
  `ContoError` and `ContoAdminError` expose a stable error contract: `code`, `status`, `requestId`,
@@ -637,14 +489,4 @@ try {
637
489
 
638
490
  MIT
639
491
 
640
- Developer support: [support@conto.finance](mailto:support@conto.finance). Include the package version and request ID; never include API keys.
641
-
642
- ### Connected-card delivery
643
-
644
- For an organization with connected cards enabled, `conto.connectedCards.draw()` returns a disposable
645
- credential exactly once. Keep it in memory and use it at the mandate's merchant before
646
- `credentialExpiresAt`. Never log or persist it. After receipt, call
647
- `conto.connectedCards.acknowledgeDelivery(draw.requestId)`. Acknowledgement is idempotent and records
648
- delivery only, not payment settlement. Replaying the original draw key cannot recover a lost
649
- credential; check the original outcome before requesting a replacement. Issued capacity stays
650
- consumed even when checkout fails.
492
+ Developer support: [support@conto.finance](mailto:support@conto.finance). Include the package version and request ID. Never include API keys.