测试与集成指南
概述
这是在端点详情页点击立即测试后打开的页面。您可以直接在浏览器中测试 API 调用,无需任何额外工具,还可以与协作者分享,让他们在一个地方找到集成所需的所有信息。
此页面的测试仅在沙盒环境中进行。不会影响生产环境数据,请放心试验。
页面有两个标签页:
- 快速开始 — 使用 API 密钥认证并立即测试调用
- 指南 — 面向所有者和协作者的集成参考(分步指南、API 端点、头信息、字段定义、代码示例等)
如何进入
- 端点详情右侧边栏 > 立即测试 按钮(沙盒环境标签页)
- 协作者接受邀请后也可以从自己的仪表盘访问
端点信息

- 显示端点名称和描述
- 旁边显示环境标签(沙盒环境)和版本信息
- 在 快速开始 / 指南 标签页之间切换
快速开始标签页
认证
要开始测试,需要先使用 API 密钥进行认证。


认证后,输入框消失,显示 退出 按钮。要使用其他密钥测试,先退出再重新认证。
试一试

认证后,CRUD 调用执行区域被激活。选择方法,输入请求体(JSON),点击 Execute 即可立即看到结果。
如果想一次性测试完整流程,请按以下顺序进行:
完整 CRUD 测试指南
CREATE (POST) — 在请求体中输入测试 JSON 并执行。从响应中复制
id——后续步骤需要用到。READ — 单条查询 (GET) — 将
id粘贴到 Record ID 字段并执行。该记录的完整 payload 会被返回。READ — 列表查询 (GET list) — 不带 Record ID 调用 GET,按时间倒序返回最近的记录。使用
limit(1-30,默认 10)和cursor进行分页;将响应中的pagination.next_cursor作为下一次调用的cursor即可获取下一页。READ — 搜索 (GET search) — 通过 payload 中的关键词查找记录。使用
q(必需,3-200 个字符)以及可选的start/end(未指定时为最近 30 天)、limit、cursor。匹配为不区分大小写的子串匹配,采用游标分页。READ — 轮询 (GET poll) — 获取上次轮询之后创建的记录,从旧到新。首次调用不传任何参数(从现在开始订阅)或使用
since;之后每次都把上一次响应中的游标原样传回。next_cursor表示还有积压,应立即再次调用;poll_cursor表示已经追平,保存它并等到下一个周期。UPDATE (PUT) — 输入相同的
id,并在请求体中提供修改后的 JSON。这是完全替换,所以要保留的字段和要更改的字段都需要包含。DELETE — 输入相同的
id并执行。之后再试一次 READ,确认记录已被删除。
权限检查:使用协作密钥测试时,只能执行该密钥权限允许的方法。调用未授权的方法返回 403 错误。请在协作密钥 > 权限中查看权限。
协作者 Webhook

试一试区域底部有一个可折叠的 Webhook 设置区域。这与所有者在仪表盘配置的 Webhook 不同——它是让 API 调用者在请求头中包含 Webhook 信息,以便在指定的 URL 接收处理结果。您可以在此测试这些头信息。
- 与所有者 Webhook 独立运行
- 在实际集成中,Webhook 头信息直接包含在 API 调用代码中
- 详细的头名称和实现方法请参阅指南标签页的 Webhook 设置部分
指南标签页
指南标签页的结构让所有者和协作者都可以在一个地方查看完整的集成流程和技术细节。顶部是角色专属的分步指南,下方是技术参考。
入门 — 所有者

选择 我创建了端点 标签页,从所有者的视角查看步骤。
- 创建端点 — 只需设置 API 名称,CRUD 自动创建。描述和必填字段可以稍后添加
- 沙盒环境测试和日志检查 — 在快速开始标签页使用默认 API 密钥发起调用,然后在仪表盘日志中验证数据接收
- 创建协作密钥并邀请 — 在详情页创建密钥并发送邮件邀请
- 集成测试 — 通过日志共同验证协作者在沙盒环境中的调用是否正确
- 生产环境部署 — 批准协作者的部署请求,或直接部署。部署后协作者会收到通知
入门 — 协作者

选择 我被邀请了 标签页,从协作者的视角查看步骤。
- 接受邀请 — 查看邀请邮件,登录后在仪表盘上接受
- 查看 API 密钥 — 在端点详情页找到您的沙盒环境 API 密钥(
tm_test_) - 集成和测试 — 在快速开始标签页测试调用,参考指南标签页的技术信息进行开发。如果收到 202 响应,说明系统保证处理
- 请求部署 — 测试完成后,在端点详情页提交部署请求
- 切换到生产环境 — 所有者完成部署后您会收到通知。从生产环境标签页查看并应用生产环境 API 密钥(
tm_live_)
API 端点

