API 接口文档

为开发者提供专业的正版授权解决方案,支持多种编程语言快速接入

概述

兴旺云卡密授权平台提供标准 RESTful API 接口,支持所有主流编程语言调用。所有接口均支持 JSON 和表单两种请求方式,返回格式统一为 JSON。

使用 API 前,请先注册账号并在后台创建应用,获取 APPIDAPP密钥

提示:建议将 API 请求放在您的服务端进行,避免在客户端暴露 APP 密钥。

接口地址

// 接口基础地址
https://您的域名/api/

// 完整接口示例
https://您的域名/api/verify.php

签名机制

为确保请求安全,部分接口(如在线解绑)需要使用签名验证。签名算法如下:

第一步:将所有请求参数按参数名 ASCII 码从小到大排序
第二步:将排序后的参数拼接成字符串:key1=value1&key2=value2
第三步:在字符串末尾拼接 APP 密钥:key1=value1&key2=value2&app_secret=xxx
第四步:对拼接后的字符串进行 SHA256 加密,得到签名值
注意:APP 密钥请勿暴露在客户端代码中,建议通过您的服务端调用。

返回格式

{
  "code": 200,
  "msg": "成功",
  "data": {}
}
字段类型说明
codeint状态码,200表示成功,其他表示失败
msgstring返回消息描述
dataobject/array返回数据,失败时可能为null

错误码说明

状态码说明
200请求成功
400参数错误(缺少必要参数)
401验证失败(卡密无效、已过期、设备不匹配等)
403权限不足(密钥错误或签名验证失败)
404资源不存在
500服务器内部错误

卡密验证

POST /api/verify.php
验证卡密有效性。首次验证时自动激活卡密并绑定设备;后续验证时检查卡密状态和设备绑定。

请求参数

参数名类型必填说明
app_keystring必填应用标识(APPID)
codestring必填卡密
device_idstring必填设备机器码
device_infostring可选设备详细信息

返回示例

{
  "code": 200,
  "msg": "验证成功",
  "data": {
    "code": "ABCD-1234-EFGH-5678",
    "type": "month",
    "type_name": "月卡",
    "duration": 720,
    "status": 1,
    "expire_at": "2026-08-12 10:30:00"
  }
}

心跳保活

POST /api/heartbeat.php
心跳保活接口,软件运行中定期调用,保持在线状态并获取剩余时间。建议调用间隔30-60秒。

请求参数

参数名类型必填说明
app_keystring必填应用标识
codestring必填卡密
device_idstring必填设备机器码

返回示例

{
  "code": 200,
  "msg": "心跳成功",
  "data": {
    "online": 1,
    "online_count": 42,
    "remaining": 604800
  }
}

在线解绑

POST /api/unbind.php
在线解绑接口,解除卡密与设备的绑定关系。需要 APP 密钥验证。
重要:此接口需要 app_secret(APP密钥),请勿将密钥暴露在客户端代码中!

请求参数

参数名类型必填说明
app_keystring必填应用标识
app_secretstring必填应用密钥
codestring必填卡密
device_idstring必填要解绑的设备机器码

获取公告

GET /api/notice.php
获取指定应用的公告列表,按排序值从大到小排列。公告可在后台发布,软件端对接显示。

请求参数

参数名类型必填说明
app_keystring必填应用标识

返回示例

{
  "code": 200,
  "msg": "获取成功",
  "data": {
    "list": [
      {
        "id": 1,
        "title": "重要更新通知",
        "content": "新版本已发布,请及时更新",
        "sort": 100,
        "created_at": "2026-07-12 10:00:00"
      }
    ]
  }
}

自定义公告一

GET /api/notice1.php
获取自定义公告一的标题和内容。在后台应用设置中配置,用于软件弹窗、启动页公告等场景。

请求参数

参数名类型必填说明
app_keystring必填应用标识

返回示例

{
  "code": 200,
  "msg": "获取成功",
  "data": {
    "title": "欢迎使用",
    "content": "欢迎使用本软件,请遵守使用协议。"
  }
}

自定义公告二

GET /api/notice2.php
获取自定义公告二的标题和内容。在后台应用设置中配置,可用于活动公告、维护通知等独立场景。

请求参数

参数名类型必填说明
app_keystring必填应用标识

返回示例

