Skip to main content
Stripe Link is Stripe’s payment wallet. With Link CLI, Stripe’s command-line tool, an agent can ask Stripe Link for a virtual card for one purchase. The person approves each card in their Link app, and Stripe Link issues it. Conto integrates with Link CLI so the agent asks Conto first. Conto checks the purchase against the owner’s rules. Only after Conto approves does Link CLI ask Stripe Link for a card, for exactly the approved amount at that store. If Conto does not approve, Stripe Link is never asked, so no card exists.

How it works

  1. At the payment step, once the final total is known, the agent’s code calls conto.checkout.getLinkCard().
  2. Conto checks the purchase against the agent’s rules and holds the amount against its limits. When a rule requires it, the owner approves in Conto first.
  3. After Conto approves, Stripe’s Link CLI on your machine asks Stripe Link for a card for that amount at that store. The person approves it in the Link app.
  4. Your code gets the card and fills in the store’s card form. Keep the card out of any model prompt, tool result, or log.
  5. Right before paying, the agent calls confirm(). After paying, it reports the outcome.
Stripe Link sends the card to your machine. Conto does not receive the card number or security code. Conto stores only the Link request ID, so the owner can see which Link request paid.

Set up

Install Stripe’s Link CLI on the machine where your agent runs, and log in with the Link account that pays:
The person who approves needs the Link app. Nobody connects Link to Conto, and there is no Link setup in the Conto dashboard. You also need an agent and its standard SDK key, as for checkout checkpoints.

Get a card with the SDK

getLinkCard() takes the same purchase details as checkout.begin(), plus the wallet. The checkout method is always LINK. It waits for the owner when a rule requires approval, then for the person in Link. Two optional settings limit each wait, and both default to 10 minutes: ownerApprovalTimeoutMs and linkApprovalTimeoutMs. Pass signal to stop early. Retrying getLinkCard() with the same input resumes the same checkpoint and the same Link request, so the person is not asked twice.

The card

The card stays in your agent’s process. Printing or serializing the result shows only the last four digits, the brand, and the expiry. Use the card only in the store’s card form for this purchase. linkCliWallet() runs Link CLI without a shell and reads the card from a private temporary file that it deletes before the call returns. Its options are binary (defaults to link-cli on PATH), test, paymentMethodId (defaults to the person’s default payment method), timeoutSeconds, and env.

When the total changes

Call getLinkCard() at the payment step, when the total includes shipping and tax. The card covers the amount Conto approved, so confirm() refuses a different total for it with LINK_CARD_TOTAL_CHANGED. If the total changes anyway, get a new card for the final total:
replaceLinkCard() cancels the old Link request and checkpoint, checks the final total against the agent’s rules, and gets a new card. Confirm replacement.checkpoint with the final total.

When something goes wrong

If any call throws, do not pay. The four Link errors extend LinkCardError, which also covers other Link failures. Each has holdReleased, which is false when Conto could not cancel the checkpoint. Cancel it with conto.checkout.cancel(error.checkpoint.id) in that case. Error messages never contain card data. A LinkCardError with code LINK_CARD_NOT_CANCELLED means Conto could not cancel the Link request, so Link could still issue its card. Conto keeps the spend held and returns the linkRequestId. Retry with the same input, or cancel the request with wallet.cancel(error.linkRequestId) before conto.checkout.cancel(error.checkpoint.id). The same code without a linkRequestId means the wallet failed while asking Link for the card, so Conto cannot tell whether Link created the request. Retry with the same input to resume it.

Test mode

linkCliWallet({ test: true }) creates test-mode Link requests. Link returns test card data and charges nothing. The person still approves each request in the Link app. Conto checks and records test purchases like any other purchase.

MCP

The Conto MCP server does not issue Link cards. A tool result goes into the model’s context and often into the MCP host’s logs, so a card number and CVC must never be in one. Get the card with conto.checkout.getLinkCard() in code the model does not see, and pass the model only the linkRequestId and the card’s last four digits. The MCP checkpoint tools still take a linkRequestId. checkout_checkpoint_confirm and checkout_checkpoint_report_outcome send it to Conto as the payment reference. With CONTO_LINK_WALLET set to link-cli, checkout_checkpoint_cancel with a linkRequestId also cancels that Link request, and keeps the spend held until Link cancels it or reports it closed. See MCP tools.

What this protects

This integration makes Conto’s approval part of how the agent pays, as long as Conto is the agent’s only way to get a Link card. It stops:
  • An agent going off script. Link is asked for a card only for a purchase Conto approved.
  • Overspending. The card is limited to the approved amount, and the amount counts toward the agent’s limits.
  • The wrong store. Conto checks the store’s domain against the owner’s rules before any card exists, and the person sees the store in Link.
  • Too many purchases. Count and velocity rules apply to each card request.
It does not stop a builder who also gives the agent raw Link access. An agent that can run Link CLI itself, use a shell, or call Link with your credentials can get a card without asking Conto. Give the agent the Conto SDK or the MCP tool, not Link CLI or a shell.

What the owner sees

Each purchase appears in Transactions like any checkout. Its page shows the Link request ID next to the order number, and each step that reported it. A purchase that needs approval appears in Alerts & Approvals first.