@finverse/sdk-typescript

中文文档
0.0.427发布于 2026/11/13MITTypeScriptESM + CJS近 30 天下载 6689

OpenAPI client for @finverse/sdk-typescript

原始使用文档
文档目录18 节
  1. Installation
  2. API Overview
  3. Payment API
  4. Key Classes & Methods
  5. Payment Flow (End-to-End)
  6. Data API
  7. Key Classes & Methods
  8. Data Retrieval Flow (End-to-End)
  9. Best Practices
  10. Use async/await
  11. Handle API responses correctly
  12. Use exported types and interfaces
  13. Handle errors with try/catch
  14. Handle validation errors
  15. Reuse Configuration instances
  16. Client secret: never commit, server-side only
  17. Payment idempotency
  18. Resources for AI Agents

Finverse API - TypeScript SDK

This SDK enables end-to-end backend integration with the Finverse API, including API authentication, institution linking, data retrieval, and payment operations.

Installation

npm install @finverse/sdk-typescript

API Overview

The SDK is organized into two main API categories:

APIPurpose
Payment APICreate payment links, mandates, payments, and manage payment accounts
Data APIRetrieve accounts, transactions, statements, balance history, and identity data

Both APIs share authentication and linking flows via PublicApi and LinkApi.


Payment API

The Payment API enables you to create payment links for checkout, initiate payments, manage mandates, and handle payment-related operations.

Key Classes & Methods

ClassKey Methods
PaymentApicreatePaymentLink, getPaymentLink, cancelPaymentLink, createScheduledPayout, getPayoutById, createPaymentMethod, createPayment, getPayment, createMandate, getMandate, authorizeMandate, createPaymentUser, createPaymentAccount, listPaymentAccounts

Payment Flow (End-to-End)

The payment link flow: Create → Redirect → Callback → Poll → Result.

  1. Create – Create payment link via API, get url and payment_link_id. Save both and unique_reference_id.
  2. Redirect – Redirect user to the payment link URL (use HTTP 303 so the redirect is followed with GET).
  3. Callback – Finverse redirects back with payment_link_id and unique_reference_id query params. Verify they match what you stored.
  4. Poll – Poll GET /payment_links/{paymentLinkId} every 2 seconds for up to 30 seconds until session_status is "COMPLETE".
  5. Result – If COMPLETE → success; otherwise → error.

Security: FINVERSE_CLIENT_ID and FINVERSE_CLIENT_SECRET must never be committed to git or sent to the frontend. Use them only on the server (e.g. environment variables, secrets manager).

1. Authenticate: Obtain Customer Access Token

import { Configuration, PublicApi } from '@finverse/sdk-typescript';

const apiHost = process.env.FINVERSE_BASE_URL ?? "https://api.prod.finverse.net";
const clientId = process.env.FINVERSE_CLIENT_ID;
const clientSecret = process.env.FINVERSE_CLIENT_SECRET;

const configuration = new Configuration({ basePath: apiHost });
const customerTokenResp = await new PublicApi(configuration).generateCustomerAccessToken({
  client_id: clientId,
  client_secret: clientSecret,
  grant_type: 'client_credentials',
});

const customerAccessToken = customerTokenResp.data.access_token;
// Cache the token; refresh before expiry (use expires_in minus 60s buffer)

Payment mode – For one-time payments. Requires amount (minor units, e.g. 10000 = 100.00 HKD), currency, sender, payment_details, and link_customizations with redirect_uri:

import { Configuration, PaymentApi } from '@finverse/sdk-typescript';
import crypto from 'crypto';

const configuration = new Configuration({
  basePath: apiHost,
  accessToken: customerAccessToken,
});
const paymentApi = new PaymentApi(configuration);

const uniqueReferenceId = crypto.randomUUID();
const callbackUrl = process.env.CALLBACK_URL; // e.g. https://yoursite.com/callback

const createResp = await paymentApi.createPaymentLink({
  mode: "PAYMENT",
  amount: 10000,  // 100.00 HKD
  currency: "HKD",
  unique_reference_id: uniqueReferenceId,
  sender: {
    external_user_id: "your-internal-user-id",
    name: "Customer Name",
    email: "[email protected]",
  },
  payment_details: {
    description: "Order #12345",
    external_transaction_reference: "order-12345",  // max 35 chars
  },
  link_customizations: {
    ui_mode: "redirect",
    redirect_uri: callbackUrl,
  },
});

