@conto_finance/sdk 0.7.1 → 0.8.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 +137 -12
- package/dist/index.d.mts +382 -18
- package/dist/index.d.ts +382 -18
- package/dist/index.js +779 -123
- package/dist/index.mjs +777 -123
- package/dist/link-wallet.d.mts +11 -2
- package/dist/link-wallet.d.ts +11 -2
- package/dist/link-wallet.js +41 -4
- package/dist/link-wallet.mjs +41 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -106,7 +106,9 @@ await conto.checkout.reportOutcome(confirmed.id, { outcome: 'PAID', reference: o
|
|
|
106
106
|
- `begin()` throws `CheckoutCheckpointClosedError` when its idempotency key belongs to a
|
|
107
107
|
checkpoint that already closed. Start a new purchase with a new key.
|
|
108
108
|
- `reportOutcome()` accepts `PAID`, `NOT_PAID`, or `UNKNOWN`. Until an outcome arrives, the spend
|
|
109
|
-
stays counted. Cancel an unconfirmed checkpoint with `conto.checkout.cancel(id)`.
|
|
109
|
+
stays counted. Cancel an unconfirmed checkpoint with `conto.checkout.cancel(id)`. With a Link
|
|
110
|
+
card, cancel the Link request first, because the checkpoint cancel releases the spend even if the
|
|
111
|
+
card still works.
|
|
110
112
|
- Conto records what your checkout reports and does not see the charge. For control at the
|
|
111
113
|
moment of payment, pay with a Conto-managed wallet or a card Conto authorizes.
|
|
112
114
|
|
|
@@ -154,8 +156,41 @@ const confirmed = await conto.checkout.confirm(result.checkpoint, {
|
|
|
154
156
|
- When the person declines in Link, the request expires, the wait passes `linkApprovalTimeoutMs`,
|
|
155
157
|
or `link-cli` is missing or logged out, `getLinkCard()` cancels the checkpoint to release the
|
|
156
158
|
held spend and throws `LinkCardDeniedError`, `LinkCardExpiredError`, `LinkCardTimeoutError`, or
|
|
157
|
-
`LinkWalletUnavailableError`. All extend `LinkCardError`. Do not pay.
|
|
158
|
-
|
|
159
|
+
`LinkWalletUnavailableError`. All extend `LinkCardError`. Do not pay. If a Link request is already
|
|
160
|
+
on record, it closes that first, and if it cannot, it keeps the hold and throws
|
|
161
|
+
`LINK_CARD_NOT_CANCELLED`. `holdReleased` says whether the checkpoint still holds the spend, not
|
|
162
|
+
whether the card is closed, so follow `error.retryGuidance` whatever its value.
|
|
163
|
+
- Retrying with the same input resumes the same checkpoint and Link request while Conto's approval
|
|
164
|
+
is open. That approval lasts 30 minutes. For about 5 to 10 minutes after it lapses, the stage can
|
|
165
|
+
still read `APPROVED`, so a retry can return the card, but `confirm()` refuses it. Once the stage
|
|
166
|
+
is `OUTCOME_UNKNOWN` with `linkRequestOpen: true`, a retry throws
|
|
167
|
+
`CHECKOUT_CHECKPOINT_NOT_APPROVED`. Once a `confirm()` has started, a retry throws
|
|
168
|
+
`LINK_CARD_NOT_ISSUED` and returns no card. Do not cancel the Link request while a payment may be in
|
|
169
|
+
flight. Follow `error.retryGuidance`.
|
|
170
|
+
- A request in `requires_action` that Link will not resume cannot be retried or cancelled. Link closes
|
|
171
|
+
it on its own, and `error.retryGuidance` gives the steps. `LINK_CARD_DUPLICATE_REQUEST` means Link has
|
|
172
|
+
an open request for another purchase with the same details. `error.retryGuidance` names that request
|
|
173
|
+
and its checkpoint and gives the steps for each stage. Once it closes, start this one with a new
|
|
174
|
+
idempotency key. A `signal` that fires during the owner wait throws
|
|
175
|
+
`LINK_CARD_ABORTED` with the checkpoint, and the spend stays held.
|
|
176
|
+
- `getLinkCard()` and `replaceLinkCard()` tell Conto the Link request ID as soon as Stripe Link
|
|
177
|
+
creates it. If Conto's approval then lapses, or a rule stops `confirm()`, Conto keeps the spend held,
|
|
178
|
+
because the card may still work. The checkpoint moves to stage `OUTCOME_UNKNOWN` with
|
|
179
|
+
`linkRequestOpen: true`. Cancel the Link request, then call `conto.checkout.cancel(id)` to release
|
|
180
|
+
the spend. If the card was used, report `PAID`. If you cannot tell, report `UNKNOWN`, which keeps
|
|
181
|
+
the spend held until the owner records what happened. Otherwise the owner gets a
|
|
182
|
+
review alert and records what happened. If Conto cannot record the request, the SDK cancels it in
|
|
183
|
+
Link, then cancels the checkpoint, and throws `LinkCardError` with code `LINK_CARD_NOT_RECORDED`.
|
|
184
|
+
`holdReleased` says whether the spend was released. If the read fails, a confirm has started, or Link
|
|
185
|
+
cannot cancel a request that is still open, the SDK throws `LINK_CARD_NOT_CANCELLED` instead. Conto
|
|
186
|
+
may have no record of that request, so the hold can end when the approval lapses while the card may
|
|
187
|
+
still work. Retry or cancel before then.
|
|
188
|
+
- `linkCliWallet().cancel()` also succeeds when Link already closed the request. If it throws, the
|
|
189
|
+
card may still work or may have been used, so keep the hold.
|
|
190
|
+
- An owner's not paid decision does not close a Link card, which can work for up to 48 hours. After
|
|
191
|
+
`CheckoutCheckpointClosedError`, if `error.checkpoint.paymentReference` is set, cancel the request
|
|
192
|
+
with `wallet.cancel(error.checkpoint.paymentReference.id)` before you start a new purchase. If that
|
|
193
|
+
call throws, the card may have been used, so do not begin a new purchase.
|
|
159
194
|
- Pass `onLinkApproval` to get Stripe Link's approval page, so a person without the Link app can
|
|
160
195
|
approve on the web while signed in to Link. It is called once, after Conto approves and Link
|
|
161
196
|
creates the request, with `{ checkpoint, linkRequestId, approvalUrl, approvalExpiresAt }`.
|
|
@@ -163,20 +198,108 @@ const confirmed = await conto.checkout.confirm(result.checkpoint, {
|
|
|
163
198
|
stopped while the person had not decided.
|
|
164
199
|
- The card (`number`, `securityValue` for the CVC, `expMonth`, `expYear`, `validUntil`, `last4`,
|
|
165
200
|
`brand`) stays in this process. Printing or serializing the result shows only the last four
|
|
166
|
-
digits. It never appears in an error.
|
|
167
|
-
- The card covers the approved total, so `confirm()`
|
|
168
|
-
|
|
169
|
-
|
|
201
|
+
digits, the brand, and the expiry. It never appears in an error.
|
|
202
|
+
- The card covers the approved total, so `confirm()` refuses a different total for a checkpoint from
|
|
203
|
+
`getLinkCard()` or `onLinkApproval`, even when `paymentReference` is not passed. Call
|
|
204
|
+
`conto.checkout.replaceLinkCard(result, { wallet, amountMinor })` to
|
|
205
|
+
cancel the old card and checkpoint and get a card for the final total. `replaceLinkCard()` always
|
|
206
|
+
reads the checkpoint first. `confirm()` reads it when the total differs and it has no reference,
|
|
207
|
+
including for checkouts without a Link card, so a saved copy is safe to pass. A `getLinkCard()`
|
|
208
|
+
retry reads it after a failure, before it closes a request on record. Those reads need
|
|
209
|
+
`transactions:read`. If the checkpoint was already confirmed, or a different Link request is on
|
|
210
|
+
record, `replaceLinkCard()` throws `LINK_CARD_NOT_REPLACED` and leaves the card and the hold alone.
|
|
211
|
+
Report the outcome instead of replacing a card whose payment may be in flight. If the old card
|
|
212
|
+
closes but Conto does not release the spend, it throws `CHECKPOINT_NOT_CANCELLED`, and trying
|
|
213
|
+
again is safe. If the total changes again, pass the latest result. Do not run it while another
|
|
214
|
+
flow may confirm the same checkpoint.
|
|
170
215
|
- Any `LinkWallet` works in place of `linkCliWallet()`: it creates a card request, waits for
|
|
171
216
|
approval, retrieves the card, and cancels.
|
|
172
217
|
- The protection holds only when the agent cannot also run `link-cli`, use a shell, or call Link
|
|
173
218
|
with your credentials itself.
|
|
174
219
|
- Pass observed final items and charges to `confirm()` even when the total is unchanged.
|
|
175
|
-
The server
|
|
220
|
+
The server checks the items and the final total. Other rows, such as tax and shipping, may
|
|
221
|
+
differ from the ones passed to `begin()`. The trusted host must
|
|
176
222
|
validate the actual merchant and checkout, own a durable one-use payment dispatch
|
|
177
223
|
claim, and keep card use outside model tools. Replaying a confirmed checkpoint is
|
|
178
224
|
not permission to submit payment again.
|
|
179
225
|
|
|
226
|
+
## Shared budgets
|
|
227
|
+
|
|
228
|
+
A shared budget is one limit that several agents draw on. The budget holder sets it in Budgets or with `admin.spending`. A budget stops other payment paths for the agents it covers, listed below. Agents no budget covers are not affected, except a buyer linked to an owner workspace. Until a budget in that workspace covers it, those paths fail with `reasonCode` `LINKED_BUDGET_REQUIRED`.
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// Agent key. Nothing on conto.spending can raise a limit, approve a task, or release a hold.
|
|
232
|
+
const { budgets } = await conto.spending.budgets();
|
|
233
|
+
await conto.spending.preview({
|
|
234
|
+
amount: '40',
|
|
235
|
+
currency: 'USDC',
|
|
236
|
+
sourceId: walletId,
|
|
237
|
+
merchant: recipientAddress,
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// Organization API key.
|
|
241
|
+
await admin.spending.createBudget({
|
|
242
|
+
name: 'Team tools',
|
|
243
|
+
scope: 'AGENTS',
|
|
244
|
+
participantIds: [agentA, agentB],
|
|
245
|
+
amount: '500',
|
|
246
|
+
currency: 'USDC',
|
|
247
|
+
period: 'MONTHLY',
|
|
248
|
+
periodStart: new Date().toISOString(),
|
|
249
|
+
periodEnd: new Date(Date.now() + 365 * 86_400_000).toISOString(),
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**A budget stops other payment paths.** While it exists, it stops x402, MPP, external wallet
|
|
254
|
+
payments, agent-to-agent payments, payment grants, checkout relay, hosted Stripe Link, guarded browser
|
|
255
|
+
checkout (`runGuardedCheckout()`), card overlays and checkout checkpoints, including
|
|
256
|
+
`checkout.getLinkCard()`, for every agent it covers. A paused, expired or not yet started budget still
|
|
257
|
+
stops them. Until its start date, while paused, and after its end date, a budget also refuses the
|
|
258
|
+
managed wallet payments and connected card draws it covers, for those agents. A task's budget stops nothing on other paths. It applies only to a managed wallet payment or connected card draw that names the task, and it refuses that payment or draw while it is paused.
|
|
259
|
+
`updateBudget()` can resume a paused budget or extend an
|
|
260
|
+
expired one, and a start date cannot be changed. To end a budget, call `admin.spending.deleteBudget(id, { version })`. It fails with
|
|
261
|
+
`reasonCode` `BUDGET_HAS_HOLDS` while a purchase holds spend against the budget. Try a budget first on one agent with a Tempo Testnet wallet.
|
|
262
|
+
|
|
263
|
+
- A budget covers purchases in its own currency, so set it to what the wallets pay in: `USDC` on
|
|
264
|
+
Base, `USDC.e` on Tempo or `pathUSD` on Tempo Testnet. `USD`, `USDC` and `USDC.e` budgets cover one
|
|
265
|
+
another at par when no budget at that level, workspace, agent or task, is in the exact currency. A
|
|
266
|
+
managed wallet payment or connected card draw is refused, whatever the budget's state, when a level
|
|
267
|
+
has budgets for that agent and none covers its currency. `preview()` gives `reasonCode`
|
|
268
|
+
`BUDGET_CURRENCY_UNSUPPORTED`. A budget's currency cannot be changed.
|
|
269
|
+
- `preview()` needs a managed wallet linked to the agent, and that wallet's stablecoin as `currency`.
|
|
270
|
+
It holds nothing and approves nothing, so keep the request, approval and execute flow.
|
|
271
|
+
- When a budget requires a task, ask for one with `conto.spending.requestTask()`. Once the budget
|
|
272
|
+
holder approves it, pass its id as `context.taskRequestId` on `payments.request()` from a managed
|
|
273
|
+
wallet, or as `taskRequestId` on `connectedCards.draw()`. A self-custody wallet cannot use a task. When a budget covers the agent, `payments.request()` throws status 409 with `reasonCode` `EXECUTION_PATH_NOT_CONNECTED`. When none does, a request that names a task ends in `DENIED`. `payments.approve()` refuses the task fields.
|
|
274
|
+
- `context.purchaseKey` identifies one purchase. A key cannot be used again, even after its purchase
|
|
275
|
+
is released, so use a new key for a new attempt.
|
|
276
|
+
- `payments.request()` can return `APPROVED` for a purchase a budget refuses. `payments.execute()`
|
|
277
|
+
then throws status 409 and code `SHARED_BUDGET_BLOCKED`. With `autoExecute`, the request stays
|
|
278
|
+
`APPROVED` and nothing is thrown. To see why, call `preview()` with the same `taskRequestId` and
|
|
279
|
+
`purchaseKey`.
|
|
280
|
+
- `purchases()` lists purchases against budgets in the agent's organization, not Commerce
|
|
281
|
+
`conto.purchases`. It is empty when none of those budgets has applied. A buyer linked to an owner
|
|
282
|
+
workspace has no row for a purchase that only an owner budget covered. The owner reads those with
|
|
283
|
+
`admin.spending.purchases()`.
|
|
284
|
+
- `admin.spending` needs an organization API key. `createBudget()`, `updateBudget()`, `deleteBudget()`
|
|
285
|
+
and `decideTask()` need `policies:write`. `accounting()`, `attachEvidence()` and `reviewEvidence()`
|
|
286
|
+
need `transactions:write`. `reconcile()` needs `spending:reconcile`, which Standard keys do not
|
|
287
|
+
have. An admin SDK key cannot change budgets, decide tasks, or reconcile.
|
|
288
|
+
- `attachEvidence()` takes a PDF, PNG or JPEG of at most 2 MiB, with up to 10 files per purchase. Set
|
|
289
|
+
the Blob's `type`, for example `new Blob([bytes], { type: 'application/pdf' })`. A Blob with no type,
|
|
290
|
+
or with a type that does not match the file's first bytes, fails with `reasonCode` `INVALID_FILE`.
|
|
291
|
+
Conto does not take the amount, currency or merchant from the file. The budget holder enters them
|
|
292
|
+
with `reviewEvidence()`.
|
|
293
|
+
- `exportPurchases()` returns CSV bytes and fails with `reasonCode` `EXPORT_TOO_LARGE` above 10,000
|
|
294
|
+
purchases.
|
|
295
|
+
- Most budget errors have `code` `POLICY_VIOLATION`, so read `reasonCode` on `ContoError` and
|
|
296
|
+
`ContoAdminError`. Some also have `nextActions`, such as `SHARED_BUDGET_EXCEEDED` with
|
|
297
|
+
`REQUEST_BUDGET_INCREASE`. `checkout.begin()`, `getLinkCard()` and `replaceLinkCard()` have `code` `CHECKPOINT_BUDGET_NOT_SUPPORTED` and `reasonCode` `EXECUTION_PATH_NOT_CONNECTED`. `payments.execute()` has `code`
|
|
298
|
+
`SHARED_BUDGET_BLOCKED` and no `reasonCode`.
|
|
299
|
+
- A `VALIDATION_ERROR` on a spending call usually lists the fields in `fieldErrors`. It does not when
|
|
300
|
+
the call got a field it does not accept, such as `periodStart` or `currency` on `updateBudget()`. A
|
|
301
|
+
`payments.request()` validation failure never has `fieldErrors`.
|
|
302
|
+
|
|
180
303
|
## External-card Policy Overlay
|
|
181
304
|
|
|
182
305
|
The admin client registers only a masked card alias and assigns cooperative
|
|
@@ -322,9 +445,10 @@ Shop Pay, or PayPal browser action without requiring private provider integratio
|
|
|
322
445
|
privileged browser executor must be available only through this wrapper. An unrestricted click or
|
|
323
446
|
payment tool would bypass the control. Persist its stable dispatch attempt before calling the
|
|
324
447
|
helper. The helper owns authorization, one-use claim, the privileged callback, and finalization.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
448
|
+
When a rule requires the owner's approval, `runGuardedCheckout` stops with status 409 and code
|
|
449
|
+
`APPROVAL_REQUIRED`. Checkpoints wait for the owner instead, so for Stripe Link prefer the
|
|
450
|
+
[checkpoints in the Stripe Link guide](https://conto.finance/docs/guides/stripe-link#add-the-checkpoints)
|
|
451
|
+
or `getLinkCard()`.
|
|
328
452
|
|
|
329
453
|
Isolated browser processes can implement `PrivilegedBrowserCheckoutDriver` and use
|
|
330
454
|
`runGuardedCheckoutWithDriver`. The agent model must receive only that guarded wrapper, never the
|
|
@@ -527,7 +651,8 @@ and other non-idempotent mutations are never retried automatically. If execution
|
|
|
527
651
|
payment until an operator has resolved it.
|
|
528
652
|
|
|
529
653
|
`ContoError` and `ContoAdminError` expose a stable error contract: `code`, `status`, `requestId`,
|
|
530
|
-
`retryAfter`,
|
|
654
|
+
`retryAfter`, `fieldErrors` on most spending validation failures, `reasonCode` and `nextActions` on a
|
|
655
|
+
budget refusal, and locally generated `retryGuidance` where applicable. Arbitrary server details,
|
|
531
656
|
context, hints, and workflow steps are not forwarded through SDK errors:
|
|
532
657
|
|
|
533
658
|
```typescript
|