{
  "code": 200,
  "msg": "获取成功",
  "data": {
    "title": "系统维护通知",
    "content": "7月20日凌晨2点至4点进行系统维护,期间可能短暂无法使用。"
  }
}

获取版本

GET /api/version.php
获取应用的最新版本信息,可用于软件自动更新检测。

请求参数

参数名类型必填说明
app_keystring必填应用标识

返回示例

{
  "code": 200,
  "msg": "成功",
  "data": {
    "version": "1.0.1",
    "title": "更新说明",
    "download_url": "https://xxx.com/download",
    "force_update": 0
  }
}

版本列表

GET /api/version_list.php
获取应用的版本列表,支持分页查询,按版本发布时间倒序排列。

请求参数

参数名类型必填说明
app_keystring必填应用标识
pageint可选页码,默认1
pageSizeint可选每页数量,默认20,最大100

返回示例

{
  "code": 200,
  "msg": "获取成功",
  "data": {
    "list": [
      {
        "id": 3,
        "version": "1.0.2",
        "title": "新增功能",
        "download_url": "https://xxx.com/v1.0.2",
        "update_log": "修复Bug",
        "force_update": 0,
        "created_at": "2026-07-12 10:00:00"
      }
    ],
    "total": 15,
    "page": 1,
    "pageSize": 20,
    "totalPage": 1
  }
}

账号注册

软件端调用此接口注册新账号,注册后需使用激活码激活才能登录。

POST /api/account_register.php
参数类型必填说明
app_keystring应用标识(APPID)
usernamestring账号(3-50字符)
passwordstring密码(6-64字符)
返回示例:
"code": 200,
"msg": "注册成功",
"data": {
    "username": "user001",
    "status": 0,
    "msg": "注册成功,请使用激活码激活账号"
}

账号激活

使用平台生成的卡密/激活码激活已注册的账号,激活后账号获得对应卡密的有效期。
单设备互斥在线:激活成功后,本次 device_id 即登记为当前在线设备;若账号此前在其他机器在线,旧机器下次心跳会被踢下线。

POST /api/account_activate.php
参数类型必填说明
app_keystring应用标识(APPID)
usernamestring账号
passwordstring密码
codestring平台激活码/卡密
device_idstring本台机器唯一标识(用于互斥登录踢线,同账号后登录保留)
返回示例:
"code": 200,
"msg": "激活成功",
"data": {
    "username": "user001",
    "status": 1,
    "kami_code": "ABCD-EFGH-...",
    "expire_at": "2025-12-31 23:59:59",
    "remaining_seconds": 15552000,
    "type": "month",
    "type_name": "月卡",
    "single_device": true
}

账号登录

验证账号密码并登录,返回有效期和自定义数据等信息。
单设备互斥在线:如果账号已在其他设备登录,本次登录后 accounts.device_id 更新为本机,旧设备下次心跳会被踢下线(返回 kicked=true)。

POST /api/account_login.php
参数类型必填说明
app_keystring应用标识(APPID)
usernamestring账号
passwordstring密码
device_idstring本台机器唯一标识(同账号后登录保留,旧设备被踢)
返回示例:
"code": 200,
"msg": "登录成功",
"data": {
    "username": "user001",
    "status": 1,
    "expire_at": "2025-12-31 23:59:59",
    "remaining_seconds": 15552000,
    "last_login": "2025-01-01 12:00:00",
    "kicked_other": true,
    "single_device": true,
    "custom_data": "自定义内容"
}

kicked_other = true 表示本次登录把前一台在线的机器踢下线了;false 表示就是本机再次登录,不涉及踢线。

账号心跳保活

软件端定时调用此接口保持在线状态,建议每60秒调用一次。
被踢下线判定:若账号已在其他设备登录,本机本次心跳会返回 403data.kicked=true,软件应立即退出登录并提示用户。

POST /api/account_heartbeat.php
参数类型必填说明
app_keystring应用标识(APPID)
usernamestring账号
passwordstring密码
device_idstring本台机器唯一标识(必须与登录时传入一致)
正常返回示例:
"code": 200,
"msg": "心跳成功",
"data": {
    "online": true,
    "username": "user001",
    "expire_at": "2025-12-31 23:59:59",
    "remaining_seconds": 15552000,
    "last_heartbeat": "2025-01-01 12:00:30",
    "single_device": true
}
被其他设备踢下线示例(账号在别处登录):
"code": 403,
"msg": "账号已在其他设备登录,您已被踢下线",
"data": {
    "kicked": true,
    "reason": "another_device_login",
    "single_device": true
}

