Skip to content
Logo

Add financial insights to your agent

Use financial insights to let your agent answer questions such as “What did I spend on dining this month?” The agent reads transactions, balances, and account details from the financial accounts a customer chooses to share through Link.

Financial insights are available for US customers. The data comes from the Link API at api.link.com, not the Stripe API.

Before you begin

You need a customer with a US Link account who can authorize access to the financial accounts they choose to share.

Choose an integration

Choose how your application connects to Link before setting up authorization:

  • Local agent: Install Link CLI, then follow the CLI setup. You don’t need to complete the hosted payments guide.
  • Hosted application: Complete the OAuth prerequisites, then follow the hosted setup. Choose the financial data actions in this guide before redirecting the customer to Link.

Link CLI and the TypeScript SDK support transactions, sources, balances, and precomputed insights. The Go and Python SDKs support transactions, sources, and balances. The data retrieval examples on this page use Link CLI.

Choose the data to request

Source actions specify which financial data the customer can share. Request only the actions your feature needs. Customers choose which accounts to share and can opt in to future accounts.

Source actionReadsRegistration
read_link_transactionsTransactions from the customer’s Link wallet.Not required.
read_external_transactionsTransactions from connected external accounts.Required.
read_balancesAccount balances.Required.
read_source_detailsAccount names, types, and last four digits.Required.

The registration column applies to the Stripe account whose publishable key starts a hosted authorization flow. See Financial Connections registration.

For a local agent, request source actions when logging in. This example requests all four actions. Remove any your feature doesn’t need:

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

Follow the returned verification URL to authorize access. To add actions to an existing session, use auth upgrade with the additional --source-actions values. After authorization, continue to List connected accounts.

Authorize a hosted application

For a hosted application, configure registration and the authorization request before sending the customer through OAuth. If you’re using Link CLI’s local flow, continue to List connected accounts.

Register for Financial Connections

If you request external transactions, balances, or account details, the Stripe account whose publishable key starts authorization must be registered for Financial Connections. Registration isn’t required if you only request read_link_transactions.

  1. Open Financial Connections settings in the Dashboard.
  2. Complete the application form and accept the terms.

Use the same account whose publishable key you pass to the authorization URL.

Request financial data scopes

Add authorization_details to the OAuth authorization URL. This parameter contains a URL-encoded JSON array of the source actions you need:

[
  {
    "type": "source",
    "actions": [
      "read_link_transactions",
      "read_external_transactions",
      "read_balances",
      "read_source_details"
    ]
  }
]

URL-encode the array before adding it to the URL. To request payments and insights together, keep payment_methods.agentic in scope. For insights only, use userinfo:read:

https://login.link.com/auth?key=pk_live_YOUR_PUBLISHABLE_KEY&client_id=YOUR_CLIENT_ID&redirect_uri=https://yourapp.com/callback&response_type=code&scope=userinfo:read&state=RANDOM_STATE_VALUE&code_challenge=YOUR_PKCE_CODE_CHALLENGE&code_challenge_method=S256&authorization_details=ENCODED_AUTHORIZATION_DETAILS

Replace ENCODED_AUTHORIZATION_DETAILS with the encoded array. Then exchange the authorization code for tokens. Read the granted authorization_details from the response: a customer can approve only some accounts or actions.

Use the resulting access token with your SDK client. Your application handles token refresh and revocation.

List connected accounts

List the sources the customer shared, along with what each one can do:

link-cli sources list --format json
{
  "data": [
    {
      "id": "csmrpd_abc123",
      "name": "BANK SAVINGS",
      "type": "bank_account",
      "capabilities": {
        "balances": { "status": "eligible" },
        "transactions": { "status": "eligible" }
      },
      "external_connection": { "status": "active" },
      "bank_account": { "last4": "5115" },
      "granted_actions": [
        "read_balances",
        "read_external_transactions",
        "read_source_details",
        "read_link_transactions"
      ]
    }
  ],
  "has_more": false
}

A capability status is eligible or pending. Sources use card and bank_account. Don’t confuse these with the card_details and bank_account_details fields on payment methods.

Retrieve transactions

List transactions for the accounts the customer shared. This example requests up to 50 transactions for a date range:

link-cli transactions list \
  --limit 50 \
  --start-date 2026-06-01 \
  --end-date 2026-06-30 \
  --format json
{
  "data": [
    {
      "id": "lbctxn_abc123",
      "source_id": "csmrpd_abc123",
      "amount": 4999,
      "currency": "usd",
      "created_date": "2026-06-15",
      "description": "ACME Coffee Shop",
      "status": "succeeded",
      "category": null,
      "origin": "external_connection"
    }
  ],
  "has_more": true
}
OptionDescription
--limitNumber of results, from 1 to 100.
--start-date, --end-dateInclusive dates in YYYY-MM-DD format.
--originlink or external_connection.
--categoryFilter by category.
--source <id>Limit results to a source. Repeatable.
--starting-after, --ending-beforePagination cursors.

Amounts use the smallest unit of the currency. Negative amounts are outflows and positive amounts are inflows. status is an open set, so handle values you haven’t seen before, and category can be null.

