npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@stripe/link-sdk

v0.14.0

Published

Node.js SDK for building agents that use Link

Readme

@stripe/link-sdk

Node.js SDK for agents that use Link. It provides typed resources for Link APIs and accepts an access token from your application.

The SDK does not perform login, persist credentials, or own refresh tokens. Authentication state and user-facing authorization flows belong to the CLI or application embedding the SDK.

For services verifying credentials presented by agents, use the separate Agent Identity SDK. This package calls Link APIs on behalf of an agent.

Install

npm install @stripe/link-sdk

The package is ESM-only and requires Node.js 20 or newer.

Quick start

Pass an access token when creating the client:

import Link from '@stripe/link-sdk';

const link = new Link({ accessToken: process.env.LINK_ACCESS_TOKEN! });

const paymentMethods = await link.paymentMethods.list();

Retrieve the approval policy for the current app and user:

const approvalPolicy = await link.approvalPolicy.retrieve();

Use a fixed token for a short-lived job or when the caller replaces the entire client as credentials change.

Credentials

Exactly one credential option is required.

Dynamic access tokens

When your application manages expiring credentials, provide getAccessToken. The SDK calls it for each request. After a 401 response, the SDK calls it once with forceRefresh: true and retries the request with the returned token.

const link = new Link({
  getAccessToken: async ({ forceRefresh } = {}) =>
    credentialManager.getLinkAccessToken({ forceRefresh }),
});

The credential manager should coalesce concurrent refreshes if several requests can receive a 401 at the same time. A client configured with a fixed accessToken does not retry a 401 because it cannot obtain a different token.

Agent tools

@stripe/link-sdk/tools exports createLinkTools, linkToolSchemas, and the LinkTools / LinkToolName types. Each tool has a description, a Zod input schema, and an executor that delegates to the existing SDK resources. This entrypoint has no dependency on Eve or another agent framework.

import { Link } from '@stripe/link-sdk';
import { createLinkTools } from '@stripe/link-sdk/tools';

const tools = createLinkTools(new Link({ accessToken }));
const methods = await tools.list_payment_methods.execute({}, undefined);

For shared agents, pass a client resolver that receives your framework's execution context. The resolver runs for each execution, never during tool discovery:

const tools = createLinkTools((context: MyAuthenticatedContext) =>
  new Link({
    getAccessToken: (options) => credentials.getLinkToken(context.user, options),
  }),
);

Tool inputs use API field names and are validated before resolving the client. The catalog includes wallet reads, spend-request operations, financial-data reads, and purchase reports. Creating a spend request defaults to requesting Link approval and returns immediately; the application handles approval URLs and subsequent retrieval. Supply a stable idempotency_key when an executor can be replayed.

For native Eve discovery, namespacing, access-token configuration, and replay handling, use @stripe/link-integrations-eve.

User-approved purchase flow

Amounts are expressed in the currency's minor unit, such as cents for USD.

Omitting currency uses the consumer's default spend-request currency, reported by userinfo.default_spend_request_currency (user-info retrieve in the CLI). Specify currency explicitly when using an amount from a checkout with a known currency. Amounts, line-item unit_amount values, and total amount values use the selected currency's minor units: 100 means ¥100 in JPY or $1 in USD. The client passes amounts through unchanged and performs no FX conversion. This default applies to newly created requests; existing requests retain their stored currency.

context must be at least 100 characters and should tell the user what the agent is buying and why.

const methods = await link.paymentMethods.list();
const paymentMethod = methods.find((method) => method.is_default) ?? methods[0];

if (!paymentMethod) {
  throw new Error('The user needs to add a Link payment method.');
}

const spendRequest = await link.spendRequests.create({
  payment_details: paymentMethod.id,
  credential_type: 'card',
  amount: 2599,
  currency: 'usd',
  merchant_name: 'Acme',
  merchant_url: 'https://acme.example',
  context:
    'The user asked the agent to buy the selected item from Acme for $25.99, including the displayed shipping cost.',
});

const approval = await link.spendRequests.requestApproval(spendRequest.id);
await sendToUser(`Approve this purchase: ${approval.approval_url}`);
await saveRunState({ spendRequestId: spendRequest.id });

Retrieve the request in a later agent run:

