From 814090eb371526d531e3b1f000ac14be08c1692f Mon Sep 17 00:00:00 2001 From: Selina Feng Date: Tue, 11 Aug 2026 00:40:32 -0400 Subject: [PATCH 1/4] expose financial insights CLI commands and skill file --- packages/cli/src/__tests__/cli.test.ts | 15 +- packages/cli/src/cli.tsx | 187 +++++++------ packages/cli/src/commands/balances/index.tsx | 2 +- packages/cli/src/commands/sources/index.tsx | 2 +- .../cli/src/commands/transactions/index.tsx | 2 +- skills/financial-insights/SKILL.md | 256 ++++++++++++++++++ 6 files changed, 359 insertions(+), 105 deletions(-) create mode 100644 skills/financial-insights/SKILL.md diff --git a/packages/cli/src/__tests__/cli.test.ts b/packages/cli/src/__tests__/cli.test.ts index 0f8fbd6..598b292 100644 --- a/packages/cli/src/__tests__/cli.test.ts +++ b/packages/cli/src/__tests__/cli.test.ts @@ -1190,11 +1190,12 @@ describe('production mode', () => { expect(txnRequest).toBeUndefined(); }); - it('does not show transactions in root help', async () => { + it('shows transactions in root help as beta', async () => { const result = await runProdCli('--help'); expect(result.exitCode).toBe(0); - expect(result.stdout + result.stderr).not.toContain('transactions'); + expect(result.stdout + result.stderr).toContain('[beta]'); + expect(result.stdout + result.stderr).toContain('transactions'); }); }); @@ -1270,11 +1271,12 @@ describe('production mode', () => { expect(sourcesRequest).toBeUndefined(); }); - it('does not show sources in root help', async () => { + it('shows sources in root help as beta', async () => { const result = await runProdCli('--help'); expect(result.exitCode).toBe(0); - expect(result.stdout + result.stderr).not.toContain('sources'); + expect(result.stdout + result.stderr).toContain('[beta]'); + expect(result.stdout + result.stderr).toContain('sources'); }); }); @@ -1349,11 +1351,12 @@ describe('production mode', () => { expect(balancesRequest).toBeUndefined(); }); - it('does not show balances in root help', async () => { + it('shows balances in root help as beta', async () => { const result = await runProdCli('--help'); expect(result.exitCode).toBe(0); - expect(result.stdout + result.stderr).not.toContain('balances'); + expect(result.stdout + result.stderr).toContain('[beta]'); + expect(result.stdout + result.stderr).toContain('balances'); }); }); diff --git a/packages/cli/src/cli.tsx b/packages/cli/src/cli.tsx index 874b8a8..2cbf9aa 100644 --- a/packages/cli/src/cli.tsx +++ b/packages/cli/src/cli.tsx @@ -63,38 +63,14 @@ const factory = new ResourceFactory({ const authRepo = factory.createAuthResource(); const spendRequestRepo = factory.createSpendRequestResource(); -const requestedCommand = process.argv[2]; -const hiddenCli = - requestedCommand === 'transactions' - ? createTransactionsCli( - () => factory.createTransactionsResource(), - authStorage, - envAccessToken, - ) - : requestedCommand === 'sources' - ? createSourcesCli( - () => factory.createSourcesResource(), - authStorage, - envAccessToken, - ) - : requestedCommand === 'balances' - ? createBalancesCli( - () => factory.createBalancesResource(), - authStorage, - envAccessToken, - ) - : null; -if (hiddenCli) { - process.argv.splice(2, 1); -} - -const cli = - hiddenCli ?? - Cli.create('link-cli', { - description: - 'Create a secure, one-time payment credential from a Link wallet to let agents complete purchases on behalf of users.', - version: cliVersion, - }); +const cli = Cli.create('link-cli', { + description: + 'Create a secure, one-time payment credential from a Link wallet to let agents complete purchases on behalf of users.', + version: cliVersion, + sync: { + include: ['skills/*'], + }, +}); const isAgent = process.argv.includes('--format') || process.argv.includes('--mcp'); @@ -112,70 +88,89 @@ if (!isAgent && process.stdout.isTTY) { } } -if (!hiddenCli) { - cli.command( - createAuthCli(authRepo, getUpdateInfo, authStorage, envAccessToken), - ); - cli.command( - createSpendRequestCli(spendRequestRepo, authStorage, envAccessToken), - ); - cli.command( - createPaymentMethodsCli( - () => factory.createPaymentMethodsResource(), - authStorage, - envAccessToken, - ), - ); - cli.command( - createShippingAddressCli( - () => factory.createShippingAddressResource(), - authStorage, - envAccessToken, - ), - ); - cli.command( - createUserInfoCli( - () => factory.createUserInfoResource(), - authStorage, - envAccessToken, - ), - ); - cli.command( - createMppCli( - spendRequestRepo, - () => factory.createPaymentMethodsResource(), - authStorage, - envAccessToken, - ), - ); - // cli.command( - // createWebBotAuthCli(() => factory.createWebBotAuthResource(), authStorage), - // ); - cli.command( - createReportCli( - () => factory.createReportResource(), - authStorage, - envAccessToken, - ), - ); - cli.command( - createDemoCli( - authRepo, - spendRequestRepo, - () => factory.createPaymentMethodsResource(), - authStorage, - ), - ); - cli.command( - createOnboardCli( - authRepo, - spendRequestRepo, - () => factory.createPaymentMethodsResource(), - authStorage, - ), - ); - cli.command(createServeCli(cli)); -} +cli.command( + createAuthCli(authRepo, getUpdateInfo, authStorage, envAccessToken), +); +cli.command( + createSpendRequestCli(spendRequestRepo, authStorage, envAccessToken), +); +cli.command( + createPaymentMethodsCli( + () => factory.createPaymentMethodsResource(), + authStorage, + envAccessToken, + ), +); +cli.command( + createShippingAddressCli( + () => factory.createShippingAddressResource(), + authStorage, + envAccessToken, + ), +); +cli.command( + createUserInfoCli( + () => factory.createUserInfoResource(), + authStorage, + envAccessToken, + ), +); +cli.command( + createMppCli( + spendRequestRepo, + () => factory.createPaymentMethodsResource(), + authStorage, + envAccessToken, + ), +); +// cli.command( +// createWebBotAuthCli(() => factory.createWebBotAuthResource(), authStorage), +// ); +cli.command( + createReportCli( + () => factory.createReportResource(), + authStorage, + envAccessToken, + ), +); +cli.command( + createBalancesCli( + () => factory.createBalancesResource(), + authStorage, + envAccessToken, + ), +); +cli.command( + createSourcesCli( + () => factory.createSourcesResource(), + authStorage, + envAccessToken, + ), +); +cli.command( + createTransactionsCli( + () => factory.createTransactionsResource(), + authStorage, + envAccessToken, + ), +); +cli.command( + createDemoCli( + authRepo, + spendRequestRepo, + () => factory.createPaymentMethodsResource(), + authStorage, + ), +); +cli.command( + createOnboardCli( + authRepo, + spendRequestRepo, + () => factory.createPaymentMethodsResource(), + authStorage, + ), +); +cli.command(createServeCli(cli)); cli.serve(); diff --git a/packages/cli/src/commands/balances/index.tsx b/packages/cli/src/commands/balances/index.tsx index 75a5ac0..ec3ae5f 100644 --- a/packages/cli/src/commands/balances/index.tsx +++ b/packages/cli/src/commands/balances/index.tsx @@ -16,7 +16,7 @@ export function createBalancesCli( envAccessToken?: string, ) { const cli = Cli.create('balances', { - description: 'List balances from your Link wallet', + description: '[beta] List balances from your Link wallet', }); cli.command('list', { diff --git a/packages/cli/src/commands/sources/index.tsx b/packages/cli/src/commands/sources/index.tsx index 76d3fde..0eeb29a 100644 --- a/packages/cli/src/commands/sources/index.tsx +++ b/packages/cli/src/commands/sources/index.tsx @@ -16,7 +16,7 @@ export function createSourcesCli( envAccessToken?: string, ) { const cli = Cli.create('sources', { - description: 'List sources from your Link wallet', + description: '[beta] List sources from your Link wallet', }); cli.command('list', { diff --git a/packages/cli/src/commands/transactions/index.tsx b/packages/cli/src/commands/transactions/index.tsx index 809a7ee..7eddd67 100644 --- a/packages/cli/src/commands/transactions/index.tsx +++ b/packages/cli/src/commands/transactions/index.tsx @@ -16,7 +16,7 @@ export function createTransactionsCli( envAccessToken?: string, ) { const cli = Cli.create('transactions', { - description: 'List transactions from Link and external accounts', + description: '[beta] List transactions from Link and external accounts', }); cli.command('list', { diff --git a/skills/financial-insights/SKILL.md b/skills/financial-insights/SKILL.md new file mode 100644 index 0000000..e7bf892 --- /dev/null +++ b/skills/financial-insights/SKILL.md @@ -0,0 +1,256 @@ +--- +version: 0.6.0 +name: financial-insights +description: | + Reads a user's Link financial data — transactions, balances, and wallet sources — so agents can answer questions about spending and available source capabilities. +allowed-tools: + - Bash(link-cli:*) + - Bash(npx:*) + - Bash(npm:*) +license: Complete terms in LICENSE +metadata: + author: stripe + url: link.com/agents + openclaw: + emoji: "📊" + homepage: https://link.com/agents + requires: + bins: + - link-cli + install: + - kind: node + package: "@stripe/link-cli" + bins: [link-cli] +user-invocable: true +--- + +# Financial insights + +Use this skill to answer questions about a user’s Link-connected financial data, including: + +- Recent transactions +- Spending patterns +- Account balances +- Linked wallet sources +- Basic summaries derived from the user’s financial data + +All commands are read-only. They do not move money, initiate payments, modify accounts, or expose payment credentials. + +## Safety and privacy + +Do not retrieve financial data until the user is authenticated with the required source actions. + +Only retrieve the data needed to answer the user’s request. Do not run every list command by default. + +Do not expose sensitive identifiers, access tokens, credentials, or payment instrument details. Summarize financial information at the level needed to answer the user’s question. + +If the user asks for an action that would move money, reference `skills/create-payment-credential/SKILL.md` instead. + +## Authentication + +Before retrieving financial data, check whether the user is authenticated. + +```bash +link-cli auth status +``` + +If the user is not authenticated, ask them to authenticate with the source actions needed for the requested data. + +Use the minimum required source actions: + +- Transactions: `transactions.read` +- Balances: `balances.read` +- Sources: `sources.read` + +If the user asks a question that requires multiple data types, request all relevant actions together. + +Example: + +```bash +link-cli auth login --source-actions transactions.read,balances.read,sources.read +``` + +Do not proceed with financial data retrieval until authentication succeeds. + +## Choosing the right command + +Use the smallest command set that answers the user’s question. + +| User asks about | Command | +|---|---| +| Recent purchases, merchants, spend, transaction history, income, deposits, subscriptions | `link-cli transactions list` | +| Current available balance, account balance, cash position | `link-cli balances list` | +| Connected accounts, cards, banks, wallet sources, source metadata | `link-cli sources list` | + +Examples: + +- “How much did I spend on restaurants last month?” → Use transactions only. +- “What is my current checking account balance?” → Use balances only. +- “Which accounts are connected?” → Use sources only. +- “Summarize my cash position and recent spending.” → Use balances and transactions. + +## Output format + +Use JSON for agent-readable structured output. + +```bash +link-cli transactions list --format json +link-cli balances list --format json +link-cli sources list --format json +``` + +The default `toon` format is intended for humans. Prefer `--format json` whenever parsing, filtering, aggregating, or summarizing results. + +All monetary amounts across all endpoints are integers in the smallest currency unit (e.g. `152340` = $1,523.40 USD). Positive amounts indicate money owed to the account holder. Negative amounts indicate money owed by the account holder. + +## Sources (concept) + +A **source** is a financial account connected to the user's Link wallet — a bank account, credit card, savings account, etc. Every source has a unique `source_id` (e.g. `csmrpd_abc123`) that appears across all endpoints: + +- In `transactions list`, each transaction includes a `source_id` indicating which account it belongs to. +- In `balances list`, each balance entry includes a `source_id` identifying the account. +- In `sources list`, the full source metadata (name, institution, type, status) is returned. + +Use `source_id` to correlate data across commands — for example, to find all transactions for a specific account or to match a balance to its source type. + +## Transactions + +Use transactions to answer questions about spending, income, merchants, categories, recurring payments, deposits, or account activity. + +```bash +link-cli transactions list --format json +``` + +Common options: + +```bash +link-cli transactions list --format json --limit 100 +link-cli transactions list --format json --starting-after +``` + +When using paginated results, continue only as far as needed to answer the user’s question. Stop once enough relevant data has been retrieved. + +### Response fields + +| Field | Note | +|---|---| +| `amount` | Negative = money leaving the account (debit/purchase), positive = money entering (credit/deposit). | +| `origin` | `external_connection` (from linked bank/card) or `link` (Link-native transaction). | +| `category` | May be `null` if unclassified. | +| `status` | `pending` or `posted`. Pending transactions may still change or disappear. | + +For transaction summaries: + +- Normalize signs consistently before calculating totals. +- Distinguish debits from credits when possible. +- Group by merchant, category, account, currency, or time period only when relevant. +- Mention if the answer is based on a limited retrieved window. + +## Balances + +Use balances to answer questions about current account balances or available funds. + +```bash +link-cli balances list --format json +``` + +### Response fields + +| Field | Note | +|---|---| +| `type` | `cash` (bank/savings) or `credit` (credit card/line of credit). Determines which sub-object is present. | +| `current` | Balance *before* pending transactions. Not the same as available funds. | +| `cash.available` | Object mapping currency codes to available funds (current minus outbound pending plus inbound pending). Only present when `type` is `cash`. | +| `credit.used` | Object mapping currency codes to credit used. Only present when `type` is `credit`. | +| `as_of` | When the balance was last updated — may be stale by hours or days. | + +When summarizing balances: + +- Preserve currencies. +- Do not add balances across different currencies unless the user explicitly asks and exchange-rate data is available. +- Use the `current` field as the default definition of a balance, unless the user's question requires considering pending transactions. +- If multiple sources are returned, summarize by account/source. + +## Sources + +Use sources to answer questions about connected wallet sources, linked accounts, or available financial data sources. + +```bash +link-cli sources list --format json +``` + +### Response fields + +| Field | Description | +|---|---| +| `id` | Unique source identifier (same as `source_id` in other endpoints). | +| `name` | Display name of the source. | +| `type` | Source type (e.g. `card`, `bank_account`). | +| `capabilities` | Object indicating what data is available. Each key (e.g. `balances`, `transactions`) maps to an object with a `status` field (e.g. `eligible`). | +| `external_connection.status` | Connection status to the external institution. | +| `granted_actions` | List of actions the user has granted for this source. | + +When summarizing sources: + +- Include only non-sensitive metadata needed for the answer. +- Avoid exposing full account numbers, credentials, tokens, or payment instrument details. +- Prefer labels such as institution, account type, source status, and last updated time when available. + +## Pagination + +List commands may return paginated responses. If a response includes a cursor or `has_more` indicator, use the next cursor only when more data is needed. + +For transaction pagination, use the returned transaction ID or cursor with `--starting-after` when applicable: + +```bash +link-cli transactions list --format json --starting-after +``` + +Do not exhaustively paginate unless the user’s request requires a complete time range and the command supports retrieving it safely. + +## Answering user questions + +When answering: + +- State the direct answer first. +- Mention the relevant time range and data source. +- Note any limitations, such as partial pagination, missing categories, pending transactions, or unsupported currencies. +- Avoid dumping raw records and object IDs unless the user asks for them. +- Prefer concise summaries, totals, and notable patterns. + +Example response style: + +```text +You spent $342.18 on restaurants across 12 transactions in July. The largest restaurant transaction was $86.40 at Example Bistro on July 18. This is based on the transactions returned for your connected Link sources. +``` + +## Error handling + +If authentication fails, ask the user to re-authenticate. + +If a command returns no data, say that no matching Link financial data was available for the requested scope. + +If the CLI returns an error indicating missing permissions or source actions, request authentication again with the specific missing action. + +If data is incomplete or paginated, clearly state that the answer is based on the data retrieved so far. + +## Guardrails + +Do not: + +- Move money. +- Initiate payments. +- Modify financial sources. +- Retrieve unrelated financial data. +- Request broader source actions than needed. +- Expose credentials, tokens, or full payment details. +- Present uncertain derived insights as definitive. + +Do: + +- Use read-only commands. +- Authenticate before retrieval. +- Request the minimum required source actions. +- Use `--format json` for parsing. +- Retrieve only the data needed. +- Summarize clearly and note limitations. From a0bd3e7be24a7f724b3cc058ecac0d9807686df1 Mon Sep 17 00:00:00 2001 From: Selina Feng Date: Tue, 11 Aug 2026 16:21:28 -0400 Subject: [PATCH 2/4] fix skill file --- skills/financial-insights/SKILL.md | 43 +++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/skills/financial-insights/SKILL.md b/skills/financial-insights/SKILL.md index e7bf892..6bfa5b3 100644 --- a/skills/financial-insights/SKILL.md +++ b/skills/financial-insights/SKILL.md @@ -58,16 +58,22 @@ If the user is not authenticated, ask them to authenticate with the source actio Use the minimum required source actions: -- Transactions: `transactions.read` -- Balances: `balances.read` -- Sources: `sources.read` +- Transactions processed through Link: `read_link_transactions` +- Transactions imported from bank connections: `read_external_transactions` +- Account balances: `read_balances` +- Data source details and descriptions: `read_sources` If the user asks a question that requires multiple data types, request all relevant actions together. Example: ```bash -link-cli auth login --source-actions transactions.read,balances.read,sources.read +link-cli auth login \ + --scope "userinfo:read payment_methods.agentic " \ + --source-actions read_link_transactions \ + --source-actions read_balances \ + --source-actions read_external_transactions \ + --source-actions read_source_details ``` Do not proceed with financial data retrieval until authentication succeeds. @@ -126,8 +132,23 @@ Common options: ```bash link-cli transactions list --format json --limit 100 link-cli transactions list --format json --starting-after +link-cli transactions list --format json --start-date 2025-01-01 --end-date 2025-01-31 +link-cli transactions list --format json --category groceries +link-cli transactions list --format json --origin external_connection +link-cli transactions list --format json --source --source ``` +| Flag | Description | +|---|---| +| `--limit` | Max results (1-100). | +| `--starting-after` | Pagination cursor (transaction ID). | +| `--ending-before` | Pagination cursor (transaction ID, reverse). | +| `--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 category. | +| `--origin` | Filter by origin: `link` or `external_connection`. | +| `--source` | Filter by source ID (repeatable). | + When using paginated results, continue only as far as needed to answer the user’s question. Stop once enough relevant data has been retrieved. ### Response fields @@ -152,8 +173,16 @@ Use balances to answer questions about current account balances or available fun ```bash link-cli balances list --format json +link-cli balances list --format json --source ``` +| Flag | Description | +|---|---| +| `--limit` | Max results (1-100). | +| `--starting-after` | Pagination cursor (balance ID). | +| `--ending-before` | Pagination cursor (balance ID, reverse). | +| `--source` | Filter by source ID (repeatable). | + ### Response fields | Field | Note | @@ -179,6 +208,12 @@ Use sources to answer questions about connected wallet sources, linked accounts, link-cli sources list --format json ``` +| Flag | Description | +|---|---| +| `--limit` | Max results (1-100). | +| `--starting-after` | Pagination cursor (source ID). | +| `--ending-before` | Pagination cursor (source ID, reverse). | + ### Response fields | Field | Description | From 6ed6da57433b6f58076313900749cb7fadfac2fa Mon Sep 17 00:00:00 2001 From: Selina Feng Date: Tue, 11 Aug 2026 20:22:07 -0400 Subject: [PATCH 3/4] address review comments --- scripts/sync-skill-version.js | 4 ++++ skills/financial-insights/SKILL.md | 13 +++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/sync-skill-version.js b/scripts/sync-skill-version.js index 035c71d..42b17a0 100644 --- a/scripts/sync-skill-version.js +++ b/scripts/sync-skill-version.js @@ -36,6 +36,10 @@ syncSkillVersion( 'SKILL.md', resolve(root, 'skills/create-payment-credential/SKILL.md'), ); +syncSkillVersion( + 'financial-insights/SKILL.md', + resolve(root, 'skills/financial-insights/SKILL.md'), +); syncPluginJsonVersion( '.cursor-plugin/plugin.json', resolve(root, 'plugins/link/.cursor-plugin/plugin.json'), diff --git a/skills/financial-insights/SKILL.md b/skills/financial-insights/SKILL.md index 6bfa5b3..b2fd1e8 100644 --- a/skills/financial-insights/SKILL.md +++ b/skills/financial-insights/SKILL.md @@ -1,12 +1,13 @@ --- -version: 0.6.0 +version: 0.11.0 name: financial-insights description: | - Reads a user's Link financial data — transactions, balances, and wallet sources — so agents can answer questions about spending and available source capabilities. + Reads a user's Link financial data — transactions, balances, and wallet sources — so agents can answer questions about spending and available source capabilities. Use when the user says "check my balance", "how much did I spend", "show my transactions", "what accounts are connected", "summarize my spending", "recent purchases", or asks about their financial activity, account balances, or linked sources. allowed-tools: - Bash(link-cli:*) - - Bash(npx:*) - - Bash(npm:*) + - Bash(npx --yes @stripe/link-cli:*) + - Bash(npx @stripe/link-cli:*) + - Bash(npm install -g @stripe/link-cli:*) license: Complete terms in LICENSE metadata: author: stripe @@ -61,7 +62,7 @@ Use the minimum required source actions: - Transactions processed through Link: `read_link_transactions` - Transactions imported from bank connections: `read_external_transactions` - Account balances: `read_balances` -- Data source details and descriptions: `read_sources` +- Data source details and descriptions: `read_source_details` If the user asks a question that requires multiple data types, request all relevant actions together. @@ -69,7 +70,7 @@ Example: ```bash link-cli auth login \ - --scope "userinfo:read payment_methods.agentic " \ + --scope "userinfo:read payment_methods.agentic" \ --source-actions read_link_transactions \ --source-actions read_balances \ --source-actions read_external_transactions \ From 42494db53c7caf79a14929aafc866463f6c43d96 Mon Sep 17 00:00:00 2001 From: Selina Feng Date: Tue, 11 Aug 2026 21:52:19 -0400 Subject: [PATCH 4/4] skill file tweaks --- skills/financial-insights/SKILL.md | 90 +++++++++++++++++++----------- 1 file changed, 57 insertions(+), 33 deletions(-) diff --git a/skills/financial-insights/SKILL.md b/skills/financial-insights/SKILL.md index b2fd1e8..614d949 100644 --- a/skills/financial-insights/SKILL.md +++ b/skills/financial-insights/SKILL.md @@ -49,13 +49,15 @@ If the user asks for an action that would move money, reference `skills/create-p ## Authentication -Before retrieving financial data, check whether the user is authenticated. +Before retrieving financial data, check whether the user is authenticated and whether the current session has the required source actions. ```bash -link-cli auth status +link-cli auth status --format json ``` -If the user is not authenticated, ask them to authenticate with the source actions needed for the requested data. +When present, inspect `authorization_details` in the response for entries with `type: "source"` and the required actions. The field may be absent when the token endpoint did not return authorization details or when authentication comes from `LINK_ACCESS_TOKEN`; in that case, run only the minimum data command needed and handle a permission error as described below. + +If the user is not authenticated, start a login that requests only the source actions needed for the requested data. If the user is already authenticated but one or more required source actions are missing, use `auth upgrade` instead of `auth login`. `auth upgrade` preserves the current session while the user approves the additional access and replaces it only after approval succeeds. Use the minimum required source actions: @@ -66,18 +68,34 @@ Use the minimum required source actions: If the user asks a question that requires multiple data types, request all relevant actions together. -Example: +Example for a new login that needs all financial data types: ```bash link-cli auth login \ - --scope "userinfo:read payment_methods.agentic" \ + --client-name "" \ --source-actions read_link_transactions \ --source-actions read_balances \ --source-actions read_external_transactions \ - --source-actions read_source_details + --source-actions read_source_details \ + --format json +``` + +Example for adding balance access to an existing session: + +```bash +link-cli auth upgrade \ + --client-name "" \ + --source-actions read_balances \ + --format json ``` -Do not proceed with financial data retrieval until authentication succeeds. +Replace `` with a clear name for the agent or application. Present the returned `verification_url` to the user, then follow the response's `_next` instruction or poll with: + +```bash +link-cli auth status --interval 5 --max-attempts 60 --format json +``` + +Do not proceed until authentication or the access upgrade succeeds. If the approval expires, is denied, or times out, report that outcome instead of repeatedly starting new authorization flows. ## Choosing the right command @@ -108,17 +126,19 @@ link-cli sources list --format json The default `toon` format is intended for humans. Prefer `--format json` whenever parsing, filtering, aggregating, or summarizing results. -All monetary amounts across all endpoints are integers in the smallest currency unit (e.g. `152340` = $1,523.40 USD). Positive amounts indicate money owed to the account holder. Negative amounts indicate money owed by the account holder. +All monetary amounts across all endpoints are integers in the currency's smallest unit (e.g. `152340` = $1,523.40 USD). Format amounts with a currency-aware formatter that uses the currency's ISO 4217 minor-unit exponent; do not assume every currency has two decimal places or always divide by 100. + +Keep sign interpretation field-specific. Only `transactions.amount` uses negative for money leaving the account and positive for money entering it. Do not apply transaction sign semantics to balance fields; interpret `current`, `cash.available`, and `credit.used` according to the balance type. ## Sources (concept) -A **source** is a financial account connected to the user's Link wallet — a bank account, credit card, savings account, etc. Every source has a unique `source_id` (e.g. `csmrpd_abc123`) that appears across all endpoints: +A **source** is a financial account connected to the user's Link wallet — a bank account, credit card, savings account, etc. Each source has a unique `id` (e.g. `csmrpd_abc123`) that other endpoints may expose as `source_id`: -- In `transactions list`, each transaction includes a `source_id` indicating which account it belongs to. +- In `transactions list`, `source_id` indicates which account a transaction belongs to. - In `balances list`, each balance entry includes a `source_id` identifying the account. - In `sources list`, the full source metadata (name, institution, type, status) is returned. -Use `source_id` to correlate data across commands — for example, to find all transactions for a specific account or to match a balance to its source type. +Use a `source_id` to correlate data across commands — for example, to find transactions for a specific account or to match a balance to its source type. Do not assign transactions with a null `source_id` to a source by guessing from their description. ## Transactions @@ -131,8 +151,6 @@ link-cli transactions list --format json Common options: ```bash -link-cli transactions list --format json --limit 100 -link-cli transactions list --format json --starting-after link-cli transactions list --format json --start-date 2025-01-01 --end-date 2025-01-31 link-cli transactions list --format json --category groceries link-cli transactions list --format json --origin external_connection @@ -141,16 +159,13 @@ link-cli transactions list --format json --source --source | Flag | Description | |---|---| -| `--limit` | Max results (1-100). | -| `--starting-after` | Pagination cursor (balance ID). | -| `--ending-before` | Pagination cursor (balance ID, reverse). | | `--source` | Filter by source ID (repeatable). | +See [Pagination](#pagination) for shared list controls. + ### Response fields | Field | Note | @@ -203,18 +217,12 @@ When summarizing balances: ## Sources -Use sources to answer questions about connected wallet sources, linked accounts, or available financial data sources. +Use sources to answer questions about connected wallet sources, linked accounts, or available financial data sources. See [Pagination](#pagination) for shared list controls. ```bash link-cli sources list --format json ``` -| Flag | Description | -|---|---| -| `--limit` | Max results (1-100). | -| `--starting-after` | Pagination cursor (source ID). | -| `--ending-before` | Pagination cursor (source ID, reverse). | - ### Response fields | Field | Description | @@ -234,15 +242,31 @@ When summarizing sources: ## Pagination -List commands may return paginated responses. If a response includes a cursor or `has_more` indicator, use the next cursor only when more data is needed. +All three list commands support the same pagination flags: -For transaction pagination, use the returned transaction ID or cursor with `--starting-after` when applicable: +| Flag | Description | +|---|---| +| `--limit` | Maximum results per page (1-100). Prefer `100` when multiple pages may be needed. | +| `--starting-after` | Fetch the next page after a cursor value. | +| `--ending-before` | Fetch the previous page before a cursor value. Use for reverse navigation, not normal forward collection. | + +JSON responses contain a `data` array and may contain `has_more`. They do not provide a separate next-cursor field. When `has_more` is `true`, derive the next cursor from the final item in `data`: + +| Command | Next cursor | +|---|---| +| `transactions list` | Final transaction's `id`. | +| `balances list` | Final balance's `source_id`. | +| `sources list` | Final source's `id`. | + +For example: ```bash -link-cli transactions list --format json --starting-after +link-cli transactions list --format json --limit 100 --starting-after ``` -Do not exhaustively paginate unless the user’s request requires a complete time range and the command supports retrieving it safely. +Keep all filters identical across pages and change only `--starting-after`. Stop when `has_more` is false or absent, or when enough data has been retrieved for a non-exhaustive lookup. If `has_more` is true but `data` is empty or the required cursor is null or missing, stop and report that pagination could not continue. + +Do not exhaustively paginate unless the user’s request requires a complete bounded result, such as a total for a specified time range. ## Answering user questions @@ -266,7 +290,7 @@ If authentication fails, ask the user to re-authenticate. If a command returns no data, say that no matching Link financial data was available for the requested scope. -If the CLI returns an error indicating missing permissions or source actions, request authentication again with the specific missing action. +If the CLI returns an error indicating missing permissions or source actions, request only the specific missing action. Use `auth upgrade` when a session is already authenticated and `auth login` when it is not, then wait for approval before retrying the data command once. If data is incomplete or paginated, clearly state that the answer is based on the data retrieved so far.