const paymentLinkId = createResp.data.payment_link_id;
const paymentUrl = createResp.data.url;

// Store paymentLinkId and uniqueReferenceId for callback verification

Setup mode – For saving payment methods (e.g. Click to Pay). Do not pass amount:

const createResp = await paymentApi.createPaymentLink({
  mode: "SETUP",
  currency: "HKD",
  unique_reference_id: uniqueReferenceId,
  sender: {
    external_user_id: "your-internal-user-id",
    name: "Customer Name",
    email: "[email protected]",
  },
  payment_details: {
    description: "Save payment method",
    external_transaction_reference: "setup-12345",
  },
  link_customizations: {
    ui_mode: "redirect",
    redirect_uri: callbackUrl,
  },
  payment_setup_options: {
    future_payments: "CLICK_TO_PAY",
  },
});

3. Redirect User to Payment URL

Redirect the user to paymentUrl. Use HTTP 303 so the browser follows with GET (Finverse expects GET):

4. Callback Handler: Poll for Completion

When Finverse redirects back, read payment_link_id and unique_reference_id from query params. Verify they match your stored values, then poll until session_status is COMPLETE:

import { Configuration, PaymentApi } from '@finverse/sdk-typescript';

const paymentLinkId = req.query.payment_link_id as string;  // from callback URL
const uniqueReferenceId = req.query.unique_reference_id as string;

// Verify uniqueReferenceId matches what you stored
// if (uniqueReferenceId !== storedUniqueReferenceId) { return error; }

const configuration = new Configuration({
  basePath: apiHost,
  accessToken: customerAccessToken,
});
const paymentApi = new PaymentApi(configuration);

const POLL_INTERVAL_MS = 2000;
const POLL_TIMEOUT_MS = 30000;
const startTime = Date.now();

while (Date.now() - startTime < POLL_TIMEOUT_MS) {
  const getResp = await paymentApi.getPaymentLink(paymentLinkId);
  const sessionStatus = getResp.data.session_status;

  if (sessionStatus === "COMPLETE") {
    // Success – redirect to success page
    // Log getResp.data.payment for payment details
    break;
  }

  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
}

// If loop ended without COMPLETE → timeout, show error page

Data API

The Data API enables you to retrieve financial data: accounts, transactions, statements, balance history, identity, and income estimates.

Key Classes & Methods

ClassKey Methods
LoginIdentityApigetLoginIdentity, listAccounts, getAccount, getAccountNumber, listTransactionsByLoginIdentityId, listTransactionsByAccountId, getStatements, getStatement, getBalanceHistory, getIdentity, getIncomeEstimateByLoginIdentityId, listCardDetails, refreshLoginIdentity

Data Retrieval Flow (End-to-End)

1. Authenticate: Obtain Customer Access Token

import { Configuration, PublicApi } from '@finverse/sdk-typescript';

const apiHost = process.env.FINVERSE_BASE_URL ?? "https://api.prod.finverse.net";
const clientId = process.env.FINVERSE_CLIENT_ID;
const clientSecret = process.env.FINVERSE_CLIENT_SECRET;
const redirectUri = process.env.REDIRECT_URI;

const configuration = new Configuration({ basePath: apiHost });
const customerTokenResp = await new PublicApi(configuration).generateCustomerAccessToken({
  client_id: clientId,
  client_secret: clientSecret,
  grant_type: 'client_credentials',
});

const customerAccessToken = customerTokenResp.data.access_token;
import { Configuration, LinkApi } from '@finverse/sdk-typescript';

const userId = "someUserId";
const state = "someUniqueState";
const linkConfig = new Configuration({
  basePath: apiHost,
  accessToken: customerAccessToken,
});
const linkTokenResp = await new LinkApi(linkConfig).generateLinkToken({
  client_id: clientId,
  user_id: userId,
  redirect_uri: redirectUri,
  state: state,
  response_mode: "form_post",
  response_type: "code",
  grant_type: "client_credentials",
});

console.log("linkUrl:", linkTokenResp.data.link_url);

