API 密钥管理 — API 参考
管理此账户的认证凭据。
| 方法 | 路径 | 概览 |
|---|---|---|
GET | /v1/api-keys | 列出该账户的所有 API 密钥 |
POST | /v1/api-keys | 创建新的 API 密钥 |
PATCH | /v1/api-keys/{keyId} | 修改 API 密钥 |
DELETE | /v1/api-keys/{keyId} | 撤销 API 密钥 |
基于 openapi.yaml 在构建时生成。基准 URL 为 https://api.tenergy.me/v1,Nile 测试网环境为 https://api-nile.tenergy.me/v1(详见环境说明)。下述每个请求均遵循身份鉴权规范进行签名,除非鉴权行另有说明。
列出该账户的所有 API 密钥
GET /v1/api-keys · listApiKeys
鉴权: API 密钥 (HMAC)。
此接口绝不会返回密钥私钥(Secret)—— Secret 仅在创建成功的响应中返回唯一一次。此处显示的 key 是用于在请求头 X-API-KEY 中传递的公开标识符。
响应
| 状态码 | 含义 |
|---|---|
200 | OK |
401 | 缺少、格式错误或已被拒绝的凭据。 |
500 | 服务端内部错误。 |
响应字段
| 字段 | 类型 | 必选 | 说明 |
|---|---|---|---|
data | array of object (ApiKey) | 是 | |
data[].id | string | 是 | |
data[].key | string | 是 | 在 X-API-KEY 头部传递的公开标识符。非敏感数据。 |
data[].label | string | 是 | |
data[].scopes | array of enum (13 values, ApiKeyScope) | 是 | |
data[].ip_allowlist | array of string | ||
data[].is_active | boolean | 是 | |
data[].last_used_at | string (date-time) | null | 该密钥最近一次签名请求的时间。每个密钥最多每分钟记录一次,回答的是“该密钥是否仍在活跃使用”,而非精确到秒级的时间戳。 | |
data[].last_used_ip | string | null | 最近一次请求的来源 IP 地址。使用前为 null。 | |
data[].expires_at | string (date-time) | null | ||
data[].created_at | string (date-time) | 是 | |
limit | integer | 是 | 该账户可同时持有的活跃密钥数量上限。属于产品配额限制,并非权限体系:限制凭据数量,不限制具体功能。超出配额时 POST /api-keys 返回 3017 api_key_limit_reached;撤销废弃密钥可立即释放名额。 |
used | integer | 是 | 当前活跃密钥数 —— 已撤销或已过期的密钥不计入。 |
创建新的 API 密钥
POST /v1/api-keys · createApiKey
鉴权: API 密钥 (HMAC) 或引导令牌 (Bootstrap token)。
创建密钥并仅展示一次私钥 Secret。私钥在服务端不可逆存储;若遗失请删除该密钥并新建。
账户的第一个密钥使用注册流程中获取的引导令牌 (Bootstrap token) 创建;其后的密钥均由具备 keys.create 权限的现有密钥创建。
亦支持未充值账户(自 2026-09-26 起生效),以便系统集成后无需人工介入即可凭新密钥查询充值地址并充值。
scopes 字段必填且没有默认值。API 刻意不预设任何默认权限模板:密钥权限范围必须由账户所有者在对照权限清单后明确做出决定。未提供 scopes 的请求将被拒绝并返回 2001 validation_failed,任何客户端 SDK、Agent 自动化工作流或控制台表单均不得代为填充。
统一权限字典
权限采用 area.action 规范命名,全平台使用统一权限列表。下表中列出的是 v1 版本中 API 密钥可被授予的权限范围。权限体系中的其余项 —— balance.withdraw、billing.write、invoices.read、referral.read、referral.withdraw、team.read、team.invite、team.remove、team.grant、settings.write、audit.read —— 适用于控制台团队协作管理,在 v1 版本中不支持通过 API 密钥使用。
| Scope | 授予的能力 |
|---|---|
prices.read | POST /estimate/transfer (GET /prices, GET /estimate 与 GET /resources/{address} 为公开接口,无需权限) |
balance.read | GET /account, GET /balance —— 余额及历史累计统计 |
balance.topup_address | GET /deposit-addresses —— 账户的充值地址及已废弃历史地址 |
orders.read | GET /orders (包括 CSV 导出), GET /orders/{id}, GET /batches…, GET /quotes/{id}, GET /account/stats |
orders.create | POST /orders, POST /quotes, POST /batches, POST /batches/{id}/cancel —— 扣减账户资金 |
orders.reclaim | POST /orders/{id}/reclaim —— 提前结束租赁质押,不予退款 |
subscriptions.read | GET /subscriptions… |
subscriptions.write | 创建、修改、取消周期订阅 —— 产生持续扣款承诺 |
webhooks.read | GET /webhooks…,包括 GET /webhooks/{id}/deliveries |
webhooks.write | 创建、修改、删除、轮换及测试 Webhook 回调端点 |
keys.read | GET /api-keys |
keys.create | POST /api-keys, PATCH /api-keys/{id} —— 具备此权限的密钥可扩大该账户的访问能力 |
keys.revoke | DELETE /api-keys/{id} —— 可直接终止线上生产集成 |
GET /ledger、GET /account/addresses 与 GET /session/history 属于控制台会话专属操作,不向任何 API 密钥开放权限。
新建密钥所包含的权限范围不能超出创建方密钥自身所拥有的权限,因此 keys.create 不能用于权限越权升级。而使用 Bootstrap token 创建的密钥可被赋予任意 API 密钥有效权限,因为此时的签名者是账户的所有者。
请求体
JSON (ApiKeyRequest),必填。
| 字段 | 类型 | 必选 | 说明 |
|---|---|---|---|
label | string | 可选。若未填写,将自动按索引顺序命名为 Key N,以便无需即兴取名即可批量创建。标签仅作展示,不涉及权限控制。 | |
scopes | array of enum (13 values, ApiKeyScope) | 是 | 必填,无默认值,服务端不设猜测建议。名称来源于平台统一权限体系;详见端点说明。 |
ip_allowlist | array of string | 允许使用此密钥的来源 IP 地址或 CIDR 网段。为空或省略表示允许所有 IP —— 对于只读密钥可接受,对于有资金消耗权限的密钥不建议。 | |
expires_at | string (date-time) | null | 自动吊销时间。null 表示永不过期。 |
来自规范的请求体示例(示意数值):
{
"label": "grafana exporter",
"scopes": ["balance.read","orders.read"],
"ip_allowlist": ["203.0.113.10"]
}
响应
| 状态码 | 含义 |
|---|---|
201 | 创建成功。secret 仅在此次响应中返回一次。 |
400 | 格式错误的请求 —— 无效 JSON、未知字段或字段类型错误。 |
401 | 缺少、格式错误或已被拒绝的凭据。 |
403 | 已通过认证,但当前密钥无权执行此操作。 |
409 | 3017 api_key_limit_reached —— 活跃密钥数已达上限。包含 details.limit 与 details.used;撤销废弃密钥可释放名额。 |
422 | 语法合法但逻辑上无法满足操作要求。 |
500 | 服务端内部错误。 |
响应字段
| 字段 | 类型 | 必选 | 说明 |
|---|---|---|---|
id | string | 是 | |
key | string | 是 | 在 X-API-KEY 头部传递的公开标识符。非敏感数据。 |
label | string | 是 | |
scopes | array of enum (13 values, ApiKeyScope) | 是 | |
ip_allowlist | array of string | ||
is_active | boolean | 是 | |
last_used_at | string (date-time) | null | 最近一次签名请求的时间戳。最多每分钟刷新一次。 | |
last_used_ip | string | null | 最近一次请求的来源 IP。使用前为 null。 | |
expires_at | string (date-time) | null | ||
created_at | string (date-time) | 是 | |
secret | string | 是 | HMAC 私钥 Secret,256 位,仅展示一次。生产环境前缀为 sk_live_…,Nile 环境前缀为 sk_test_…。不可恢复:若遗失请撤销并重建。 |
修改 API 密钥
PATCH /v1/api-keys/{keyId} · updateApiKey
鉴权: API 密钥 (HMAC)。
修改 label、ip_allowlist、is_active 或 scopes。收紧 scopes 立即生效;扩充权限同样遵循创建时的防越权原则:调用方密钥必须已经拥有所扩充的全部权限。
请求参数
| 参数名 | 位置 | 类型 | 必选 | 说明 |
|---|---|---|---|---|
keyId | path | string | 是 |
请求体
JSON (ApiKeyPatch),必填。
| 字段 | 类型 | 必选 | 说明 |
|---|---|---|---|
label | string | ||
scopes | array of enum (13 values, ApiKeyScope) | ||
ip_allowlist | array of string | ||
is_active | boolean | ||
expires_at | string (date-time) | null |
响应
| 状态码 | 含义 |
|---|---|
200 | 已更新 |
400 | 格式错误的请求 —— 无效 JSON、未知字段或字段类型错误。 |
401 | 缺少、格式错误或已被拒绝的凭据。 |
403 | 已通过认证,但当前密钥无权执行此操作。 |
404 | 目标对象不存在或属于其他账户。 |
422 | 语法合法但逻辑上无法满足操作要求。 |
500 | 服务端内部错误。 |
响应字段 (ApiKey)
| 字段 | 类型 | 必选 | 说明 |
|---|---|---|---|
id | string | 是 | |
key | string | 是 | 在 X-API-KEY 头部传递的公开标识符。非敏感数据。 |
label | string | 是 | |
scopes | array of enum (13 values, ApiKeyScope) | 是 | |
ip_allowlist | array of string | ||
is_active | boolean | 是 | |
last_used_at | string (date-time) | null | 该密钥最近一次签名请求的时间戳。 | |
last_used_ip | string | null | 最近一次请求的来源 IP。 | |
expires_at | string (date-time) | null | ||
created_at | string (date-time) | 是 |
撤销 API 密钥
DELETE /v1/api-keys/{keyId} · deleteApiKey
鉴权: API 密钥 (HMAC)。
立即生效且不可撤销。正在处理中且附带此密钥签名的请求将立即被拒;此前已成功创建的订单不受影响,将继续正常执行交付。
密钥不能自我删除 —— 避免在它是账户唯一密钥时导致账户无法再次访问。如需撤销自己的密钥,请在控制台中操作。
请求参数
| 参数名 | 位置 | 类型 | 必选 | 说明 |
|---|---|---|---|---|
keyId | path | string | 是 |
响应
| 状态码 | 含义 |
|---|---|
204 | 已撤销。无响应体。 |
401 | 缺少、格式错误或已被拒绝的凭据。 |
403 | 已通过认证,但当前密钥无权执行此操作。 |
404 | 目标对象不存在或属于其他账户。 |
500 | 服务端内部错误。 |