多语言接入示例

Py Python
import requests
import json

url = "https://您的域名/api/verify.php"
data = {
  "app_key": "您的APPID",
  "code": "卡密",
  "device_id": "设备机器码"
}

try:
  response = requests.post(url, json=data, timeout=10)
  result = response.json()
  if result["code"] == 200:
    print("验证成功:", result["data"])
  else:
    print("验证失败:", result["msg"])
except Exception as e:
  print("请求异常:", str(e))
C++ C/C++
#include <iostream>
#include <string>
#include "curl/curl.h"

size_t WriteCallback(char *contents, size_t size, size_t nmemb, std::string *s) {
  s->append(contents, size * nmemb);
  return size * nmemb;
}

std::string request_api(const std::string& url, const std::string& json_data) {
  CURL *curl = curl_easy_init();
  std::string response_string;
  if (curl) {
    struct curl_slist *headers = NULL;
    headers = curl_slist_append(headers, "Content-Type: application/json");
    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data.c_str());
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_string);
    curl_easy_perform(curl);
    curl_easy_cleanup(curl);
    curl_slist_free_all(headers);
  }
  return response_string;
}

int main() {
  std::string url = "https://您的域名/api/verify.php";
  std::string data = "{\"app_key\":\"您的APPID\",\"code\":\"卡密\",\"device_id\":\"设备码\"}";
  std::string result = request_api(url, data);
  std::cout << result << std::endl;
  return 0;
}
J Java
import java.net.http.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;

public class ApiClient {
  public static void main(String[] args) throws Exception {
    HttpClient client = HttpClient.newHttpClient();
    String json = "{\"app_key\":\"您的APPID\",\"code\":\"卡密\",\"device_id\":\"设备码\"}";
    HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("https://您的域名/api/verify.php"))
      .header("Content-Type", "application/json")
      .POST(HttpRequest.BodyPublishers.ofString(json))
      .build();
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body());
  }
}
易语言
.版本 2
.支持库 internet

.子程序 卡密验证
.参数 卡密, 文本型
.参数 设备码, 文本型

.局部变量 url, 文本型
.局部变量 json, 文本型
.局部变量 返回值, 文本型

url = "https://您的域名/api/verify.php"
json = "{\"app_key\":\"您的APPID\",\"code\":\"" + 卡密 + "\",\"device_id\":\"" + 设备码 + "\"}"
返回值 = 网页_访问 (url, 1, json, , , "Content-Type: application/json")
信息框 (返回值, 0, , )
按键精灵
Url = "https://您的域名/api/verify.php"
AppKey = "您的APPID"
Code = "卡密"
DeviceID = "设备机器码"

JsonData = "{\"app_key\":\"" & AppKey & "\",\"code\":\"" & Code & "\",\"device_id\":\"" & DeviceID & "\"}"

Set Http = CreateObject("Msxml2.XMLHTTP")
Http.Open "POST", Url, False
Http.SetRequestHeader "Content-Type", "application/json"
Http.Send JsonData

MsgBox Http.ResponseText
Set Http = Nothing
C# C# / .NET
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program
{
  static async Task Main(string[] args)
  {
    var url = "https://您的域名/api/verify.php";
    var json = "{\"app_key\":\"您的APPID\",\"code\":\"卡密\",\"device_id\":\"设备码\"}";

    using var client = new HttpClient();
    var content = new StringContent(json, Encoding.UTF8, "application/json");
    var response = await client.PostAsync(url, content);
    var result = await response.Content.ReadAsStringAsync();

    Console.WriteLine(result);
  }
}
Go Go
package main

import (
  "bytes"
  "encoding/json"
  "fmt"
  "net/http"
  "io/ioutil"
)

func main() {
  url := "https://您的域名/api/verify.php"
  payload := map[string]string{
    "app_key": "您的APPID",
    "code": "卡密",
    "device_id": "设备码",
  }
  jsonData, _ := json.Marshal(payload)

  resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
  if err != nil {
    fmt.Println("请求失败:", err)
    return
  }
  defer resp.Body.Close()
  body, _ := ioutil.ReadAll(resp.Body)
  fmt.Println(string(body))
}
JS Node.js
const https = require('https');

