云 SP云验证

开发文档

云验证 HTTP API · 支持网站后端、前端 JavaScript、桌面程序与 Android APK

接入流程

云验证平台通过一组简单的 HTTP JSON 接口,为你的网站或软件提供卡密验证能力。整体流程如下:

  • 注册账号:在平台注册(若站点开启付费注册,需先完成支付)后登录控制台。
  • 创建应用:每个网站 / APK 建议创建独立应用,获得专属 API Key 与 Secret。
  • 生成卡密:在「卡密管理」中批量生成,设置每张卡密的可用次数与有效期。
  • 接入代码:在你的代码中填入 API Key,将用户输入的卡密提交到验证接口。
  • 验证成功即扣次:接口返回剩余次数,验证失败不扣次。
建议将站点部署在 HTTPS 下,避免 API Key 与卡密在传输过程中被截获。

获取 API 凭证

登录后进入「我的应用」,创建应用即可看到以下信息:

名称示例用途
API Key pk_8f3a...c1d2 请求时标识你的应用,必填
API Secret sk_2b7e...9f00 计算请求签名(可选),不要写进网页前端
重置凭证后旧 Key 与 Secret 会立即失效,线上项目请谨慎操作。

生成卡密

在「卡密管理」中可以为指定应用批量生成卡密,参数含义:

  • 生成数量:单次 1 ~ 100 张。
  • 每张可用次数:每成功验证一次扣减 1 次,次数用完后卡密自动失效。
  • 有效期:从生成时间开始计算,0 表示永久有效。
  • 备注:仅用于后台识别,例如「月卡」「渠道 A」。

卡密格式为 16 位字符,通常按 XXXX-XXXX-XXXX-XXXX 展示。接口同时兼容带与不带分隔符的写法。

验证接口

验证卡密并扣减一次使用次数。支持 application/json、表单或 Query 参数。

POST https://cloud.spent.cc/api/verify.php

请求参数

参数类型必填说明
keystring是应用 API Key
cardstring是用户输入的卡密,可带 -
devicestring条件必填设备唯一标识。应用开启「设备绑定」后必须提供,且首次验证的标识会被绑定
signstring否请求签名,见下方「签名校验」
tsint否Unix 时间戳,使用签名时必填

请求示例

curl
curl -X POST https://cloud.spent.cc/api/verify.php \
  -H 'Content-Type: application/json' \
  -d '{"key":"pk_你的APIKey","card":"ABCD-EFGH-JKLM-NPQR","device":"device-001"}'

成功时返回:

JSON
{
  "ok": true,
  "code": 0,
  "msg": "验证成功,扣除 1 次",
  "data": {
    "card": "ABCD-EFGH-JKLM-NPQR",
    "remaining": 9,
    "used": 1,
    "max_uses": 10,
    "expires_at": null,
    "bind_device": false,
    "device": "device-001",
    "server_time": "2026-01-01 12:00:00"
  }
}

返回格式

所有接口均返回 JSON,HTTP 状态码通常为 200,通过 ok 与 code 判断业务结果。

字段类型说明
okbool业务是否成功
codeint0 表示成功,其余为错误码
msgstring可直接展示给用户的提示
data.remainingint本次验证后剩余可用次数
data.usedint已使用次数
data.max_usesint总可用次数
data.expires_atstring|null到期时间,null 表示永久有效

错误码

code含义建议处理
0成功—
1001缺少 API Key检查请求参数 key
1002API Key 无效检查是否复制完整或凭证是否被重置
1003应用 / 账号已被禁用联系平台管理员
1004签名校验失败或时间戳过期检查签名算法、Secret 与服务器时间
1005缺少卡密参数检查请求参数 card
2001卡密不存在或不属于该应用确认卡密归属的应用与输入的卡密
2002卡密已被禁用提示用户联系管理员
2003卡密已过期提示用户续费
2004卡密次数已用完提示用户续费
2005缺少设备标识开启设备绑定后必须传 device
2006设备不匹配卡密已绑定其他设备
5000服务异常稍后重试或联系管理员

查询接口

仅查询卡密状态与剩余次数,不会扣减次数,可用于「查询余额」等功能。

GET https://cloud.spent.cc/api/query.php?key=pk_xxx&card=ABCD-EFGH-JKLM-NPQR

参数与验证接口一致。返回的 data.status 取值:

  • active:可用
  • disabled:已被禁用
  • expired:已过期
  • used_up:次数已用完