显示该端点可用的 API 路径和方法。创建端点时自动准备以下方法。
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /api/v1/data/{slug} |
创建新记录 |
| GET | /api/v1/data/{slug}/{record_id} |
按 ID 获取记录 |
| GET | /api/v1/data/{slug} |
获取最近记录列表(cursor 分页) |
| GET | /api/v1/data/{slug}/search |
按 payload 文本搜索(q, 可选 start/end;最少 3 字符,游标分页) |
| GET | /api/v1/data/{slug}/poll |
获取上次轮询之后创建的记录,从旧到新(since 或 cursor,游标分页) |
| PUT | /api/v1/data/{slug}/{record_id} |
替换记录 |
| DELETE | /api/v1/data/{slug}/{record_id} |
删除记录 |
{slug} 是端点创建时自动分配的唯一标识符。您可以在此页面查看实际值。
搜索 (search) 调用需要 q(3-200 个字符)。start / end(YYYY-MM-DD 或 RFC 3339)是可选的,未指定时自动使用最近 30 天。范围没有上限。结果为游标分页,有下一页时响应包含 pagination.next_cursor。匹配为 payload 全文不区分大小写的子串匹配,因此可能出现数字或 JSON 键的误匹配(例如搜索 32 也会匹配 132)。搜索使用与单条 GET / GET 列表相同的 read 权限。
轮询 (poll) 调用按 created_at 升序推进记录——与列表、搜索相反。不传任何参数即从现在开始订阅,用 since(YYYY-MM-DD 或 RFC 3339,一律为 UTC——2026-08-28 是 UTC 零点而非本地零点)指定起点,或用 cursor 续传;since 与 cursor 同时传入返回 400。limit 为 1-100(默认 100),且不包含在游标中,因此每页都要重新传。每次响应只会包含两种游标中的一种:next_cursor 表示还有积压,应立即再次调用;poll_cursor 表示已经追平,保存它并等到下一个周期。最近约 60 秒会被排除,因为 created_at 由网关签发,而实际写入要经过队列异步完成——没有这段余量,水位线就会越过仍在途中的记录。那些记录会在后续轮询中到达:是延后,不是丢失。重试和重启可能重复投递同一条记录,因此请按记录 id 做幂等处理。轮询使用与单条 GET / GET 列表 / GET 搜索相同的 read 权限。
API 密钥

API 调用认证所需的密钥信息。
| 环境 | 密钥前缀 | 用途 |
|---|---|---|
| 沙盒环境 | tm_test_ |
开发和测试 |
| 生产环境 | tm_live_ |
正式服务 |
生产环境 API 密钥可在部署完成后在端点详情页找到。部署前,使用生产环境密钥的调用将被拒绝。
请求头

API 调用中需要包含的 HTTP 头信息。Content-Type 和 Authorization 为必需;Webhook 头仅在需要时添加。
| 头信息 | 是否必需 | 说明 |
|---|---|---|
Content-Type |
必需 | application/json(用于 POST/PUT) |
Authorization |
必需 | Bearer {API_KEY} 格式 |
X-Webhook-Callback |
可选 | 接收调用者 Webhook 的 URL |
X-Webhook-Auth |
可选 | Webhook 认证值(例如 Bearer token) |
X-Webhook-Auth-Header |
可选 | Webhook 认证头键(默认:Authorization) |
请求体

关于 POST/PUT 请求发送的 JSON 请求体的信息。
- 格式:JSON(
application/json)· 最大 100KB · UTF-8 - 如果所有者定义了必填字段,这些字段必须包含。必填字段以外的额外字段可以自由发送
- 如果未定义必填字段,任何 JSON 都可接受
- 请求异步处理。您会立即收到 202 响应,实际存储和 Webhook 发送在后台进行
响应格式

显示各方法的成功响应和错误代码。
成功响应:
- POST/PUT/DELETE →
202 Accepted(请求已接受并加入队列) - GET(单条) →
200 OK(记录立即返回) - GET(列表) →
200 OK(分页数据 + 还有下一页时返回next_cursor) - GET(搜索) →
200 OK(分页数据 + 还有下一页时返回next_cursor) - GET(轮询) →
200 OK(从旧到新的数据 +next_cursor/poll_cursor中恰好一个)
错误代码:
| 代码 | 状态 | 含义 |
|---|---|---|
| 400 | Bad Request | 无效 JSON、缺少必填字段、无效记录 ID |
| 401 | Unauthorized | API 密钥缺失或无效 |
| 403 | Forbidden | 端点未激活、无订阅或权限不足 |
| 415 | Unsupported Media Type | Content-Type 不是 application/json |
| 429 | Too Many Requests | 月度使用量超出限额 |
| 5xx | Server Error | 临时服务器错误——请实现重试逻辑 |
如果收到 5xx 错误,请求未到达服务器。请在代码中实现重试逻辑(例如 1 秒 → 2 秒 → 4 秒退避)。如果收到 202 响应,系统保证处理。
Webhook 设置

