开始之前
准备三样东西,五分钟即可。
- 账户和余额。创建访问密钥,用加密货币充值。订购号码会扣除余额,因此账户中必须有钱。
- 一个具有
admin权限范围的 API 密钥。订购号码会产生费用,因此read和write密钥无权操作。请在 API 密钥页面创建;密钥只显示一次。 - 一个我们能够访问的 HTTPS 端点。纯 HTTP 会被拒绝。本地开发时,任何隧道工具都可以使用。
不要把密钥放进代码仓库。 admin 密钥可以持续订购号码,直到余额耗尽。请使用环境变量、密钥管理器或其他安全方式,绝不能提交到仓库;如果密钥泄露,应先在控制面板中撤销,再做其他处理。
第 1 步——订购号码
只需一次调用。系统会扣除余额,并在分配确认后返回结果;号码约一分钟内开始接收消息。
curl -X POST https://api.nokycphone.com/v1/numbers \
-H "Authorization: Bearer $NKP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"country":"de","type":"mobile","period":1,"label":"signup-bot"}'
# 201 Created
{
"id": "num_8f2c1a94",
"e164": "+4915735550088",
"status": "active",
"renews_at": "2026-10-21T09:14:02Z",
"charged": { "monthly": 12.90, "activation": 10.00, "total": 22.90 }
}始终发送 Idempotency-Key。 在你的系统看来,请求超时和请求失败无法区分。带上此标头后,重试会重放已保存的响应,而不会再订购第二个号码;该记录会保留 24 小时。
第 2 步——注册 Webhook
每个端点只需注册一次,之后便可停止轮询。密钥只会在这次响应中返回,以后不再显示,因此请立即保存。
curl -X POST https://api.nokycphone.com/v1/webhooks \
-H "Authorization: Bearer $NKP_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.org/hooks/nkp","events":["message.received"]}'
# 201 Created
{
"id": "whk_77c1e0",
"url": "https://example.org/hooks/nkp",
"events": ["message.received"],
"secret": "whsec_2b91f4c7a0d3…"
}只订阅你确实会处理的事件。完成这项任务时,需要了解以下事件:
message.received——收到一条短信,验证码已自动提取。number.active——订购的号码已经启用。number.grace——余额不足导致续费失败。请为此事件设置警报;它会在号码消失前提前 3 天发出警告。topup.credited——充值已确认到账。
第 3 步——验证签名
如果一个端点接受发送给它的任何内容,那就不是 Webhook,而是一个公开的写入 API。信任请求正文前,必须先验证签名。
签名以端点密钥为键,对 timestamp + "." + raw_body 计算 HMAC-SHA256,再编码为十六进制;它位于 X-NKP-Signature 标头中,格式为 v1=…。
import hmac, hashlib, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["NKP_WEBHOOK_SECRET"].encode()
seen = set() # en production : Redis, avec une expiration
@app.post("/hooks/nkp")
def hook():
raw = request.get_data() # le corps BRUT, jamais re-serialise
ts = request.headers.get("X-NKP-Timestamp", "")
sig = request.headers.get("X-NKP-Signature", "").split("=", 1)[-1]
if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
abort(400) # trop vieux : rejeu
mine = hmac.new(SECRET, f"{ts}.".encode() + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(mine, sig):
abort(401)
delivery = request.headers["X-NKP-Delivery"]
if delivery in seen:
return "", 200 # deja traite : on acquitte quand meme
seen.add(delivery)
event = request.get_json()
if event["event"] == "message.received":
enqueue(event["data"]) # traiter APRES avoir repondu
return "", 200这个处理程序中有三件事至关重要;漏掉任何一项,都可能造成真实的服务中断:
- 对原始正文签名。解析 JSON 后重新序列化会改变字节,导致 HMAC 校验失败。
- 使用恒定时间比较。用
==比较签名会泄露时序信息。 - 拒绝过旧的时间戳。如果没有五分钟窗口,截获的请求就能被无限重放。
你会收到什么
POST /hooks/nkp HTTP/1.1
X-NKP-Event: message.received
X-NKP-Delivery: evt_6f0b28d4
X-NKP-Timestamp: 1789033541
X-NKP-Signature: v1=6b3a1f8e7c0d94aa5e2b…
Content-Type: application/json
{
"event": "message.received",
"created_at": "2026-09-21T09:45:41Z",
"data": {
"id": "msg_5b1f77c0",
"number": "num_8f2c1a94",
"e164": "+4915735550088",
"from": "Telegram",
"body": "Your login code is 72194. Do not share it.",
"code": "72194",
"received_at": "2026-09-21T09:45:41Z"
}
}code 由服务器按照控制面板所用的同一套规则提取:识别 4 至 8 位数字组,去掉空格和连字符,并忽略发件人自己的号码。如果没有内容符合验证码特征,该字段为 null,而 body 仍会保留,供你自行解析。
重试、顺序及其他容易踩坑之处
- 采用至少一次投递。请根据
X-NKP-Delivery去重。同一个 ID 永远不会代表两个不同事件。 - 不保证顺序。间隔一秒的两条消息可能以任意顺序到达。如果顺序很重要,请按
created_at排序。 - 必须在十秒内响应。处理程序响应更慢会被视为失败,事件将重新投递。应先确认接收,再执行后续工作。
- 大约一天内尝试八次,退避间隔依次为 10 秒、1 分钟、5 分钟、30 分钟、2 小时、6 小时、12 小时和 24 小时。
- 连续三天全部失败会禁用端点,控制面板会明确提示。数据不会丢失:仍可通过 API 读取消息。
保留轮询作为后备方案。 Webhook 是快速通道,而不是事实数据源。每隔几分钟执行一次轻量的 GET /v1/messages?since=…,可以补回端点停机期间漏掉的内容;没有新内容时也不会产生额外成本。
第 4 步——让自动化持续健康运行
如果自动化程序只订购号码却从不释放,余额会在不知不觉中耗尽。请养成两个习惯:
- 释放已经用完的号码。
DELETE /v1/numbers/{id}会立即生效并停止续费。消息会随之删除,因此请先读取。 - 监控
number.grace。这是号码自动释放前唯一的警告,会提前 3 天发出。
# release every line labelled "signup-bot" that has been idle for a week
curl -s "https://api.nokycphone.com/v1/numbers?label=signup-bot" \
-H "Authorization: Bearer $NKP_KEY" |
jq -r '.data[] | select(.last_message_at < (now - 604800 | todate)) | .id' |
while read -r id; do
curl -s -X DELETE "https://api.nokycphone.com/v1/numbers/$id" \
-H "Authorization: Bearer $NKP_KEY"
done每个密钥的速率限制为每分钟读取 120 次、写入 30 次,订购操作另有单独上限。每个响应都带有 X-RateLimit-Remaining;收到 429 时,应遵循 Retry-After,不要继续猛发请求。完整数值见 API 参考文档。
常见问题
我需要使用 Webhook,还是轮询就够了?
规模较小时,轮询完全可用,而且更容易调试。Webhook 会在一秒内送达,而不用等到下一次轮询;没有事件时也没有成本。多数人最终会两者并用:Webhook 保证速度,低频轮询提供安全网。
为什么我的签名验证总是失败?
最常见的原因是正文在计算哈希前已经被解析并重新序列化。必须严格按收到时的原始字节计算签名。第二常见的原因是只对正文计算哈希,而没有依次加入时间戳、一个英文句点和正文。
可以为每个号码设置不同的 Webhook 吗?
可以。通过 PATCH 在号码上设置的专属 Webhook URL 会覆盖账户级端点;这是把不同自动化任务路由到不同服务的简洁方式。
如果我的服务器停机会怎样?
我们会在约一天内重试八次。连续三天全部失败后,端点会被禁用,控制面板会明确提示。无论如何消息都不会丢失,仍可通过 API 读取。
有官方 SDK 吗?
没有,这是有意为之。接口规模很小,封装库反而会比 HTTP 调用更快过时。API 参考文档中提供了完整的 Node 和 Python 客户端示例,各自大约十五行。
本文由运营本服务的团队撰写,更新于 2026年5月21日。如果其中有任何错误或过时内容,请告诉我们——我们更新指南的速度比修复代码更快。