const data = JSON.stringify({
  app_key: '您的APPID',
  code: '卡密',
  device_id: '设备码'
});

const options = {
  hostname: '您的域名',
  path: '/api/verify.php',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Content-Length': data.length
  }
};

const req = https.request(options, (res) => {
  let body = '';
  res.on('data', (chunk) => body += chunk);
  res.on('end', () => console.log(body));
});

req.on('error', (e) => console.error('请求异常:', e));
req.write(data);
req.end();
P PHP
<?php
$url = 'https://您的域名/api/verify.php';
$data = [
  'app_key' => '您的APPID',
  'code' => '卡密',
  'device_id' => '设备码'
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
  'Content-Type: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
if ($result['code'] === 200) {
  echo "验证成功\n";
} else {
  echo "验证失败: " . $result['msg'] . "\n";
}
Fl Flutter (Dart)
提示:Flutter 项目中需在 pubspec.yaml 添加 http 依赖:http: ^1.2.2
// 完整的卡密授权 API 封装类
import 'dart:convert';
import 'package:http/http.dart' as http;

class KamiApi {
  static const String baseUrl = 'https://您的域名/api';
  static const String appKey = '您的APPID';

  /// 卡密验证接口
  static Future<Map<String, dynamic>> verify(
    String code,
    String deviceId,
    {String? deviceInfo}
  ) async {
    final url = Uri.parse('$baseUrl/verify.php');
    final body = {
      'app_key': appKey,
      'code': code,
      'device_id': deviceId,
      if (deviceInfo != null) 'device_info': deviceInfo,
    };

    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(body),
    );

    return jsonDecode(response.body);
  }

  /// 心跳保活接口
  static Future<Map<String, dynamic>> heartbeat(
    String code,
    String deviceId
  ) async {
    final url = Uri.parse('$baseUrl/heartbeat.php');
    final body = {
      'app_key': appKey,
      'code': code,
      'device_id': deviceId,
    };

    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(body),
    );

    return jsonDecode(response.body);
  }

  /// 获取公告列表
  static Future<Map<String, dynamic>> getNotices() async {
    final url = Uri.parse('$baseUrl/notice.php');
    final body = {'app_key': appKey};

    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(body),
    );

    return jsonDecode(response.body);
  }

  /// 获取最新版本
  static Future<Map<String, dynamic>> getVersion() async {
    final url = Uri.parse('$baseUrl/version.php');
    final body = {'app_key': appKey};

    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(body),
    );

    return jsonDecode(response.body);
  }

  /// 获取版本列表(分页)
  static Future<Map<String, dynamic>> getVersionList({
    int page = 1,
    int pageSize = 20,
  }) async {
    final url = Uri.parse('$baseUrl/version_list.php');
    final body = {
      'app_key': appKey,
      'page': page,
      'pageSize': pageSize,
    };

    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(body),
    );

    return jsonDecode(response.body);
  }

  /// 在线解绑(需要 app_secret)
  static Future<Map<String, dynamic>> unbind(
    String code,
    String deviceId,
    String appSecret
  ) async {
    final url = Uri.parse('$baseUrl/unbind.php');
    final body = {
      'app_key': appKey,
      'app_secret': appSecret,
      'code': code,
      'device_id': deviceId,
    };

    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(body),
    );

    return jsonDecode(response.body);
  }
}

// 使用示例
void main() async {
  // 1. 卡密验证
  final verifyResult = await KamiApi.verify('卡密', '设备码');
  if (verifyResult['code'] == 200) {
    print('验证成功: ${verifyResult['data']}');
  } else {
    print('验证失败: ${verifyResult['msg']}');
  }

  // 2. 获取公告
  final noticeResult = await KamiApi.getNotices();
  if (noticeResult['code'] == 200) {
    final notices = noticeResult['data']['list'] as List;
    for (var notice in notices) {
      print('公告: ${notice['title']}');
    }
  }

  // 3. 获取最新版本
  final versionResult = await KamiApi.getVersion();
  if (versionResult['code'] == 200) {
    final version = versionResult['data'];
    print('最新版本: ${version['version']}');
    if (version['force_update'] == 1) {
      print('强制更新: ${version['download_url']}');
    }
  }
}