一个 HTTP GET 就能跑通:带上 AppID、卡密、机器码,拿回到期时间、剩余次数、最新版本。下面按「先跑通、再加固」的顺序写,示例可直接抄。
只需要三样东西:接口地址、AppID、AppSecret。前两个可以放进客户端;AppSecret 只用来在服务端或你的签名逻辑里算 sign,不要打包进分发给最终用户的程序。
GET 带查询参数,或 POST 表单 / JSON 都行,参数名完全一致。会员门户在 https://key.dlam.cc/user/,与接口读的是同一套数据,会员在门户里看到的到期时间与客户端里必然一致。
ok=true,方便你先接流程、后发码。公共参数(不是每个 act 都要,按需取用):
| 字段 | 说明 |
|---|---|
| appid | 必填。应用编号,后台「应用管理」可见。缺失或写错会直接拒绝。 |
| act | 要做的操作,默认 verify。可选 verify / renew / unbind / register / login / info / logout。 |
| code | 卡密原文。用户手输,或从本地配置读出的那张卡。 |
| machine | 机器码。应用开启「绑定机器码」时必传;建议用 CPU + 主板 + 磁盘序列号做哈希,重装系统尽量不变。 |
| ver | 客户端当前版本号,用来和后台发布版本比对,决定是否推送更新。 |
| username | 账号名。走账号体系时可用它代替 code 验证。 |
| sign / ts | 可选签名与时间戳,见 签名校验。 |
返回永远是同一个信封,先判 code 再取 data:
| 字段 | 说明 |
|---|---|
| code | 200 成功、400 失败。与 HTTP 状态码无关,请以此判断成败。 |
| ok | 布尔值,等价于 code==200,脚本里直接取更省事。 |
| msg | 一句话结论;失败时就是给用户看的提示,可原样展示。 |
| data | 业务数据对象,失败时为空对象。 |
主接口。程序启动时调一次,运行中按周期复验。卡密与账号二选一:只传 code 走纯卡密模式;传 username 会自动取该账号名下最晚到期、仍在有效期内的一张卡。校验通过才会扣量,被拒的请求不动卡密余额。
curl "https://key.dlam.cc/api/verify.php?appid=你的AppID&act=verify&code=卡密&machine=A1B2C3D4E5F6&ver=1.0.0"
{
"code": 200,
"ok": true,
"msg": "验证通过",
"data": {
"auth": {
"code": "SHAO3M9SLQG388RY",
"type": "会员",
"days": 30,
"times_left": 0,
"points": 0,
"expire_at": "2026-11-11 06:25:03",
"days_left": 29,
"activated_at": "2026-10-12 06:25:03",
"username": "",
"machine": "A1B2C3D4E5F6",
"verify_total": 1,
"unbind_left": 2
},
"app": { "name": "星云助手", "version": "1.2.0", "notice": "更新请先到官网下载", "down_url": "", "force_update": 0 },
"update": null,
"notice": null,
"server_time": "2026-10-12T06:25:03+08:00"
}
}
返回字段:
| 字段 | 说明 |
|---|---|
| auth.type | 卡密种类:会员 / 单码 / 次数 / 积分 / 充值。 |
| auth.expire_at | 到期时间。会员卡首次验证才起算(按卡面天数),未激活为 null。 |
| auth.days_left | 剩余天数,向下取整;无到期概念时为 null。 |
| auth.times_left | 剩余次数,次卡每成功验证一次减 1。 |
| auth.points | 剩余积分,积分卡每次成功验证扣掉应用设定的步长。 |
| auth.machine | 当前绑定的机器码,为空表示这张卡还没绑设备。 |
| auth.verify_total | 这张卡累计成功验证次数。 |
| auth.unbind_left | 还能自助解绑几次;应用没开放解绑时为 null。 |
| server_time | 服务器时间,用它校准本地时钟,防止改系统时间白嫖。 |
客户端调用方式完全相同,只是服务端扣量方式不同。定价、生成、发货都在后台完成。
| 字段 | 说明 |
|---|---|
| 会员 | 按天授权。首次验证起算 days 天,之后每次验证只校验是否过期,不扣量。适合订阅制软件。 |
| 单码 | 不带天数时一次一用:验证过一次即作废,第二次直接拒。带天数时等同会员卡,适合试用码、一次性激活码。 |
| 次数 | 每成功验证一次扣 1 次,用完提示「卡密次数已用完」。适合按量收费的工具。 |
| 积分 | 每次扣掉后台设定的「积分步长」,默认 1 分,可按应用调整。 |
| 充值 | 不能用于验证。会员在门户「我的余额」里兑换成金额,走接口验证会被拒。 |
用户手里有张新卡,直接叠到当前卡上,不用重新绑定设备。两张卡类型必须一致,新卡会被消耗。
https://key.dlam.cc/api/verify.php?appid=你的AppID&act=renew&code=当前卡密&newcode=另一张同类型的新卡
| 类型 | 叠加规则 |
|---|---|
| 会员 / 单码 | 取「当前到期时间」与「现在」的较晚者,再加新卡天数;days 累加。已过期的用户因此能无损续上。 |
| 次数 | times_left 直接相加。 |
| 积分 | points 直接相加。 |
| msg | 成功时形如「已续 30 天」,可直接提示给用户。 |
让用户自己换电脑,省掉一半客服。前提是后台把该应用的「自助解绑次数」设为大于 0,否则一律提示联系客服。解绑会清掉机器码、IP 与设备记录。
https://key.dlam.cc/api/verify.php?appid=你的AppID&act=unbind&code=卡密&sig_machine=当前机器码
sig_machine 可选:传了就和卡上的绑定记录核对,避免别人拿卡号恶意解绑。返回里的 auth.unbind_left 是剩余可解绑次数,建议在界面上显示出来。想要账号体系(余额、代理价、名下多张卡)就让用户先注册。可以同时带 code,注册即绑定,省一步。
https://key.dlam.cc/api/verify.php?appid=你的AppID&act=register&username=用户账号&password=至少6位&nickname=显示名&qq=12345678&code=卡密
| 字段 | 说明 |
|---|---|
| username | 4-20 位,只允许字母、数字、下划线;不能与后台管理员重名。 |
| password | 6 位以上,入库用强哈希,接口永不返回密码。 |
| code | 可选。绑给新账号,卡仍需在客户端首次验证才起算。充值卡不能在这里用。 |
| 限制 | 后台关闭「允许注册」时直接拒;同一账号或 IP 失败过多会暂时拒绝。 |
账号密码换一枚 token,之后用 username 验证即可,不必让用户重复输卡密。
https://key.dlam.cc/api/verify.php?appid=你的AppID&act=login&username=用户账号&password=登录密码
{
"ok": true, "msg": "登录成功",
"data": {
"token": "56ad48797ff148f757a054ec79aeca93",
"user": { "username": "xiaoyu", "nickname": "小雨", "balance": 128.5, "spent": 671.5 },
"cards": [ { "code": "...", "type": "会员", "state": "已使用", "expire_at": "2026-11-11 06:25:03" } ],
"app": { "name": "星云助手", "version": "1.2.0" },
"update": null
}
}
只读:不扣次数、不绑设备。适合做「剩余天数」悬浮窗、到期提醒和用户自助查询页。
https://key.dlam.cc/api/verify.php?appid=你的AppID&act=info&code=卡密
比 verify 多一个 state:未使用 / 已使用 / 已过期 / 已用尽 / 已封禁,用来给用户一句人话。
清掉服务端 token,配合本地删配置。token 传了会先核对,避免别人拿账号名顶掉你。
https://key.dlam.cc/api/verify.php?appid=你的AppID&act=logout&username=用户账号&token=登录时拿到的token
不传 sign 时接口照常工作,接入门槛最低。想防止别人扒走 AppID 白嫖,就加上签名:把除 sign 外的全部参数按参数名升序拼成 k=v,用 & 连接,再以 AppSecret 做 HMAC-SHA256,十六进制小写。
<?php
$endpoint = 'https://key.dlam.cc/api/verify.php';
$appid = '你的 AppID';
$secret = '你的 AppSecret'; // 只参与签名,不出现在返回值与日志里
function kami_sign(array $p, $secret) {
unset($p['sign']);
ksort($p);
$parts = [];
foreach ($p as $k => $v) { $parts[] = $k . '=' . $v; }
return hash_hmac('sha256', implode('&', $parts), $secret);
}
function kami_verify($endpoint, $appid, $secret, $code, $machine, $ver = '1.0.0') {
$p = ['appid' => $appid, 'act' => 'verify', 'code' => $code,
'machine' => $machine, 'ver' => $ver, 'ts' => time()];
$p['sign'] = kami_sign($p, $secret);
$ch = curl_init($endpoint . '?' . http_build_query($p));
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 8]);
$raw = curl_exec($ch);
if ($raw === false) { curl_close($ch); return ['ok' => false, 'msg' => '网络异常,请检查网络后重试']; }
curl_close($ch);
return json_decode($raw, true) ?: ['ok' => false, 'msg' => '返回解析失败'];
}
$r = kami_verify($endpoint, $appid, $secret, '卡密', '机器码');
if ($r['ok']) {
$a = $r['data']['auth'];
echo '授权成功,到期:' . ($a['expire_at'] ?: '不限') . PHP_EOL;
} else {
echo $r['msg'] . PHP_EOL; // 直接把提示给用户
}
import hashlib, hmac, time, requests
from urllib.parse import urlencode
ENDPOINT = "https://key.dlam.cc/api/verify.php"
APPID, SECRET = "你的 AppID", "你的 AppSecret"
def sign(params):
p = {k: v for k, v in params.items() if k != "sign"}
canon = "&".join(f"{k}={p[k]}" for k in sorted(p))
return hmac.new(SECRET.encode(), canon.encode(), hashlib.sha256).hexdigest()
def verify(code, machine, ver="1.0.0"):
params = {"appid": APPID, "act": "verify", "code": code,
"machine": machine, "ver": ver, "ts": int(time.time())}
params["sign"] = sign(params)
r = requests.get(ENDPOINT, params=params, timeout=8)
data = r.json()
return data["data"]["auth"] if data["ok"] else data["msg"]
| 字段 | 说明 |
|---|---|
| sign | 对除 sign 外的全部参数做的 HMAC-SHA256,十六进制小写。 |
| ts | 秒级时间戳。带上后服务端只接受 ±300 秒内的请求,防止重放。 |
| 注意 | 布尔和空值都按字符串拼;参数名区分大小写;不要对 value 做 URL 编码后再签。 |
后台「版本发布」发新版、「公告管理」发公告后,客户端不用改代码就能收到,靠的是 verify / login / info 附带的两个字段。
| 字段 | 说明 |
|---|---|
| update | 把 ver 和最新版本比较;已是最新为 null,落后时返回版本详情。 |
| update.version / log | 新版本号与更新说明,可原样贴进更新弹窗。 |
| update.url / size | 下载地址与包体大小;版本里留空时自动回落到应用配置的下载地址。 |
| update.force_update | 1 表示强制更新:建议只留「立即更新」,不放行进入主界面。 |
| notice | 最新一条公告(本应用优先,其次全站公告),null 表示没有。 |
| notice.level | 普通 / 提醒 / 紧急,用来决定弹窗口还是角标。 |
| app.notice | 应用上常驻的一句话提示,适合放「加群领福利」这类长期文案。 |
$r = kami_verify($endpoint, $appid, $secret, $code, $machine, '1.0.0');
if (!empty($r['ok'])) {
$u = $r['data']['update'];
if ($u) {
if ((int)$u['force_update'] === 1) {
kami_forced_update($u['version'], $u['log'], $u['url']); // 不给关闭
} else {
kami_ask_update($u['version'], $u['log'], $u['url']); // 用户可跳过
}
}
$n = $r['data']['notice'] ?? null;
if ($n) kami_show_notice_once($n['id'], $n['title'], $n['content'], $n['level']);
}
id 请存到本地,同一条只弹一次;每次成功验证会给该公告 views 加一,用来统计触达。msg 已经是给人看的话,直接展示即可。下面标注了哪些该让用户重试、哪些该找客服。
| 提示语(msg) | 该怎么处理 |
|---|---|
| 缺少参数 appid / 请提交卡密或账号 | 客户端调用漏参,属于开发问题。 |
| AppID 不存在,请核对后台应用管理 | AppID 写错或应用已被删除。 |
| 该应用已被停用 | 后台关了这个应用;提示「服务暂停,请联系作者」。 |
| 卡密不存在 / 这张卡密属于「其他应用」 | 卡号打错,或拿的是别的软件的卡;让用户核对,不要自动重试。 |
| 卡密已被封禁,请联系客服 | 作弊或退款回收;给出你的联系方式。 |
| 卡密已于 2026-10-01 到期 | 引导续费:卖新卡或走 renew。 |
| 卡密次数已用完 / 积分已用完 | 引导复购,可在门户里直接下单。 |
| 单码已于 … 使用过,请更换卡密 | 一次一用的码被重复使用;补发一张新卡。 |
| 客户端需上报机器码 | 应用开了设备绑定,但客户端没传 machine。 |
| 该卡已绑定其他设备,请解绑后再试 | 换机场景;开放了自助解绑就直接调 act=unbind。 |
| 已达到最多可开机台数(N 台) | 多开超限。 |
| 该应用未开放自助解绑,请联系客服 | 后台把解绑次数设成了 0。 |
| 账号或密码错误 | 不区分「账号不存在」与「密码错误」,避免撞库探测。 |
| 尝试次数过多,请 15 分钟后再试 | 风控生效;客户端应停止自动重试。 |
| 站点尚未连接授权放行云 / 服务已暂停 | 这套系统自身的授权中断,属于站长运维问题,与用户无关。 |
| 事项 | 建议 |
|---|---|
| 调用时机 | 启动必须验一次;运行中每 30 分钟~2 小时复验,防止长时间挂机绕过到期。 |
| 超时与重试 | 8 秒超时;网络类失败最多重试 2 次,业务失败(ok=false)不要重试。 |
| 离线宽限 | 断网时可用上次成功结果宽限 1~3 天,本地记录 server_time 与到期时间做判断,别只信本地时钟。 |
| 机器码 | 取硬件指纹做 SHA1/MD5,长度固定,重装系统尽量不变;不要用纯 MAC(虚拟机可改)。 |
| 本地存储 | 卡密与 token 存到用户目录并做简单混淆;别放安装目录,避免同机多用户串号。 |
| 首次激活 | 会员卡是从第一次成功验证起算天数的,卖卡前提醒用户「装好再激活」。 |
| 错误处理 | 把 msg 原样显示,再补一句客服入口;用户对「卡密不存在」这种短句最容易反复提交。 |
| 版本策略 | ver 要随发布递进,后台强更才有意义。 |
启动:
本地卡密 = 读配置()
本地卡密为空 → 弹窗输入卡密 → 校验格式 → 保存
r = 调 verify(code, machine, ver)
r.ok 为假 → 显示 r.msg → 询问是否重输卡密 → 回到上一步
r.data.auth.expire_at 存在且已过期 → 视为失败(防本地缓存脏数据)
r.data.update 非空 → 弹更新(force_update=1 时不给关闭)
r.data.notice 非空 且 id 未读过 → 弹公告,记录 id
运行:
每 1 小时 → 调 verify → 失败立即锁功能并显示 msg
网络失败 → 用离线宽限,超过宽限同样锁功能