JSON
{
  "ok": true,
  "code": 0,
  "msg": "查询成功",
  "data": {
    "card": "ABCD-EFGH-JKLM-NPQR",
    "status": "active",
    "status_text": "可用",
    "remaining": 9,
    "used": 1,
    "max_uses": 10,
    "expires_at": null,
    "bind_device": false,
    "bound_device": null,
    "server_time": "2026-01-01 12:00:00"
  }
}

签名校验(可选)

API Key 需要写入客户端,可能被他人获取。启用签名后,服务端会校验请求是否由持有 Secret 的一方发起:

签名算法:sign = HMAC_SHA256("card|device|ts", API Secret),ts 为 Unix 时间戳,有效期 ±300 秒。
PHP · 生成签名
<?php
// 可选:为请求附加签名,防止他人拿到 API Key 后随意调用
$card   = 'ABCD-EFGH-JKLM-NPQR';       // 卡密
$device = 'device-fingerprint';         // 设备标识
$ts     = time();                       // Unix 时间戳(±300 秒内有效)

// API Secret 来自后台「我的应用」页面
$sign = hash_hmac('sha256', $card . '|' . $device . '|' . $ts, $apiSecret);

$payload = [
    'key'    => $apiKey,
    'card'   => $card,
    'device' => $device,
    'ts'     => $ts,
    'sign'   => $sign,
];

请求时携带 sign 与 ts 两个参数即可,平台会自动校验。APK 场景仍建议把关键业务校验放在服务端,客户端签名只能提高门槛,无法绝对防止逆向。

示例代码

以下代码可直接复制使用,记得替换 API Key。接口地址已自动填充为你当前站点的地址。

适用于网站后端。建议将卡密校验放在服务端,验证通过后再放行内容。

PHP · 网站后端验证
<?php
// 服务端验证示例:建议在网站后端调用,避免 API Key 暴露给浏览器
const CLOUD_API_KEY  = 'pk_请替换成你的APIKey';
const CLOUD_VERIFY_URL = 'https://cloud.spent.cc/api/verify.php';

/**
 * 验证卡密(每次成功调用会扣减 1 次)
 * @return array{ok:bool, code:int, msg:string, data?:array}
 */
function cloud_verify(string $card, string $device): array
{
    $payload = json_encode([
        'key'    => CLOUD_API_KEY,
        'card'   => $card,
        'device' => $device,
    ], JSON_UNESCAPED_UNICODE);

    $ch = curl_init(CLOUD_VERIFY_URL);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $payload,
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 8,
    ]);

    $body  = curl_exec($ch);
    $error = curl_error($ch);
    curl_close($ch);

    if ($body === false) {
        return ['ok' => false, 'code' => -1, 'msg' => '网络请求失败: ' . $error];
    }

    $result = json_decode($body, true);
    return is_array($result)
        ? $result
        : ['ok' => false, 'code' => -1, 'msg' => '返回数据格式错误'];
}

// 使用示例:用户提交卡密后调用
$result = cloud_verify($_POST['card'] ?? '', $_SERVER['REMOTE_ADDR']);

if ($result['ok']) {
    echo '验证成功,剩余 ' . $result['data']['remaining'] . ' 次';
} else {
    echo '验证失败:' . $result['msg'];
}

适用于网页前端演示。API Key 会暴露给浏览器,正式项目建议通过你自己的后端代理请求。

JavaScript · 网页验证
<form id="verify-form">
  <input id="card-input" placeholder="请输入卡密">
  <button type="submit">验证</button>
</form>
<p id="verify-result"></p>

<script>
const API_KEY  = 'pk_请替换成你的APIKey';
const API_URL  = 'https://cloud.spent.cc/api/verify.php';

// 生成并持久化一个浏览器设备标识(仅作示例,可按需替换)
function getDeviceId() {
  let id = localStorage.getItem('cloud_device_id');
  if (!id) {
    id = 'web-' + (crypto.randomUUID ? crypto.randomUUID() : Math.random().toString(36).slice(2));
    localStorage.setItem('cloud_device_id', id);
  }
  return id;
}

document.getElementById('verify-form').addEventListener('submit', async (event) => {
  event.preventDefault();
  const resultEl = document.getElementById('verify-result');
  resultEl.textContent = '验证中...';

  try {
    const response = await fetch(API_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        key:    API_KEY,
        card:   document.getElementById('card-input').value.trim(),
        device: getDeviceId()
      })
    });

    const result = await response.json();
    resultEl.textContent = result.ok
      ? '验证成功,剩余 ' + result.data.remaining + ' 次'
      : '验证失败(' + result.code + '):' + result.msg;
  } catch (error) {
    resultEl.textContent = '网络错误:' + error.message;
  }
});
</script>

