# Link CLI Link CLI lets agents get secure, one-time-use payment credentials from a Link wallet to complete purchases on your behalf — without storing your real card details. The CLI can produce one of three credential types: - A virtual card (PAN) for use with a standard web checkout form. The issued card works anywhere, and is not restricted to Link-enabled sellers or sellers that use Stripe. - A Link Pay Token (LPT) for use with a Stripe hosted payment form. Stripe checkout pages use WebMCP to allow agents to complete the checkout. - A [Shared Payment Token](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens) (SPT) for use when the seller accepts programmatic payments through [Machine Payment Protocols](https://mpp.dev) (MPP) For now, this is only available to US and Canadian Link accounts. Documentation: - [Installation](#installation) - [Quickstart](#quickstart) - [Where to use Link Agent Wallet](#where-to-use-link-agent-wallet) - [Advanced usage](#advanced) - [Authentication](#authentication) - [The spend request lifecycle](#spend-request-lifecycle) - [Credential type: Shared Payment Token](#shared-payment-token) - [Credential type: Link Pay Token](#link-pay-token) - [Limits](#limits) - [Reporting issues](#report-outcomes) - [Handling step ups](#handle-step-ups) - [Adding line items and totals](#line-items-and-totals) - [Metadata](#metadata) - [Environment variables](#environment-variables) - [Integrating into your agent](#integrating-into-agents) - [SDKs](#sdks) - [Onboarding and Demos](#onboarding-and-demos) - [Development](#development) - [Releasing](#releasing) > [!TIP] > If you're looking to integrate the Link CLI into your product or agent for consumers to pay with, be sure to look at [Integrating into your agent](#integrating-into-agents). ## Installation ```bash npm i -g @stripe/link-cli ``` Or run directly with `npx`: ```bash npx @stripe/link-cli ``` ### Use with agents Install the skills: ```bash npx skills add stripe/link-cli ``` By default when called from an agent (non-TTY), all commands use `toon` output — a compact, LLM-friendly text format. All commands accept `--format [format]` for structured output. Other formats: `json`, `yaml`, `md`, `jsonl`. List available commands: ```bash link-cli --llms-full ``` Get a command's full schema with `--schema`. Example: ```bash link-cli spend-request create --schema ``` #### MCP Server Link CLI can run as a local MCP server. Add the following to your MCP client config (`.mcp.json`, etc.) ```json { "mcpServers": { "link": { "command": "npx", "args": ["@stripe/link-cli", "--mcp"] } } } ``` Alternatively, use `serve` to expose link-cli as an MCP endpoint over HTTP. ```bash link-cli serve # binds 127.0.0.1:54321 (loopback only) link-cli serve --port 8080 link-cli serve --host 0.0.0.0 # expose beyond localhost (see warning below) ``` The server handles `POST /mcp` and `GET` skill discovery at `/.well-known/skills/index.json` and `/.well-known/skills/{skill-name}/SKILL.md`, with `OPTIONS` preflight support. Other paths return `404`, unsupported methods return `405`, and malformed or ambiguous request paths return `400`. It binds to `127.0.0.1` by default so only the local host can reach it. Anyone who can reach the port can use this CLI's authenticated Link session, so only override `--host` on a trusted, isolated network — doing so prints a warning. ## Quickstart Run a guided onboarding and demo flow: ```bash link-cli onboard ``` ### Login The `link-cli` requires a Link account. You can log in to your existing one or [create one online](https://app.link.com). ```bash link-cli auth login ``` You receive a verification URL and a short phrase. Visit the URL, log in to your Link account, and enter the phrase to approve the connection. ### Retrieve user info ```bash link-cli user-info retrieve --format json ``` In addition to identity fields, the response can include the user's address, balance eligibility, spend limits, and verification requirements: ```json { "email": "jane@example.com", "name": "Jane Doe", "address": { "line1": "510 Townsend St", "line2": null, "city": "San Francisco", "state": "CA", "postal_code": "94103", "country": "US" }, "eligible_for_balance": true, "agent_wallet_spend_limits": { "per_transaction": { "limit": 50000 }, "daily": { "limit": 500000, "used": 120000, "remaining": 380000 }, "thirty_day": { "limit": null, "used": 600000, "remaining": null } }, "agent_wallet_verification_requirement": { "status": "identity_verification", "action_url": "https://app.link.com/finish_setup?verify=identity_verification&intended_email=jane%40example.com&fromEmail=jane%40example.com" } } ``` The address and `eligible_for_balance` fields are omitted when their enrichment is unavailable. `address` is null and `eligible_for_balance` is false when the user has no Person record. Finite spend-limit values are cents because this response does not include a currency. A null limit or remaining amount means unlimited. The verification requirement's action_url is null when no action is available. ### Retrieve approval policy Retrieve the rules that grant the current app authority to create spend requests without manual approval: ```bash link-cli approval-policy retrieve --format json ``` Each rule includes an action, a per-purchase limit, and optionally an ordered list of allowed payment method IDs. The API returns an error when no approval policy has been configured. ### List payment methods ```bash link-cli payment-methods list ``` Returns the cards and bank accounts saved to your Link account. Use the `id` field as `payment_method_id` in the next step. If you have no payment methods, [add new ones in Link](https://app.link.com/wallet). The list can also include a Link balance payment method with its available balance when that amount is available. Retrieve one payment method by ID: ```bash link-cli payment-methods retrieve ``` The response contains the same redacted fields as the matching list item, including capability eligibility when available. Set or change a payment-method nickname: ```bash link-cli payment-methods update --nickname "Work card" ``` Clear a nickname by passing an explicit empty string: ```bash link-cli payment-methods update --nickname "" ``` Link trims surrounding whitespace and returns the updated, redacted payment method. ### List shipping addresses ```bash link-cli shipping-address list ``` Returns the shipping addresses saved to your Link account. The response preserves nullable `nickname`, `address`, and address fields exactly as returned by the API. ### Create a spend request Create a spend request with merchant details, line items, and amounts. If `--payment-method-id` is omitted, your default payment method will be used, or the first eligible one if no default is set: ```bash link-cli spend-request create \ --payment-method-id csmrpd_xxx \ --merchant-name "Stripe Press" \ --merchant-url "https://press.stripe.com" \ --context "Purchasing 'Working in Public' from press.stripe.com. The user initiated this purchase through the shopping assistant." \ --amount 3500 \ --line-item "name:Working in Public,unit_amount:3500,quantity:1" \ --total "type:total,display_text:Total,amount:3500" \ --request-approval ``` The `--request-approval` flag triggers a push notification to the user for approval. Interactive mode polls until the request leaves the approval waiting states. Agent mode returns a `spend-request retrieve` command to wait for a status change, including a transition to `submitted`. Easily approve requests with the [Link app](https://link.com/download). ### Execute payment The approved spend request includes a `card` object with `number`, `cvc`, `exp_month`, `exp_year`, `billing_address`, and `valid_until`. Enter these into the merchant's checkout form. ```bash link-cli spend-request retrieve lsrq_001 ``` By default, retrieving a spend request doesn't include card details. Pass `--include card` to see unmasked card details. To avoid leaking card credentials into agent transcripts or logs, use `--output-file` to write the full card to a secure local file while stdout shows only redacted data (brand, last4, expiry): ```bash link-cli spend-request retrieve lsrq_001 --include card --output-file /tmp/link-card.json --format json ``` The file is created with `0600` permissions. If the file already exists, the command fails unless `--force` is passed. When `--output-file` is set, the JSON output replaces the `card` object with redacted fields and adds a `card_output_file` path. For agent polling, pass `--interval` and optionally `--max-attempts`: ```bash link-cli spend-request retrieve lsrq_001 --interval 2 --max-attempts 300 ``` ## Where to use Link Agent Wallet Link is already integrated with the following agents: - [Muse by Meta](https://muse.ai) - [Grok Bot](https://x.ai/bot) - [Instinct](https://instinct.com) - [Browser Use](https://browser-use.com/) ## Financial Insights Link CLI can also read a consumer's financial data -- transactions, balances, and connected account details. Agents can use these features to answer personal finance questions and track trends. Financial Insights are powered by [Financial Connections](https://stripe.com/financial-connections), covering 12,000+ US financial institutions. Financial Insights also provides pre-computed and user-provided insights to power betterr shopping experiences through the `insights` commands. ### Authentication Financial Insights requires additional authorization beyond the default; request access to each type of data you want to access on financial data sources: ```bash link-cli auth login \ --client-name "My Agent" \ --scope "userinfo:read" \ --source-actions read_link_transactions \ --source-actions read_external_transactions \ --source-actions read_balances \ --source-actions read_source_details ``` If already authenticated for payments, use `auth upgrade` to add financial data access without dropping existing scopes. Discovering available insight types only requires an authenticated session. Retrieving an insight can require additional source actions, which the discovery response identifies. #### Discover and list user-supplied and pre-aggregated insights ```bash link-cli insights list-available-types --format json link-cli insights list --insight --format json ``` The first command lists available insight IDs, descriptions, and any access needed to retrieve them. The second returns the selected insight's status and data. Omit `--insight` to list all insights, or repeat it for several IDs to request only a few. Both commands support `--limit` and `--starting-after` to retrieve paginated results. If the provided access token is insufficient to view an insight, a `no_data` result will include `authorization_remediation` for missing permissions. A `pending` result means the insight is still being computed. #### List sources ```bash link-cli sources list ``` Returns connected financial accounts (bank accounts, credit cards, etc.) with metadata, capabilities, and connection status. Use the `id` field as `--source` in other commands. #### List transactions ```bash link-cli transactions list ``` Supports server-side filtering: ```bash link-cli transactions list --start-date 2026-01-01 --end-date 2026-01-31 link-cli transactions list --category groceries link-cli transactions list --origin external_connection link-cli transactions list --source ``` | Flag | Description | | ---- | ---- | | `--start-date` | Only transactions on or after this date (YYYY-MM-DD) | | `--end-date` | Only transactions on or before this date (YYYY-MM-DD) | | `--category` | Filter by transaction category | | `--origin` | `link` (Link-native) or `external_connection` (from linked bank/card) | | `--source` | Filter by source ID (repeatable for multiple accounts) | | `--limit` | Max results per page (1–100) | Amounts are integers in the currency's smallest unit. Negative = money leaving the account, positive = money entering. Transactions may be Link-native (processed directly through Link), or sourced through an external connection (e.g. imported from transactions that would appear on a bank statement). #### Agent integration The financial-insights skill teaches agents which command to run for each question type, how to handle pagination, interpret amounts, and summarize results. See skills/financial-insights/SKILL.md for the full agent guide. #### List balances ```bash link-cli balances list link-cli balances list --source ``` Returns current balances for connected accounts, including `cash.available` (bank/savings) or `credit.used` (credit cards). ## Advanced ### Authentication ```bash link-cli auth login --client-name "Claude Code" # identify the connecting agent link-cli auth login --client-name "Claude Code" --interval 5 --timeout 300 # login + poll in one call link-cli auth upgrade --scope "userinfo:read" # widen access to a superset link-cli auth status # check auth status link-cli auth logout # disconnect ``` When you provide `--client-name`, the Link app displays it when you approve the connection — for example, `Claude Code on my-macbook` instead of `link-cli on my-macbook`. With `--interval`, the login command yields the verification code immediately and then polls inline until authenticated or time out — no separate `auth status` call needed. This is recommended for agents that cannot relay the code while a separate polling command blocks their I/O channel. `auth upgrade` takes the same flags as `auth login` but is meant for widening access when you're already logged in. Unlike `auth login` — which stops with an "already logged in" message when a valid session exists — `auth upgrade` merges the flags you pass with your currently granted `scope` and `authorization_details` and starts a new approval for the **superset**, so you never accidentally drop access. If there's no valid session, it prints a warning and continues with just the access you requested. Your current session stays valid throughout the approval and is only replaced (and the old grant revoked) once you approve the new one — so abandoning the approval leaves your existing session untouched. `auth status` reports the `scope` and `authorization_details` the current session was granted (echoed by the token endpoint at login/refresh and stored in the credential file), and includes an `update` field when a newer version is available: ```json { "authenticated": true, "scope": "userinfo:read payment_methods.agentic", "authorization_details": [{ "type": "source", "actions": ["read"] }], "update": { "current_version": "0.1.2", "latest_version": "0.2.0", "update_command": "npm install -g @stripe/link-cli" } } ``` `scope` and `authorization_details` are only present when the token endpoint returned them. Set `NO_UPDATE_NOTIFIER=1` to suppress update checks (for example, in CI). All commands accept `--auth ` to store auth credentials in a specific file instead of the default location. `auth login` writes to this file; all other commands read from it. Useful for running multiple sessions with separate identities. ### Identity (experimental) Unlisted commands: set `LINK_IDENTITY_COMMANDS=1` to enable them in `--help` and `--llms`. Identity commands remain excluded from MCP even when enabled. Both identity `request` commands save their artifacts to disk and return only the file path and metadata. This applies to every output format, including JSON, piped output, and `--full-output`. Request output never includes credentials, tokens, or claim values. **Privacy-preserving tokens** that show Link attests to your agent: ```bash LINK_IDENTITY_COMMANDS=1 link-cli identity attestations request --count 10 ``` Each request adds tokens to the CLI-managed pool at `~/.link-cli/attestations/pool.json`. Take one token when you need to answer an attestation challenge: ```bash LINK_IDENTITY_COMMANDS=1 link-cli identity attestations take --format json ``` `take` removes one token before returning its `token`, ready-to-use `authorization` header, issuer, and issuer-key ID. Pass `authorization` as the `Authorization` header in your browser automation or HTTP client. An empty pool returns `ATTESTATION_POOL_EMPTY`; refill it with `request --count 10`. For agent-managed tokens, export a batch to a new file outside the CLI storage directory: ```bash LINK_IDENTITY_COMMANDS=1 link-cli identity attestations request --count 10 --output-file ./aats.json ``` Exported tokens never enter the CLI pool. The agent owns their consumption and cleanup. Existing exports remain separate and are never automatically imported. Wallet credentials keep their existing storage and behavior. Pool updates are serialized and saved atomically. A crash after removal can lose a token; `take` never returns it to the pool. If a crash leaves `pool.json.lock`, ensure no attestation commands are running before removing that lock directory. **User info that has been signed, proving it comes from Link**: ```bash LINK_IDENTITY_COMMANDS=1 link-cli identity credentials request ``` `identity credentials request` saves a signed credential to `~/.link-cli/credentials/current.json`, bound to the CLI-managed holder key at `~/.link/holder-key.jwk`. Structured output includes `output_file`, issuer, expiry, holder-key path/thumbprint, and claim names. A script can read the saved credential and holder key to sign a presentation and send it through browser automation or an HTTP client without printing their contents into the agent transcript. **Unlisted presentations** disclose selected claims to a verifier using the saved credential and holder key: ```bash LINK_IDENTITY_COMMANDS=1 link-cli identity credentials present \ --aud https://directory.example \ --nonce '' \ --claim email \ --format json ``` ```json {"presentation":"~~"} ``` Use the verifier challenge's exact audience and nonce. Repeat `--claim` to disclose additional claims, such as `--claim email --claim email_verified`; at least one claim is required. The command reads `~/.link-cli/credentials/current.json`, signs with its saved holder key, and returns only the presentation. It works without login or network access and does not modify the saved credential or key. Missing claims, expired credentials, mismatched keys, and unsupported disclosure formats fail instead of producing a presentation. It supports Link's flat SHA-256 disclosures; credentials with plaintext user claims or nested selective disclosures are rejected. Send the returned `presentation` as the `Identity-Presentation` HTTP header. The verifier still validates the issuer signature, holder signature, audience, nonce, expiry, and required claims. Presentations include a fresh signing time and should be sent promptly; a verifier that has consumed the nonce requires a new challenge. **Unlisted local inspection** uses the same feature flag and MCP exclusion: ```bash LINK_IDENTITY_COMMANDS=1 link-cli identity credentials list --format json LINK_IDENTITY_COMMANDS=1 link-cli identity attestations list --format json ``` These commands inspect local files without login or Link API calls and display metadata in both terminal and structured output. Credential inspection reports the saved `~/.link-cli/credentials/current.json` path, issuer, cached expiry/`expired` status, holder-key path/thumbprint, and claim names. Private keys are never opened; credentials, tokens, and claim values are never printed. Inspection does not modify files, verify signatures, or filter artifacts by the active account. Attestation inspection reports paths, issuer/key identifiers, per-batch `stored_token_count`, aggregate `total_token_count`, and `storage` (`pool` or `export`) for JSON batches in `~/.link-cli/attestations`. Counts describe stored tokens; external usage is untracked and AATs have no embedded expiry. Empty stores return empty lists. Lists include per-file `errors` alongside valid entries. ### Spend request lifecycle A spend request moves through: **create** → **request approval** → **approved** (with credentials). **Required fields for a regular card create:** `merchant_name`, `merchant_url`, `context`, and `amount`. `payment_method_id` is optional — if omitted, your default payment method will be used, or the first eligible one if no default is set. Shared Payment Token requests instead require `network_id`; Link Pay Token requests require `execution_method=link_pay_token` and the DOM-derived `merchant_account_id`, and Link supplies their canonical merchant identity. **Constraints:** `context` must be at least 100 characters; `amount` must not exceed 50000 (cents); `currency` must be a 3-letter ISO code. The user has 30 minutes from when approval is requested to approve. Approved credentials (card or SPT) are valid for 12 hours from spend request creation. **Test mode:** Pass `--test` to create a testmode SpendRequest. A testmode SpendRequest will return test payment credentials (e.g test card `4000009990001984`) rather than a real payment credential. Testmode SpendRequests will not charge the underlying payment method of the SpendRequest. This is useful for development and integration testing without real payment methods. ```bash # Update before approval link-cli spend-request update lsrq_001 \ --merchant-url https://press.stripe.com/working-in-public # Request approval separately (alternative to create --request-approval) link-cli spend-request request-approval lsrq_001 # Retrieve at any time (includes card credentials after approval) link-cli spend-request retrieve lsrq_001 # Cancel a spend request (from created, pending_approval, or approved state) link-cli spend-request cancel lsrq_001 ``` Use `spend-request retrieve --interval 2` to wait for the initial status to change. Polling starts only for `created`, `pending_approval`, or `requires_action` with an `auto_resume` resolution. Other statuses, including `submitted` and unfamiliar API values, return immediately. A change to another waiting status also returns; inspect the result and retrieve again as needed. If `--timeout` or `--max-attempts` is reached without a change, the command exits non-zero with `POLLING_TIMEOUT`. ### Credential types By default, a spend request provisions a virtual card. Link can also provide a shared payment token (SPT) for use with the Machine Payment Protocol (MPP) and a Link Pay Token (LPT) for use on Stripe hosted checkout forms. ### Shared Payment Token For merchants that support the [Machine Payments Protocol](https://mpp.dev) (HTTP 402) and the Stripe payment method, instead pass `--credential-type "shared_payment_token"` when creating the spend request. The SPT is one-time-use — if payment fails, create a new spend request. Use `mpp decode` to validate a raw `WWW-Authenticate` header and extract the `network_id` needed for `shared_payment_token` spend requests: ```bash link-cli mpp decode \ --challenge 'Payment id="ch_001", realm="merchant.example", method="stripe", intent="charge", request="..."' ``` Use `mpp pay` to complete purchases: ```bash link-cli mpp pay https://climate.stripe.dev/api/contribute \ --spend-request-id lsrq_001 \ --method POST \ --data '{"amount":100}' \ --header "X-Custom: value" ``` ### Link Pay Token Some Stripe checkout pages expose an AI-agent steering block that supports a Link Pay Token (LPT). Inspect the checkout in a browser before creating the SpendRequest: enable the agent checkbox, then verify that both `input[name="link_pay_token"]` and `data-stripe-merchant-account="acct_..."` are present in the same Stripe frame. Create an LPT-bound request with the DOM-derived account ID. Do not pass `--merchant-name` or `--merchant-url`; Link resolves the canonical merchant identity from the account ID for the approval screen. ```bash link-cli spend-request create \ --payment-method-id csmrpd_xxx \ --execution-method link_pay_token \ --merchant-account-id acct_... \ --context "Purchasing an item from the checkout the agent inspected. The user initiated this purchase through the shopping assistant." \ --amount 3500 \ --request-approval ``` LPT requests use the default `card` credential type and do not support `--test`, `--network-id`, or `shared_payment_token`. After approval, retrieve `--include link_pay_token` immediately before using it on the same checkout surface. Each returned LPT is valid for up to 30 minutes, or until the SpendRequest expires. If either DOM marker is absent, create a regular virtual card SpendRequest instead; do not create an LPT request. ### Limits | Limit | Value | |-------|-------| | Max amount per spend request | $500 (50,000 cents) | | Approval window | 30 minutes — user must approve within 30 min of `request-approval` | | Card / SPT validity | 12 hours from spend request creation | | Daily spend | $500 | | Monthly spend (30 days) | $20,000 | | Concurrent active requests (created + approved) | 30 | | Concurrent approved requests | 10 | | Hourly creation rate | 50 per hour | | Rolling creation rate | 200 per 60 days | Use `mpp pay` to complete purchases on merchants that use the [Machine Payments Protocol](https://mpp.dev). The spend request must use `credential_type: "shared_payment_token"` and you must approve it before paying. The SPT is one-time-use — if payment fails, create a new spend request. ```bash link-cli mpp pay https://climate.stripe.dev/api/contribute \ --spend-request-id lsrq_001 \ --method POST \ --data '{"amount":100}' \ --header "X-Custom: value" ``` In agent mode (`--format json`), the full flow returns the payment continuation twice: as `_next.pay_argv` (`{ "command": "mpp", "args": [...] }`) and as `_next.pay_command`. Prefer `pay_argv` and invoke it directly, passing each `args` entry as its own process argument. The URL, body and headers can carry merchant-controlled text, so `pay_command` is shell-quoted for callers that must go through a shell — pass it to the shell verbatim, without unquoting or re-splitting it. Use `mpp decode` to validate a raw `WWW-Authenticate` header and extract the `network_id` needed for `shared_payment_token` spend requests: ```bash link-cli mpp decode \ --challenge 'Payment id="ch_001", realm="merchant.example", method="stripe", intent="charge", request="..."' ``` ### Report outcomes Use `report` to record the outcome of a purchase attempt. Reporting is optional, but calling it after attempts — success or failure — helps Stripe improve checkout for agents. ```bash # Successful purchase link-cli report --domain shop.example.com --outcome success --spend-request-id lsrq_abc123 # Blocked by captcha link-cli report --domain shop.example.com --outcome blocked --spend-request-id lsrq_abc123 \ --tag captcha --step "checkout page" --freeform-context "Turnstile challenge appeared" # Abandoned due to timeout link-cli report --domain shop.example.com --outcome abandoned --spend-request-id lsrq_abc123 \ --tag timeout # With a step-by-step account of the path taken link-cli report --domain shop.example.com --outcome success --spend-request-id lsrq_abc123 \ --attempt-trace '1. / — clicked "Shop" → category grid 2. /checkout — email required before shipping unlocks; entered [email] 3. /checkout — clicked "Pay now" → order confirmed' ``` Outcomes: `success`, `blocked`, `abandoned`. Tags: `stripe_checkout`, `captcha`, `anti_bot_script`, `cdn_block`, `waf_block`, `dns_block`, `rate_limited`, `login_required`, `3ds_challenge`, `page_inaccessible`, `timeout`, `site_error`, `payment_declined`, `other`. `--step` records where the agent was when the outcome occurred. `--attempt-trace` is the whole path: one numbered line per step, each giving the URL path, the label acted on, the action, and the observed result, so another agent can follow it. Send it on failures too — the dead ends are the useful part. Omit the buyer's personal data and write `[email]`, `[address]` in its place. Over 8000 characters is truncated by the server rather than rejected, so send the full narrative instead of skipping the report. ### Handle step-ups If the created spend request comes back with `status: "requires_action"`, no approval is needed yet — the payment method or account needs attention first. Check `status_details.requires_action.next_action` for `type`, `display_message`, `action_url`, and `resolution`. For 3D Secure (`resolution: "auto_resume"`), keep polling `spend-request retrieve` — the request resolves on its own once the challenge is completed. For any other resolution, complete the indicated action and create a new spend request. ### Line items and totals Optionally pass additional data on the specific items being purchased, and any tax, shipping or other amounts. `--line-item` and `--total` use repeatable `key:value` format. **`--line-item` keys:** `name` (required), `quantity`, `unit_amount`, `description`, `sku`, `url`, `image_url`, `product_url` ```bash --line-item "name:Running Shoes,unit_amount:12000,quantity:1,description:Trail runners" ``` **`--total` keys:** `type` (required; one of: `subtotal`, `tax`, `total`, `items_base_amount`, `items_discount`, `discount`, `fulfillment`, `shipping`, `fee`, `gift_wrap`, `tip`, `store_credit`), `display_text` (required), `amount` (required) ```bash --total "type:subtotal,display_text:Subtotal,amount:12000" \ --total "type:total,display_text:Total,amount:12000" ``` ### Metadata Attach arbitrary string data to a spend request with the repeatable `--metadata` flag (`key:value` format). Max 50 keys, key ≤ 40 chars, value ≤ 500 chars. ```bash link-cli spend-request create ... \ --metadata "order_id:ord_123" \ --metadata "team:growth" ``` In MCP/agent mode, pass `metadata` as a structured `{ key: value }` object. ### Environment variables | Variable | Effect | |----------|--------| | `LINK_AUTH_FILE` | Same as `--auth` — override the auth credential file path (flag takes precedence) | | `LINK_ACCESS_TOKEN` | Use this access token directly, bypassing auth storage | | `LINK_REFRESH_TOKEN` | Refresh token to use when `LINK_ACCESS_TOKEN` is expired | | `LINK_NO_REFRESH` | When set, never auto-refresh the access token — error instead | | `LINK_API_BASE_URL` | Override the API base URL | | `LINK_AUTH_BASE_URL` | Override the auth base URL | | `LINK_HTTP_PROXY` | Route all requests through an HTTP proxy (requires `undici`) | ## Integrating into agents If you are building an agent and want to offer Link as a native experience to your consumers (as a connector, plugin, pre-installed capability etc.), please look at our [documentation and steps for integrating](https://docs.stripe.com/agentic-commerce/link-agent-wallet). We can support higher limits, more embedded approval flows, and additional capabilities. ## SDKs Applications can use the credential-only Link client directly in [TypeScript](packages/sdk/README.md), [Go](packages/sdk-go/README.md), or [Python](packages/sdk-python/README.md). The Python SDK provides synchronous and asynchronous clients covering the Go SDK's API resources with Python conventions. Authentication flows and credential persistence remain the embedding application's responsibility. The TypeScript SDK also exports reusable [agent tools](packages/sdk/README.md#agent-tools). Use the [Eve extension](packages/integrations/eve/README.md) to mount them in an Eve agent with a static access token or an application-provided Eve auth provider, plus a wallet skill. ## Onboarding and Demos Run the guided setup flow — authenticates, checks payment methods, shows the app download QR, and runs both demo flows: ```bash link-cli onboard ``` Run an interactive demo of both Link payment flows (always uses test mode — no real charges): ```bash link-cli demo # shows menu to choose flow link-cli demo --only-card # virtual card flow only link-cli demo --only-spt # machine payment (SPT) flow only ``` ## Development Workspace development requires Node.js 24+. ```bash pnpm install pnpm run build pnpm run link-cli --help ``` Watch mode: ```bash pnpm run dev ``` Run tests: ```bash pnpm run test ``` This runs the TypeScript, Go, and Python suites. Go SDK development requires Go 1.23 or newer. Python SDK development uses [uv](https://docs.astral.sh/uv/) and requires Python 3.11 or newer; uv can install the interpreter for you. ```bash uv python install 3.11 uv sync --directory packages/sdk-python --locked pnpm run test:python pnpm run check:python ``` Type-check and lint: ```bash pnpm run typecheck pnpm biome check . ``` ## Releasing This project uses [Changesets](https://github.com/changesets/changesets) to version and publish `@stripe/link-cli`, `@stripe/link-sdk`, and `@stripe/link-integrations-eve`. `@stripe/link-typescript-config` is private and is not published. ### Add a changeset Add a changeset for any user-facing change before merging: ```bash pnpm changeset ``` Select each affected public package and its semver bump. Commit the generated file in `.changeset/` with the change. ### Publish After changesets reach `main`, the release workflow creates or updates the **Version Packages** pull request. Review and merge that PR to publish the new package versions to npm. The workflow uses npm trusted publishing and generates provenance attestations for the SDK; no npm token or local publish command is needed. CLI releases also upload the bundled JavaScript, standalone executables, and checksums to the corresponding GitHub Release. SDK-only releases skip that CLI artifact work. To inspect the packages without publishing them: ```bash pnpm turbo run build pnpm --filter @stripe/link-cli --filter @stripe/link-sdk --filter @stripe/link-integrations-better-auth --filter @stripe/link-integrations-eve publish --dry-run --no-git-checks ``` CI runs the same publish dry-run for every pull request. The Go SDK is a nested module and is released with a repository tag such as `packages/sdk-go/v0.1.0`. Go module tags are independent of npm package versions.