3. Finalize Linking: Exchange Code for Login Identity Access Token

import { LinkApi, TokenGrantTypeEnum } from '@finverse/sdk-typescript';

const code = "obtainAfterLink"; // from Finverse Link UI callback
const loginIdentityTokenResp = await new LinkApi(linkConfig).token(
  TokenGrantTypeEnum.AuthorizationCode,
  code,
  clientId,
  redirectUri,
);
const loginIdentityToken = loginIdentityTokenResp.data.access_token;

4. Retrieve data: Get Login Identity

import { Configuration, LoginIdentityApi } from '@finverse/sdk-typescript';

const dataConfig = new Configuration({
  basePath: apiHost,
  accessToken: loginIdentityToken,
});
const loginIdentityResp = await new LoginIdentityApi(dataConfig).getLoginIdentity();
console.log("login identity:", loginIdentityResp.data.login_identity);

5. Poll Login Identity Status Until Ready

import type { AxiosResponse } from 'axios';
import type { GetLoginIdentityByIdResponse } from '@finverse/sdk-typescript';

enum FinalStatus {
  ERROR = 'ERROR',
  DATA_RETRIEVAL_PARTIALLY_SUCCESSFUL = 'DATA_RETRIEVAL_PARTIALLY_SUCCESSFUL',
  DATA_RETRIEVAL_COMPLETE = 'DATA_RETRIEVAL_COMPLETE',
}

let loginIdentity: AxiosResponse<GetLoginIdentityByIdResponse>;
for (let i = 0; i < 20; i++) {
  loginIdentity = await new LoginIdentityApi(dataConfig).getLoginIdentity();
  const status = loginIdentity.data.login_identity.status;
  if (
    status === FinalStatus.ERROR ||
    status === FinalStatus.DATA_RETRIEVAL_COMPLETE ||
    status === FinalStatus.DATA_RETRIEVAL_PARTIALLY_SUCCESSFUL
  ) {
    break;
  }
  await new Promise((resolve) => setTimeout(resolve, 3000));
}

6. Get Accounts

const accountsResp = await new LoginIdentityApi(dataConfig).listAccounts();
console.log("accounts:", accountsResp.data.accounts);

7. Get Transactions (with pagination)

let offset = 0;
while (true) {
  const transactionsResp = await new LoginIdentityApi(dataConfig).listTransactionsByLoginIdentityId(
    offset,
    500  // limit: default 500, max 1000
  );
  const transactions = transactionsResp.data.transactions ?? [];
  console.log(`total: ${transactionsResp.data.total_transactions}, transactions: ${transactions.length}`);
  offset += transactions.length;
  if (offset >= transactionsResp.data.total_transactions) {
    break;
  }
}

8. Get Statements

import { writeFileSync } from 'fs';

const statementsResp = await new LoginIdentityApi(dataConfig).getStatements();
const statements = statementsResp.data.statements ?? [];
console.log("statements:", statements);

// Download a statement (assuming at least one exists)
const statementId = statements[0].id;
const statementResp = await new LoginIdentityApi(dataConfig).getStatement(
  statementId,
  true,
  { responseType: "arraybuffer" }
);
writeFileSync("statement.pdf", Buffer.from(statementResp.data));

Best Practices

Use async/await

All SDK methods return Promises. Use async/await for cleaner, readable code and to avoid callback hell:

async function fetchAccounts() {
  const config = new Configuration({ basePath: apiHost, accessToken: token });
  const response = await new LoginIdentityApi(config).listAccounts();
  return response.data.accounts;
}

Handle API responses correctly

API methods return Axios AxiosResponse objects. Access the payload via .data:

const tokenResp = await new PublicApi(config).generateCustomerAccessToken({ ... });
const accessToken = tokenResp.data.access_token;  // Correct: use .data

const accountsResp = await new LoginIdentityApi(config).listAccounts();
const accounts = accountsResp.data.accounts;  // Correct: use .data

Use exported types and interfaces

Leverage the SDK's exported types for type safety and better IDE support:

import type {
  Account,
  CreatePaymentRequest,
  GetLoginIdentityByIdResponse,
} from '@finverse/sdk-typescript';

const paymentRequest: CreatePaymentRequest = {
  // ...
};

Handle errors with try/catch

Wrap API calls in try/catch blocks. API errors are returned as HTTP error responses; the SDK may throw on network failures or validation errors:

import axios from 'axios';

try {
  const response = await new LoginIdentityApi(config).listAccounts();
  return response.data.accounts;
} catch (error) {
  if (axios.isAxiosError(error) && error.response) {
    console.error("API error:", error.response.status, error.response.data);
  } else {
    throw error;
  }
}

Handle validation errors

When required parameters are missing, the SDK throws errors. Wrap API calls in try/catch to handle validation and other failures gracefully.

Reuse Configuration instances

Create a Configuration once per token/context and reuse it for multiple API calls:

import { Configuration, LinkApi, PaymentApi } from '@finverse/sdk-typescript';

const config = new Configuration({
  basePath: apiHost,
  accessToken: customerAccessToken,
});
const linkApi = new LinkApi(config);
const paymentApi = new PaymentApi(config);
const linkTokenResp = await linkApi.generateLinkToken({ ... });
const paymentResp = await paymentApi.createPayment(paymentRequest);

Client secret: never commit, server-side only

Never commit your client secret to version control. The client secret must remain confidential and be used only on the server.

  • Server-side only: This SDK is designed for backend use. Never expose client_secret to the browser, mobile apps, or any client-side code.
  • Use environment variables or a secrets manager: Load credentials at runtime from secure storage.
  • Add to .gitignore: Ensure .env and any files containing secrets are never committed.
// ✅ Correct: Load from environment (server-side only)
const clientId = process.env.FINVERSE_CLIENT_ID;
const clientSecret = process.env.FINVERSE_CLIENT_SECRET;  // Never log, never send to client
const redirectUri = process.env.REDIRECT_URI;

Payment idempotency

For payment and mandate operations, use idempotency keys to safely retry requests without creating duplicate payments. If a request fails due to network issues, you can retry with the same key—the API will return the original result instead of creating a duplicate.

Methods that support idempotency keys: createPayment, createMandate, createMandateForExistingSender, and createScheduledPayout on PaymentApi.

import { PaymentApi } from '@finverse/sdk-typescript';
import crypto from 'crypto';

// Generate a unique key per logical operation (e.g., per checkout or mandate setup)
const idempotencyKey = crypto.randomUUID();

// Safe to retry—same key returns same result
await new PaymentApi(config).createPayment(paymentRequest, idempotencyKey);
await new PaymentApi(config).createMandate(mandateRequest, idempotencyKey);

Best practices:

  • Use one idempotency key per unique payment or mandate.
  • Store the key with your order/mandate record so you can retry with the same key if needed.

Resources for AI Agents

For AI agents implementing Finverse integrations, the Finverse AI repository contains skills, implementation guides, and reference documentation for payment flows, data retrieval, and other Finverse API patterns. Follow this link for detailed integration instructions: https://github.com/finversetech/ai

版本与发布记录

@finverse/sdk-typescript 共发布 419 个版本,首次发布于 2022/03/01;过去 12 个月发布了 69 个版本。

版本发布日期距今
0.0.427latest2026/11/131 天前
0.0.4262026/11/104 天前
0.0.4252026/11/068 天前
0.0.4242026/10/2916 天前
0.0.4232026/10/2619 天前
0.0.4222026/10/2619 天前

关于 @finverse/sdk-typescript 的常见问题

@finverse/sdk-typescript 是什么?

OpenAPI client for @finverse/sdk-typescript

如何安装 @finverse/sdk-typescript?

在项目目录运行 npm install @finverse/sdk-typescript,或使用 pnpm add / yarn add / bun add。

@finverse/sdk-typescript 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@finverse/sdk-typescript 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@finverse/sdk-typescript 可以商用吗?

@finverse/sdk-typescript 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@finverse/sdk-typescript 的下载量有多少?

根据 npm 官方下载统计,@finverse/sdk-typescript 在 2026/10/15 – 2026/11/13 这 30 天内被下载 6,689 次,日均约 223 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@finverse/sdk-typescript 还在维护吗?

最新版本 0.0.427 发布于 2026/11/13(1 天前);至今共发布 419 个版本,其中过去 12 个月发布了 69 个;首次发布于 2022/03/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。