简介 快速开始 签名算法 API 接口 示例代码 错误码 常见问题

对接文档

鸽子网络验证 · 客户端接入指南

简介

鸽子网络验证提供基于 HTTP 的卡密授权验证服务。客户端通过 AppKey 与 AppSecret 对请求签名,调用接口完成卡密激活、验证与心跳保活。

所有接口同时支持 POST 与 GET: POST 使用 JSON 请求体;GET 将参数放在 URL query string。 响应体统一为 JSON。推荐使用 POST(参数不出现在 URL,更安全)。

若客户端因代理/防火墙导致 POST 被降级为 GET,服务端也能正常处理,无需特殊配置。

快速开始

API 基础地址:https://wlyz.nogay.cn

签名算法

每个请求必须携带 app_key、device_id、 timestamp(Unix 秒)与 sign 四个字段; 强烈建议同时携带 nonce(随机串)以启用防重放。

签名规则(推荐,带 nonce):

sign = md5(app_key + device_id + timestamp + nonce + app_secret)

兼容旧版(不带 nonce):

sign = md5(app_key + device_id + timestamp + app_secret)

其中 + 表示字符串直接拼接,拼接后取 32 位小写 MD5。 服务器会校验 timestamp 与当前时间的误差(默认 300 秒,可在系统设置中调整), 超出范围将拒绝请求,请确保客户端时间准确。nonce 建议 16 位以上随机串, 同一 nonce 在时间窗内只能使用一次,重复请求会被拒绝(防重放)。

API 接口

POST GET /api/activate   激活卡密

首次使用卡密时调用,将卡密与当前设备绑定,并计算有效期。

参数类型必填说明
app_keystring是应用标识
device_idstring是设备唯一标识
timestampint是Unix 时间戳(秒)
signstring是签名
codestring是卡密

成功响应:

{
  "code": 0,
  "msg": "激活成功",
  "data": {
    "card_kind": 1,
    "expire_at": "2026-11-10 00:55:20",
    "bound_count": 1,
    "max_devices": 2
  }
}

POST GET /api/verify   验证卡密

程序运行过程中校验授权是否有效。可传入 code,也可省略(凭已绑定设备识别)。

参数类型必填说明
codestring否卡密(省略时按设备查找)
其余公共参数同 activate

成功响应:

{
  "code": 0,
  "msg": "验证通过",
  "data": {
    "card_kind": 1,
    "expire_at": "2026-11-10 00:55:20",
    "remaining": null,
    "heartbeat": 300
  }
}

POST GET /api/heartbeat   心跳保活

定期调用以维持在线状态,建议按响应中的 heartbeat(秒)间隔调用。

{
  "code": 0,
  "msg": "心跳正常",
  "data": { "heartbeat": 300, "server_time": "2026-10-11 00:55:20" }
}

POST GET /api/logout   退出

客户端退出时调用,将设备标记为离线。

GET /api/notice   获取公告

获取最新公告列表,无需签名。

{
  "code": 0,
  "msg": "ok",
  "data": [
    { "title": "维护通知", "content": "...", "level": "info", "created_at": "2026-10-11 00:00:00" }
  ]
}

示例代码

PHP

<?php
$appKey   = 'AK5B02D5D6B2A77372';
$appSecret = '你的AppSecret';
$deviceId = '设备唯一标识';
$code     = 'GZ-XXXX-XXXX-XXXX';

$ts   = time();
$sign = md5($appKey . $deviceId . $ts . $appSecret);

$data = [
    'app_key'   => $appKey,
    'device_id' => $deviceId,
    'timestamp' => $ts,
    'sign'      => $sign,
    'code'      => $code,
];

$ch = curl_init('http://your-domain/api/activate');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_POSTFIELDS     => json_encode($data),
    CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
]);
$resp = json_decode(curl_exec($ch), true);

if ($resp['code'] === 0) {
    echo '激活成功,到期:' . $resp['data']['expire_at'];
} else {
    echo '失败:' . $resp['msg'];
}

Python

import time, hashlib, requests

app_key    = "AK5B02D5D6B2A77372"
app_secret = "你的AppSecret"
device_id  = "设备唯一标识"
code       = "GZ-XXXX-XXXX-XXXX"

ts   = str(int(time.time()))
sign = hashlib.md5((app_key + device_id + ts + app_secret).encode()).hexdigest()

data = {
    "app_key": app_key, "device_id": device_id,
    "timestamp": ts, "sign": sign, "code": code,
}
resp = requests.post("http://your-domain/api/activate", json=data).json()
print(resp)

JavaScript (Node)

const crypto = require('crypto');

const appKey = 'AK5B02D5D6B2A77372';
const appSecret = '你的AppSecret';
const deviceId = '设备唯一标识';
const code = 'GZ-XXXX-XXXX-XXXX';

const ts = Math.floor(Date.now() / 1000).toString();
const sign = crypto.createHash('md5')
  .update(appKey + deviceId + ts + appSecret).digest('hex');

fetch('http://your-domain/api/activate', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    app_key: appKey, device_id: deviceId,
    timestamp: ts, sign, code
  })
}).then(r => r.json()).then(console.log);

错误码

code说明
0成功
400参数不完整或非法
401签名校验失败 / 请求已过期
403卡密被封禁 / 已过期 / 设备未绑定 / 设备数已达上限
404应用或卡密不存在
429请求过于频繁(触发频率限制)
500服务器内部错误

常见问题

提示「签名校验失败」?

请确认 AppSecret 正确、拼接顺序为 app_key + device_id + timestamp + app_secret,且结果为小写 MD5。

提示「请求已过期」?

客户端系统时间与服务器时间误差过大。请校准时间,误差需在系统设置的「时钟误差」范围内。

卡密如何换绑设备?

在控制台「设备管理」中将旧设备踢下线,即可释放绑定名额。

次数卡如何计数?

每次成功调用 /api/verify 计一次,次数耗尽后卡密自动失效。