适用于桌面工具、脚本或自动化程序,使用 Python 标准库,无需安装额外依赖。

Python · 本地程序验证
"""云验证 Python 示例(仅使用标准库,无需额外依赖)"""
import json
import urllib.request

API_KEY = "pk_请替换成你的APIKey"
API_URL = "https://cloud.spent.cc/api/verify.php"


def verify_card(card: str, device: str) -> dict:
    """验证成功时平台会扣减 1 次,失败不会扣减"""
    payload = json.dumps({
        "key": API_KEY,
        "card": card,
        "device": device,
    }).encode("utf-8")

    request = urllib.request.Request(
        API_URL,
        data=payload,
        headers={"Content-Type": "application/json"},
        method="POST",
    )

    try:
        with urllib.request.urlopen(request, timeout=8) as response:
            return json.loads(response.read().decode("utf-8"))
    except Exception as exc:
        return {"ok": False, "code": -1, "msg": f"请求失败: {exc}"}


if __name__ == "__main__":
    result = verify_card("ABCD-EFGH-JKLM-NPQR", "desktop-device-001")
    if result.get("ok"):
        print("验证成功,剩余", result["data"]["remaining"], "次")
    else:
        print("验证失败:", result.get("msg"))

适用于 Android APK。请务必在子线程中调用,并声明 INTERNET 权限。

Java · Android APK 验证
// Android 示例(API 21+)
// 请在 AndroidManifest.xml 中声明网络权限:
// <uses-permission android:name="android.permission.INTERNET" />

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;

public final class CloudVerify {
    private static final String API_KEY = "pk_请替换成你的APIKey";
    private static final String API_URL = "https://cloud.spent.cc/api/verify.php";

    /** 必须在子线程调用,Android 禁止主线程发起网络请求 */
    public static JSONObject verify(String card, String deviceId) throws Exception {
        URL url = new URL(API_URL);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setConnectTimeout(8000);
        conn.setReadTimeout(8000);
        conn.setDoOutput(true);
        conn.setRequestProperty("Content-Type", "application/json");

        JSONObject payload = new JSONObject();
        payload.put("key", API_KEY);
        payload.put("card", card);
        payload.put("device", deviceId);

        try (OutputStream out = conn.getOutputStream()) {
            out.write(payload.toString().getBytes(StandardCharsets.UTF_8));
        }

        int status = conn.getResponseCode();
        BufferedReader reader = new BufferedReader(new InputStreamReader(
                (status >= 200 && status < 300) ? conn.getInputStream() : conn.getErrorStream(),
                StandardCharsets.UTF_8));

        StringBuilder body = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            body.append(line);
        }
        reader.close();
        conn.disconnect();

        return new JSONObject(body.toString());
    }
}

// 调用示例(子线程):
// String deviceId = Settings.Secure.getString(
//         getContentResolver(), Settings.Secure.ANDROID_ID);
// JSONObject result = CloudVerify.verify(card, deviceId);
// if (result.optBoolean("ok")) {
//     int remaining = result.getJSONObject("data").optInt("remaining");
// }

下载示例文件

下载完整示例文件后,替换其中的 API Key 即可运行:

常见问题

验证失败会扣次数吗?

不会。只有验证成功时才会扣减 1 次。查询接口也不会扣次。

设备绑定是如何工作的?

开启后,卡密首次验证成功时会记录设备标识;之后同一张卡密在其它设备上验证会返回 2006。请尽量使用稳定的设备标识,例如 Android 的 ANDROID_ID 或浏览器持久化 ID。

卡密次数可以修改吗?

已生成的卡密不能直接修改次数,可以禁用后重新生成。次数与有效期在生成时确定。

一个应用可以给多个网站使用吗?

可以。同一个应用下的卡密可以在任何一处使用该 API Key 的代码中验证。不同业务建议创建不同应用,便于区分数据。

API Key 泄露了怎么办?

在「我的应用」中点击「重置凭证」,旧 Key 立即失效,然后更新你的代码。同时建议开启设备绑定,降低损失。

数据存储在哪里?

所有数据保存在你部署服务器上的 SQLite 数据库中(默认 data/cloudauth.db),不经过第三方服务器。