const result = await link.spendRequests.retrieve(state.spendRequestId);

if (!result) {
  throw new Error('Spend request not found.');
}

switch (result.status) {
  case 'approved':
    // Use the returned credential without placing it in logs or chat.
    break;
  case 'created':
    return { status: 'approval_not_requested' };
  case 'pending_approval':
    return { status: 'waiting_for_user_approval' };
  case 'requires_action': {
    const action = result.status_details?.requires_action?.next_action;
    return action?.resolution === 'auto_resume'
      ? { status: 'retry_later' }
      : action;
  }
  case 'denied':
  case 'expired':
  case 'submitted':
  case 'succeeded':
  case 'failed':
  case 'canceled':
    return { status: result.status };
}

Only a requires_action result whose resolution is auto_resume should be polled automatically. For any other resolution, surface the action to the user and follow its instructions. Keep returned card or shared-payment-token credentials out of model context, logs, and user-visible messages.

Completion callbacks

Pass optional completion_callback_url and nonce to link.spendRequests.create() or the create_spend_request agent tool.

Supply both fields or neither. Use an opaque, unpredictable nonce, save it unchanged, and verify an exact match when the callback is received. The URL is limited to 2,048 characters and the nonblank nonce to 512 JavaScript/UTF-16 code units; the API validates live-mode HTTPS, URL security, and pair validity. Use returned approval_url and next_action.action_url strings as-is. Do not manually append callback parameters when creation-time context was supplied. Retrieve the request to determine its status after a callback.

Configuration

const link = new Link({
  accessToken,
  fetch,
  defaultHeaders: { 'X-Agent-Version': 'acme-agent/1.0' },
  verbose: true,
  logger: { debug: (message) => diagnostics.debug(message) },
  apiBaseUrl: 'https://api.link.com',
  spendRequestBaseUrl: 'https://api.link.com',
});

Verbose logging includes request methods, URLs, and response status codes. It does not include authorization headers or request and response bodies.

Recurring payments

Pass recurring to spendRequests.create when the user has agreed to recurring spending. For example, this requests a $20 monthly limit:

const request = await link.spendRequests.create({
  credential_type: 'card',
  merchant_name: 'Example Pro',
  merchant_url: 'https://example.com/subscribe',
  amount: 2000,
  currency: 'usd',
  context:
    'Monthly access to Example Pro requested by the user, with a spending limit of $20 per month including all taxes.',
  recurring: { interval: 'month' },
  request_approval: true,
});

Intervals are day, week, month, and year. Optional interval_count must be a positive integer and defaults to 1 on the server; { interval: 'week', interval_count: 2 } resets the spending limit every two weeks. amount is the limit per period. Omit recurring for a one-time purchase. The exported SpendRequestRecurringParams type and create_spend_request agent tool use the same input shape. Existing credential-type and merchant requirements still apply.

Follow the normal approval and retrieval flow. The merchant schedules charges. Recurring card requests stay active after individual charges, so do not wait for succeeded after each payment or create a new request each period. Respect returned credential expiry values; confirm payments from the merchant or transaction records. update cannot change the interval or count. cancel revokes the payment credential but does not cancel the merchant's subscription.

Errors

The SDK throws typed errors:

  • LinkConfigurationError for invalid or missing client configuration
  • LinkTransportError when a request cannot reach Link
  • LinkApiError for non-success API responses
  • LinkResponseError when a successful response has an invalid shape

LinkApiError includes status, code, and structured details fields for programmatic handling.

import { LinkApiError } from '@stripe/link-sdk';

try {
  await link.spendRequests.retrieve('spend_request_id');
} catch (error) {
  if (error instanceof LinkApiError) {
    diagnostics.error({
      status: error.status,
      code: error.code,
      details: error.details,
    });
  }
  throw error;
}

Client resources

  • spendRequests — create, approve, retrieve, update, cancel, and list
  • paymentMethods — list Link payment methods
  • shippingAddresses — list shipping addresses
  • userInfo — retrieve Link user information, including the stable id when returned by the API
  • transactions — list transactions
  • sources — list connected sources
  • balances — list balances
  • webBotAuth — sign URLs for Web Bot Auth
  • reports — report agent outcomes