设置调用者 Webhook 以自动接收处理结果的说明。与所有者在仪表盘配置的 Webhook 独立运行。
设置方法:在 API 调用中包含以下头信息。
| 头信息 | 是否必需 | 说明 |
|---|---|---|
X-Webhook-Callback |
必需 | 接收 Webhook 的 URL |
X-Webhook-Auth |
可选 | 认证值(例如 Bearer token) |
X-Webhook-Auth-Header |
可选 | 认证头键(默认:Authorization) |
每次 Webhook 都会附带的头信息:
| 头信息 | 说明 |
|---|---|
X-3minapi-Record-Id |
记录 ID。所有投递尝试中该值相同——请用它判断重复 |
X-3minapi-Delivery-Attempt |
尝试次数,从 1 开始 |
webhook-id |
记录 ID,与 X-3minapi-Record-Id 值相同 |
webhook-timestamp |
签名时间(unix 秒)。每次尝试都会重新生成 |
webhook-signature |
HMAC-SHA256 签名。更换密钥期间会收到两个 |
接收方需要遵守的约定:
- 请在 15 秒内返回 2xx。将繁重处理交给你自己的队列,先响应
- 2xx 表示"我收到了",而不是"处理成功了"。即使你这边的处理失败也要返回 2xx —— 上游调用被拒、你这边的校验错误、无法履行的订单都算 —— 并把该失败记录在你自己的系统里。5xx 只用于它真正表达的情况:你的接收端或它依赖的服务临时故障,稍后重新投递同一条记录有可能成功。返回 5xx 会让我们按下方的重试计划反复重发该记录,你的接收端每次都会把同一份工作再执行一遍
- 同一个
X-3minapi-Record-Id可能到达多次。请用它判断该记录是否已处理
重试策略:
- 成功标准:2xx 状态码 —— 它只确认投递已被接收,并不表示你这边的处理成功
- 生产环境共 6 次尝试——首次投递 1 次 + 重试 5 次(30 秒·2 分·10 分·1 小时·4 小时,约 5 小时)。沙箱环境共 4 次尝试——首次投递 1 次 + 重试 3 次(30 秒·2 分·10 分,约 12 分钟)
- 会重试:5xx(501、505 除外)、429、超时、连接错误。429 上的
Retry-After仅作为「再多等一会儿」的请求生效——不会缩短默认间隔,超过 4 小时的值会被忽略 - 不会重试:除 429 外的所有 4xx——包括 409,我们将其理解为"接收方已收到"。修正设置后,下次调用即可正常送达
- 即使全部尝试失败,数据仍安全存储——在保留期内(生产环境至少 60 天,沙盒 30 天)可以稍后用轮询端点取回。投递失败或仍在重试的记录会出现在日志页面的 Webhook 投递中,连响应正文和每次尝试都能查看
- 一旦放弃投递(重试用尽,或收到不会重试的永久性响应),我们会通过邮件通知端点所有者——不分套餐(免费套餐同样适用),但仅限生产环境且为所有者 Webhook,每个端点每天最多一封。没有后续邮件,也没有恢复通知。协作者 Webhook 的失败不会发送邮件,因为端点所有者无法更改该 URL
验证 Webhook 签名
我们发送的每个 Webhook 都带有 HMAC-SHA256 签名,你可以据此确认请求确实来自 3Min API,且在传输途中未被改动。
验证是可选的——如果你已经在接收 Webhook,无需任何改动即可继续正常工作。启用后可以防止得知你接收 URL 的人发送伪造请求,从而让你的服务器把真正的投递当作"已处理"而丢弃。
这不是加密。 正文仍与以往一样以明文发送。改变的只是:请求头中多了一枚指纹,用来证明"这份正文自离开 3Min API 后一个字符都没变过"。
指纹由三部分拼接而成。
签名对象 = "{webhook-id}.{webhook-timestamp}.{请求正文原文}"
密钥 = 去掉 whsec_ 前缀后再做 base64 解码得到的字节
签名 = base64( HMAC-SHA256(密钥, 签名对象) )
这三部分各自防范不同的问题。
| 部分 | 防范什么 |
|---|---|
| 请求正文 | 在传输途中掉包、篡改内容 |
| webhook-timestamp | 把过去截获的真实请求原样重放 |
| webhook-id | 冒用他人的记录 ID,诱使你把真正的投递当作"已处理"而丢弃 |
密钥位置:控制台 > 端点详情 > Webhook 签名密钥。沙箱与生产环境各自独立。
使用库验证(推荐)
我们完全遵循 Standard Webhooks 规范,使用官方库只需几行代码。
| 语言 | 包 |
|---|---|
| Node.js / TypeScript | standardwebhooks (npm) |
| Python | standardwebhooks (pip) |
| PHP | standard-webhooks/standard-webhooks (composer) |
| Go | github.com/standard-webhooks/standard-webhooks/libraries/go |
| Ruby | standardwebhooks (gem) |
| Java / Kotlin | com.standardwebhooks:standardwebhooks |
| C# | StandardWebhooks (NuGet) |
| Rust | standardwebhooks (crates.io) |
| Elixir | standard_webhooks (hex) |
// npm i standardwebhooks
import { Webhook } from 'standardwebhooks';
import express from 'express';
const app = express();
// 서명은 우리가 보낸 바이트 그대로에 대해 계산됩니다.
// JSON으로 파싱한 뒤 다시 문자열로 만들면 반드시 실패합니다.
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const wh = new Webhook(process.env.WEBHOOK_SIGNING_SECRET.replace('whsec_', ''));
try {
const payload = wh.verify(req.body, {
'webhook-id': req.header('webhook-id'),
'webhook-timestamp': req.header('webhook-timestamp'),
'webhook-signature': req.header('webhook-signature')
});
// 검증 통과 — payload를 처리하세요
res.sendStatus(200);
} catch {
res.sendStatus(401);
}
});
自行实现时
- 去掉密钥的
whsec_前缀,将其余部分做 base64 解码得到密钥字节 - 检查
webhook-timestamp是否在当前时间的 ±5 分钟内(阻止重放的旧请求) - 计算
base64(HMAC_SHA256(密钥, "{webhook-id}.{webhook-timestamp}.{原始报文}")) - 将
webhook-signature按空格拆分,只要以v1,开头的项中有任意一项匹配即通过
注意事项
- 对原始字节计算。 解析 JSON 后再序列化会改变键顺序和空白,验证必然失败。Express 用
express.raw,Flask 用request.get_data(),PHP 用file_get_contents('php://input') - 签名可能不止一个。 更换密钥期间会收到两个,只检查第一个就判定失败会导致整个过渡期全部被拒
- 忽略非
v1,开头的项。 这样将来新增其他版本时你的代码仍能正常工作 - 不要用
==比较。 请使用恒定时间比较:crypto.timingSafeEqual(Node)、hmac.compare_digest(Python)、hash_equals(PHP)
更换密钥
只有端点所有者可以重新签发密钥,而且这是密钥泄露时的应对手段——不是需要定期轮换的值。签发后 24 小时内会同时发送新旧两个签名,你可以在这段时间内的任意时刻更新接收服务器,不会丢失投递。24 小时后只发送新签名。
如果你是以协作者身份接收 Webhook,同样可以查看密钥——你的 Webhook 也用同一个密钥签名。只有重新签发是所有者专属权限。
代码示例