To page through results, pass the id of the last transaction as --starting-after while has_more is true:

link-cli transactions list \
  --limit 100 \
  --start-date 2026-06-01 \
  --starting-after lbctxn_abc123 \
  --format json

Retrieve balances

List balances for the shared accounts. Each result identifies its source account and the time the balance applies to:

link-cli balances list --format json
{
  "data": [
    {
      "source_id": "csmrpd_abc123",
      "type": "cash",
      "current": 31005,
      "currency": "usd",
      "as_of": "2026-07-15T00:00:00Z",
      "cash": {
        "available": { "usd": 31005 }
      }
    }
  ],
  "has_more": false
}

Bank accounts return a cash balance: current is the posted balance and cash.available excludes pending transactions. Cards return a credit balance: current is the posted balance and credit.used includes pending transactions. Pass --source to limit the results to one account.

Handle pending data

Right after a customer connects an account, the external data might still be loading. The API responds with HTTP 202 and this body:

{
  "code": "external_data_retrieval_pending",
  "description": "We are still retrieving external financial data. Please try again in a few seconds."
}

Retry after a few seconds. Data is usually ready within 30 seconds of connecting.

Use insights

Insights are precomputed answers about a customer’s finances. List the types available, then retrieve the ones you need. New types can appear without a Link CLI release, so list them instead of hard-coding IDs.

link-cli insights list-available-types --format json
link-cli insights list --insight INSIGHT_ID --format json

Each available type has an id, a description, and the authorization_remediation to request if the customer hasn’t granted access yet:

{
  "data": [
    {
      "id": "top_brand_by_transaction_count_per_category_t180d",
      "description": "Top brands",
      "authorization_remediation": {
        "authorization_details": [
          { "type": "source", "actions": ["read_link_transactions"] }
        ]
      }
    },
    {
      "id": "top_5_brands_by_transaction_count_per_category_t180d",
      "description": "Top 5 brands for each shopping category in the last 180 days based on transaction count",
      "authorization_remediation": {
        "authorization_details": [
          {
            "type": "source",
            "actions": ["read_link_transactions", "read_external_transactions"]
          }
        ]
      }
    }
  ],
  "has_more": false
}

An insight comes back in one of three states:

  • ready: includes as_of (a Unix timestamp) and data, a list of entries that each have a label and a typed value. Values like number_of_items carry a label and a count. Handle value types you haven’t seen before.
  • pending: has only id, description, and status. The insight is still being computed, so retry after a few seconds.
  • no_data: has an error_code of missing_permissions and an error_message, and can include authorization_remediation. Request the additional source actions with auth upgrade if the customer hasn’t granted them.
{
  "id": "top_brand_by_transaction_count_per_category_t180d",
  "description": "Top brands",
  "status": "ready",
  "as_of": 1790723779,
  "data": [
    {
      "label": "Clothing",
      "value": {
        "type": "number_of_items",
        "number_of_items": { "label": "Marine Layer", "count": 2 }
      }
    }
  ]
}

The top_5_brands_by_transaction_count_per_category_t180d insight returns up to five brands per shopping category, ranked by transaction count. Each entry’s label includes its rank and category:

{
  "id": "top_5_brands_by_transaction_count_per_category_t180d",
  "description": "Top 5 brands for each shopping category in the last 180 days based on transaction count",
  "status": "ready",
  "as_of": 1790723779,
  "data": [
    {
      "label": "Brand #1 for Clothing and accessories",
      "value": {
        "type": "number_of_items",
        "number_of_items": { "label": "Marine Layer", "count": 4 }
      }
    },
    {
      "label": "Brand #2 for Clothing and accessories",
      "value": {
        "type": "number_of_items",
        "number_of_items": { "label": "Acme", "count": 3 }
      }
    }
  ]
}

Paginate every list

All list commands take --limit (1–100) and --starting-after. Transactions, sources, and balances also take --ending-before. Insights don’t. Responses are { "data": [...], "has_more": true } with no separate cursor, so use the last item’s identifier as the next cursor:

ResourceCursor
TransactionsThe last transaction’s id
SourcesThe last source’s id
BalancesThe last balance’s source_id
InsightsThe last insight’s id

Keep your filters unchanged while you page through a result set.

Configure your agent’s skill file

Link CLI ships an agent skill for financial insights that covers command selection, pagination, and how to answer spending questions. Install the bundled skills:

npx skills add stripe/link-cli

Find the financial insights skill in the Link CLI repository.

Test your integration

After completing the authorization path for your integration, verify that your application can read the data the customer granted. The following checks use Link CLI and live data:

  1. Authorize with the source actions your feature needs.
  2. Connect at least one account.
  3. Run link-cli sources list. Capabilities can show pending briefly, then eligible.
  4. Run link-cli transactions list --limit 5.
  5. Run link-cli balances list.
  6. Ask your agent a spending question end to end.

Customer controls

Customers control access per account and can revoke it in the Link app. After a customer revokes access, calls for that source return an authorization error. Prompt the customer to reconnect instead of retrying.

Next steps

Use these guides to extend your integration: