Finverse API - 类型脚本 SDK
这个SDK可以实现端到端后端与Finverse API的集成,包括API认证,机构连接,数据检索和支付操作.
安装
npm install @finverse/sdk-typescript
API 概览
SDK分为两大类API:
| API 密码 | 目的 |
|---|---|
| 支付 API | 建立支付链接、任务、支付和管理支付账户 |
| 数据 API | 获取账户、交易、报表、余额历史和身份数据 |
API 共享认证并通过 PublicApi 财务报告和审定财务报表 LinkApi。 。 。 .
支付 API
Paying API 允许您创建出票支付链接,启动支付,管理任务,并处理与支付相关的业务.
密钥类和方法( M)
| 类 | 关键方法 |
|---|---|
PaymentApi | createPaymentLink, (中文(简体) ), getPaymentLink, (中文(简体) ), cancelPaymentLink, (中文(简体) ), createScheduledPayout, (中文(简体) ), getPayoutById, (中文(简体) ), createPaymentMethod, (中文(简体) ), createPayment, (中文(简体) ), getPayment, (中文(简体) ), createMandate, (中文(简体) ), getMandate, (中文(简体) ), authorizeMandate, (中文(简体) ), createPaymentUser, (中文(简体) ), createPaymentAccount, (中文(简体) ), listPaymentAccounts |
付款流量(终到终)
支付链接流量 : 创建 → 重定向 → 回电 → 票价 → 结果。 。 。 .
- 创建 - 通过API创建支付链接, 获取
url财务报告和审定财务报表payment_link_id。保存两者和unique_reference_id。 。 。 . - 重定向 – 将用户重定向到支付链接 URL(使用HTTP 303,因此重定向会跟随GET).
- 回电 – Finverse 重定向以
payment_link_id财务报告和审定财务报表unique_reference_id查询参数。 校验它们符合你储存的. - 票价 - 波尔
GET /payment_links/{paymentLinkId}每2秒,最多30秒,直到session_status实值"COMPLETE"。 。 。 . - 结果 - 如果
COMPLETE成功;否则错误.
警卫:
FINVERSE_CLIENT_ID财务报告和审定财务报表FINVERSE_CLIENT_SECRET必须 永远 承诺提供或发送到前端。 只在服务器上使用(例如环境变量,秘密管理器).
1. 认证:获取客户访问托肯
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)
2. 建立支付链接
支付模式 ——一次性支付. 要求数 amount (小型单位,如:1000=100.00港元), currency, (中文(简体) ), sender, (中文(简体) ), payment_details,以及 link_customizations 与 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
设置模式 – 对于储蓄支付方法(例如点击到支付). 这样做 没有 通过 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. 将用户重新定向到支付 URL
重新引导用户到 paymentUrl。 。 。 . 使用 HTTP 303 因此浏览器跟随 GET( Finverse 期望得到) :
4. 召回处理器:填表
当 Finverse 重定向时, 读 payment_link_id 财务报告和审定财务报表 unique_reference_id 从查询参数。 校验它们与你存储的数值相符, 然后民意调查直到 session_status 实值 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
数据 API
Data API 使您能够检索财务数据:账户、交易、报表、平衡历史、身份和收入估计数.
密钥类和方法( M)
| 类 | 关键方法 |
|---|---|
LoginIdentityApi | getLoginIdentity, (中文(简体) ), listAccounts, (中文(简体) ), getAccount, (中文(简体) ), getAccountNumber, (中文(简体) ), listTransactionsByLoginIdentityId, (中文(简体) ), listTransactionsByAccountId, (中文(简体) ), getStatements, (中文(简体) ), getStatement, (中文(简体) ), getBalanceHistory, (中文(简体) ), getIdentity, (中文(简体) ), getIncomeEstimateByLoginIdentityId, (中文(简体) ), listCardDetails, (中文(简体) ), refreshLoginIdentity |
数据检索流量( 端到端)
1. 认证:获取客户访问托肯
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;
2. 链接新机构:获取链接托肯和链接URL
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. 最终确定链接:登录身份访问托肯交换码
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. 获取数据:获取登录身份
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. 投票登录身份状态直至做好准备
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. 获取账户
const accountsResp = await new LoginIdentityApi(dataConfig).listAccounts();
console.log("accounts:", accountsResp.data.accounts);
7. 获取交易(加页标)
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. 获取声明
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));
最佳做法
使用同步/等待
所有SDK方法都回归承诺. 使用 async/await 用于更清洁、可读的代码并避免召回地狱:
async function fetchAccounts() {
const config = new Configuration({ basePath: apiHost, accessToken: token });
const response = await new LoginIdentityApi(config).listAccounts();
return response.data.accounts;
}
正确处理 API 响应
API 方法返回 Axios AxiosResponse 对象。 通过 .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
使用导出类型和接口
利用 SDK 的导出类型来保证类型安全和更好的IDE支持 :
import type {
Account,
CreatePaymentRequest,
GetLoginIdentityByIdResponse,
} from '@finverse/sdk-typescript';
const paymentRequest: CreatePaymentRequest = {
// ...
};
处理尝试/捕获物出错
将 API 呼叫在尝试/捕获块中 。 API 出错作为 HTTP 出错响应返回; SDK 可能投放到网络故障或验证错误上 :
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;
}
}
处理验证错误
当缺少所需的参数时,SDK会抛出错误. 将 API 调用到尝试/ 抓取中, 处理验证和其他失败 .
重用配置实例
创建一个 Configuration 一次每个信使/密码,再用于多次API呼叫:
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);
客户端秘密: 永远不会执行, 仅服务器侧
永远不要把你的客户端秘密用于版本控制. 客户端的秘密必须保密,只用于服务器上.
- 只有服务器侧 : 这个SDK是为后端使用而设计的. 永远不要暴露
client_secret到浏览器、移动应用程序或任何客户端代码. - 使用环境变量或机密管理器 : 从安全存储器在运行时装入证书 .
- 添加为
.gitignore数字 : 保证.env和任何包含秘密的文件 永远不会被执行.
// ✅ 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;
支付能力
对于支付和任务操作,使用一能键安全地重试请求而无需产生重复支付. 如果请求因网络问题而失败, 您可以用相同的密钥重试—— API 将返回原始结果而不是创建重复 .
支持一能键的方法: createPayment, (中文(简体) ), createMandate, (中文(简体) ), createMandateForExistingSender,以及 createScheduledPayout 打开 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);
最佳做法:
- 每个独特的付款或任务使用一个独有能力键.
- 将密钥存储在您的命令/任务记录中, 以便在需要时您可以使用相同的密钥重试 .
AI代理机构的资源
对于实施Finverse整合的AI代理人 Finverse AI 存储器 载有支付流动、数据检索和其他Finverse API模式的技能、执行指南和参考文件。 详细整合指示请遵循此链接: https://github.com/finversetech/ai (中文(简体) )