提供包括 curl、JavaScript 和 Python 在内的主要语言的 API 调用代码示例。切换标签页查看各语言的示例。实际端点 URL 和必需头信息已预填,可以直接复制使用。
API 参考标签页

将此端点的规范以 OpenAPI 风格一目了然地整理 显示的标签页。每个方法卡片都包含请求 URL、请求头、路径/查询参数、请求体结构、响应示例,无需外部工具即可在此页面查看完整的集成规范。
- 如果说快速开始标签页是"直接调用确认",那么 API 参考标签页就是 "查看规范、编写集成代码" 的用途
- POST / GET(单条) / GET(列表) / GET(搜索) / GET(轮询) / PUT / DELETE 按卡片分开,可一目了然地比较各方法的差异
- 响应示例使用与实际响应相同的 JSON 结构展示 — 可直接用于客户端的类型定义
常见问题
- 点击授权后没有反应:请检查 API 密钥是否以
tm_test_(沙盒环境密钥)开头。生产环境密钥(tm_live_)不能在此页面使用 - CREATE 后丢失了 ID:再次调用 CREATE 生成新记录继续测试。如果需要之前记录的 ID,请在仪表盘日志页面查看调用历史
- 收到 403 错误:您使用的协作密钥可能没有该方法的权限。请在协作密钥 > 权限中查看
- Webhook 未到达:Webhook 服务器必须在 15 秒内响应。请检查是否可公开访问且使用 HTTPS。Discord 和 Slack 等平台有速率限制——如果短时间内触发了过多 Webhook,部分可能会被拦截