TypeScript SDK
@tenergy/sdk 是针对平台 API 契约的强类型客户端:每个 operationId 均有对应的方法,类型定义直接源自 openapi.yaml,且每一次请求都会全自动按照 API 规范完成签名。
如果直接进行轻量级调用,您也可以参考 快速上手指南 中的二十行原生 tenergy() 辅助函数。
开始之前
| SDK 的处理机制 | 背后的设计原因 |
|---|---|
| 每次调用自动生成新鲜的时间戳与签名,包括重试 | 签名具有单次有效性:重复使用旧签名会导致 1009 replayed_signature |
| 序列化请求体一次并对这组字节串进行签名 | 避免重复序列化格式微小差异导致签名不匹配 (1002) |
仅对 GET 和 DELETE 在遇到 429、5xx 或可重试错误时自动退避重试(遵循 Retry-After) | 这些幂等读操作可以安全无副作用重试 |
POST 和 PATCH 请求绝不盲目重复发送 | 网络超时的写操作可能已经在后台被执行;需使用相同 client_order_id 由业务层重试 |
除公开查询和注册接口外,每个私有调用都需要 apiKey + apiSecret | 针对免密钥的公开读取,可使用普通 fetch 直接调用 GET /v1/prices 或 /v1/estimate |
步骤 1 — 创建客户端实例
import { TenergyClient } from "@tenergy/sdk";
const tenergy = new TenergyClient({
baseUrl: "https://api-nile.tenergy.me/v1", // 主网请使用 https://api.tenergy.me/v1
apiKey: process.env.TENERGY_KEY!, // Nile 测试网为 ak_test_…
apiSecret: process.env.TENERGY_SECRET!, // 创建密钥时展示的 Secret
});
| 配置选项 | 默认值 | 说明 |
|---|---|---|
baseUrl | — (必填) | 包含 /v1 前缀。末尾斜杠会自动剔除。 |
apiKey, apiSecret | — | 签名调用必需。 |
timeoutMs | 15000 | 单次请求超时时间(毫秒)。 |
retry | { maxRetries: 2, baseDelayMs: 200, maxDelayMs: 5000 } | 仅针对只读与安全幂等接口生效。 |
fetch | globalThis.fetch | 可自定义传入任意兼容 Fetch 签名的实现。 |
步骤 2 — 询价、下单并等待确认
const quote = await tenergy.createQuote({
resource: "energy",
amount: 65_000,
tier: "1h",
receiver: "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE",
});
const order = await tenergy.createOrder({ quote_id: quote.id, client_order_id: "payout-8821" });
const settled = await tenergy.waitForOrder(order.id, { timeoutMs: 30_000 });
if (settled.partial) console.log("已交付", settled.delivered_amount, "目标总量", settled.amount);
waitForOrder 方法会以 1 秒的间隔轮询 GET /v1/orders/{id},直到订单状态变为 active、expired、reclaimed、failed 或 refunded。如果发生超时,方法将抛出 TenergyTimeoutError 并附带最后一次查询到的订单快照 —— 订单本身并不会被取消。
步骤 3 — 异常与错误处理
import { TenergyApiError, TenergyTransportError } from "@tenergy/sdk";
try {
await tenergy.createOrder({ quote_id: quote.id, client_order_id: "payout-8821" });
} catch (error) {
if (error instanceof TenergyApiError && error.slug === "insufficient_funds") {
// 账户余额不足:充值后使用相同的 client_order_id 重试,绝不会重复扣费
} else if (error instanceof TenergyTransportError) {
// 网络未收到响应:使用相同的 client_order_id 重试
} else {
throw error;
}
}
| 错误类名 | 触发场景 | 包含的核心属性 |
|---|---|---|
TenergyApiError | API 返回了标准的错误结构包 | code, slug, httpStatus, field, retryable, details, requestId, retryAfterSeconds |
TenergyTransportError | 网络中断或网关故障(如 502/504) | httpStatus, bodyExcerpt |
TenergyTimeoutError | waitForOrder 轮询等待超时 | waitedMs, last |
请务必按 slug 进行分支捕获,切勿根据英文 message 匹配。
步骤 4 — 验证 Webhook 签名
import { verifyWebhookSignature } from "@tenergy/sdk";
// rawBody: 接收到的原始请求体字节串,在进行任何 JSON 反序列化之前
const valid = verifyWebhookSignature(
process.env.TENERGY_WEBHOOK_SECRET!,
request.headers["x-api-timestamp"],
rawBody,
request.headers["x-api-sign"],
);
该工具函数验证签名;建议您自行检查 X-API-TIMESTAMP 是否在当前时间的 ±300 秒以内(防重放校验),详见 Webhooks 回调。
常用方法一览
| 模块 | 方法列表 |
|---|---|
| 注册入驻 | createAccountChallenge, verifyAccountChallenge, createAccount, getSignupDepositAddress, bootstrap |
| 账户管理 | getAccount, getBalance, listDepositAddresses |
| 价格方案 | getPrices, estimateOrder, getOrderBook, createQuote, getQuote |
| 订单管理 | createOrder, listOrders, getOrder (支持系统 ID 或 cid:<client_order_id>), reclaimOrder, waitForOrder |
| 批量处理 | createBatch, listBatches, getBatch, cancelBatch |
| 自动订阅 | createSubscription, listSubscriptions, getSubscription, updateSubscription, cancelSubscription |
| Webhook 回调 | createWebhook, listWebhooks, getWebhook, updateWebhook, deleteWebhook, rotateWebhookSecret, testWebhook |
| 链上状态 | getAddressResources, estimateTransferEnergy |
| 密钥管理 | listApiKeys, createApiKey, updateApiKey, deleteApiKey |
| 签名工具 | signRequest, canonicalString, apiTimestamp, webhookSignature, verifyWebhookSignature |