API 密钥
Open API RSA 模式使用指南
本文档指导开发者使用 RSA 签名模式调用共绩算力 Open API。RSA 模式在 Token 鉴权基础上增加请求签名,适用于生产环境及对安全性要求较高的集成场景。
1. 概述
1.1 文档说明
本文档指导开发者使用 RSA 签名模式调用共绩算力 Open API。RSA 模式在 Token 鉴权基础上增加请求签名,适用于生产环境及对安全性要求较高的集成场景。
阅读本文档前,建议先了解 Open API 接入指南 中的基础概念与 Token 模式。
1.2 RSA 模式工作原理
客户端 共绩算力 Open API
│ │
│ 1. 本地持有 RSA 私钥(签名) │
│ 2. 平台保存 RSA 公钥(验签) │
│ │
│ 构建待签名字符串 → RSA-SHA256 签名 │
│ ─────────── HTTP Request ──────────────► │
│ Header: token, version, timestamp, │
│ sign_str │
│ Body: JSON 或加密后的 Base64 │
│ │
│ ◄────────── HTTP Response ─────────────── │
│ { code, msg, data } │
1.3 与 Token 模式的区别
| 对比项 | Token 模式 | RSA 签名模式 |
|---|---|---|
| 鉴权方式 | Header 携带 token | Header 携带 token + sign_str |
| 私钥 | 不需要 | 客户端本地持有,用于签名 |
| 公钥 | 不需要 | 上传至平台,用于验签 |
| 请求体加密 | 不支持 | 部分接口支持(见 Apifox 文档) |
| 适用环境 | 开发/测试 | 生产环境 |
1.4 基础信息
| 项目 | 说明 |
|---|---|
| API 基址 | https://openapi.suanli.cn |
| 签名算法 | RSA-SHA256,PKCS#1 v1.5 填充 |
| 签名编码 | Base64 |
| 时间戳 | 毫秒级 Unix 时间戳(13 位) |
| 接口版本(version) | 1.0.0(以各接口文档为准) |
| 密钥管理 | https://console.suanli.cn/settings/key |
2. 快速开始
以下流程可在约 15 分钟内完成 RSA 模式首次调用。
生成 RSA 密钥对
在平台注册公钥
- 登录控制台 → API 密钥管理
- 新建密钥 → 选择「RSA 加验签模式」
- 粘贴
public.pem完整内容 → 生成并保存 API Token 和平台返回的 RSA 公钥
构造签名并发起请求
- 按 第 4 节 规则构建待签名字符串
- 使用私钥 RSA-SHA256 签名并 Base64 编码
- 在 Header 中携带
token、version、timestamp、sign_str
验证响应
确认 HTTP 200 且响应体 code 为 0000。若失败,参见 第 7 节调试与排错。
3. 密钥生成与平台配置
3.1 本地生成密钥对
推荐使用 OpenSSL 生成 2048 位 RSA 密钥对:
openssl genrsa -out private.key 2048
openssl rsa -pubout -in private.key -out public.pem
openssl genrsa -aes256 -out private.key 2048
| 文件 | 用途 | 保管要求 |
|---|---|---|
private.key |
客户端签名 | 严格保密,禁止上传至平台或代码仓库 |
public.pem |
平台验签 | 上传至控制台,可公开 |
3.2 在平台配置公钥
- 访问 https://console.suanli.cn/settings/key
- 点击「新建密钥」→ 选择「RSA 加验签模式」
- 填写备注,粘贴公钥(从
-----BEGIN PUBLIC KEY-----到-----END PUBLIC KEY-----的完整内容) - 点击生成,立即复制并保存平台返回的 API Token 和 RSA 公钥
⚠️ API Token 仅在创建时展示一次。平台仅保存公钥用于验签,私钥由您自行保管。
3.3 密钥格式说明
| 格式名称 | 结构标准 | 编码形式 | 推荐场景 |
|---|---|---|---|
| RsaPkcs8Pem(推荐) | PKCS#8 | PEM(含 BEGIN/END 标签) | 通用场景,文件存储 |
| RsaPkcs1Pem | PKCS#1 | PEM(RSA 专属标签) | 对接传统 PKCS#1 系统 |
| RsaPkcs8Base64 | PKCS#8 | 纯 Base64 字符串 | 代码内嵌、API 传输 |
默认推荐使用 RsaPkcs8Pem 格式。
4. 签名与加密规范
4.1 请求头(RSA 模式)
| Header | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
token |
string | 是 | 平台分配的 API Token | your-api-token-here |
version |
string | 是 | 接口版本号 | 1.0.0 |
timestamp |
string | 是 | 毫秒级 Unix 时间戳 | 1770194570564 |
sign_str |
string | 是 | RSA-SHA256 签名(Base64) | (动态生成) |
Content-Type |
string | 是 | 固定为 application/json | application/json |
4.2 签名流程
- 构建待签名字符串(5 个字段,以换行符
\n连接) - 使用 RSA 私钥 + SHA-256 + PKCS1v15 填充进行签名
- 对签名结果进行 Base64 编码
- 将结果写入 Header
sign_str
4.3 待签名字符串规范
{path}\n{version}\n{timestamp}\n{token}\n{body}
| 字段 | 说明 | 注意事项 |
|---|---|---|
path |
接口路径 | 以 / 开头;GET 请求含 Query 时需将完整 path?query 纳入签名 |
version |
接口版本 | 与 Header version 一致,通常为 1.0.0 |
timestamp |
时间戳 | 与 Header timestamp 一致,毫秒级 |
token |
API Token | 与 Header token 一致 |
body |
请求体 | GET 或无 Body 时为 empty string "";加密接口使用加密后的 Base64 字符串 |
4.4 签名示例
GET 请求(无 Body):
path = /api/deployment/resource/search
version = 1.0.0
timestamp = 1770194570564
token = your-api-token-here
body = (空字符串)
待签名字符串:
/api/deployment/resource/search
1.0.0
1770194570564
your-api-token-here
POST 请求(含 Body):
path = /api/deployment/task/create
version = 1.0.0
timestamp = 1770194570564
token = your-api-token-here
body = {"task_name":"test-task","points":1}
待签名字符串:
/api/deployment/task/create
1.0.0
1770194570564
your-api-token-here
{"task_name":"test-task","points":1}
4.5 请求体加密(可选)
部分接口(如「创建任务」)支持请求体 RSA 加密。是否需要加密以接口文档中「是否需要加密」字段为准。
加密算法规范:
| 项目 | 说明 |
|---|---|
| 加密公钥 | 平台提供的 RSA 公钥(创建密钥时返回),非您上传的公钥 |
| 加密算法 | RSA,PKCS#1 v1.5 填充 |
| 分段长度 | 2048 位密钥每段最多 244 字节(明文) |
| 输出格式 | 各分段密文拼接后,整体 Base64 编码 |
| JSON 序列化 | 紧凑格式,无多余空格:separators=(',', ':') |
4.6 加密流程:
- 将请求体 dict 序列化为紧凑 JSON 字符串
- 按 244 字节分段,使用平台公钥逐段 RSA 加密
- 拼接所有密文块,进行 Base64 编码 → 得到
encrypted_body - 将
encrypted_body作为 HTTP 请求体发送 - 签名时
body字段填入encrypted_body(先加密,后签名)
注意:加密公钥(平台公钥)与签名私钥(您的私钥)是两套不同用途的密钥,请勿混用。
4.7 完整请求流程
┌──────────────────────────────────────────────────┐
│ 1. 准备请求体(JSON 或空) │
│ 2. 如需加密 → RSA 公钥加密 → Base64 │
│ 3. 构建待签名字符串 path\nversion\n...\nbody │
│ 4. RSA-SHA256 签名 → Base64 → sign_str │
│ 5. 设置 Header 并发送 HTTP 请求 │
└──────────────────────────────────────────────────┘
4.8 加密请求签名示例
以「创建任务」接口为例,假设原始 JSON 为:
{"task_name":"test-task","points":1}
加密后 HTTP 请求体变为 Base64 字符串(示意):
xK7g3fP2mN8vQ1wR5tY9zA...(加密后的 Base64,非原始 JSON)
签名时 body 字段使用加密后的 Base64 字符串:
path = /api/deployment/task/create
version = 1.0.0
timestamp = 1770194570564
token = your-api-token-here
body = xK7g3fP2mN8vQ1wR5tY9zA...(加密后的 Base64)
待签名字符串:
/api/deployment/task/create
1.0.0
1770194570564
your-api-token-here
xK7g3fP2mN8vQ1wR5tY9zA...(加密后的 Base64)
5. 请求与响应说明
5.1 HTTP 请求示例
POST /api/deployment/task/detail HTTP/1.1
Host: openapi.suanli.cn
Content-Type: application/json
token: your-api-token-here
version: 1.0.0
timestamp: 1770194570564
sign_str: EowIBAAKCAQEA...(Base64 签名)
{"task_id": 1}
5.2 cURL 示例
curl -X POST "https://openapi.suanli.cn/api/deployment/task/detail" \
-H "Content-Type: application/json" \
-H "token: your-api-token-here" \
-H "version: 1.0.0" \
-H "timestamp: 1770194570564" \
-H "sign_str: YOUR_BASE64_SIGNATURE" \
-d '{"task_id": 1}'
5.3 统一响应格式
{
"code": 0000,
"msg": "success",
"data": { }
}
| 字段 | 类型 | 说明 |
|---|---|---|
code |
number | 0000 表示成功,非 0000 表示失败 |
msg |
string | 结果描述 |
data |
object | 业务数据,结构因接口而异 |
注意:部分历史文档中 code 写作字符串 "0000",请以实际接口返回及 Apifox 文档为准。
5.4 加密请求 HTTP 示例
加密请求的 HTTP Body 为 Base64 字符串(非 JSON 对象),签名同样基于加密后的 Body:
POST /api/deployment/task/create HTTP/1.1
Host: openapi.suanli.cn
Content-Type: application/json
token: your-api-token-here
version: 1.0.0
timestamp: 1770194570564
sign_str: EowIBAAKCAQEA...(Base64 签名)
xK7g3fP2mN8vQ1wR5tY9zA...(加密后的 Base64 请求体)
5.5 加密请求 cURL 示例
curl -X POST "https://openapi.suanli.cn/api/deployment/task/create" \
-H "Content-Type: application/json" \
-H "token: your-api-token-here" \
-H "version: 1.0.0" \
-H "timestamp: 1770194570564" \
-H "sign_str: YOUR_BASE64_SIGNATURE" \
-d "xK7g3fP2mN8vQ1wR5tY9zA..."
6. 代码集成示例
6.1 环境准备
Python:
pip install cryptography requests
Java: JDK 11+(内置 java.net.http 与 java.security)
Go: Go 1.18+(标准库 crypto/rsa)
6.2 核心签名函数(Python)
import base64
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
def gen_sign(private_key, path, version, timestamp, token, body=""):
"""生成 RSA-SHA256 签名"""
sign_content = f"{path}\n{version}\n{timestamp}\n{token}\n{body}"
signature = private_key.sign(
sign_content.encode("utf-8"),
padding.PKCS1v15(),
hashes.SHA256(),
)
return base64.b64encode(signature).decode("utf-8")
6.3 请求体加密函数(Python)
import base64
import json
from cryptography.hazmat.primitives.asymmetric import padding
def encrypt_body(platform_public_key, json_data: dict) -> str:
"""使用平台公钥加密请求体,返回 Base64 字符串"""
json_str = json.dumps(json_data, separators=(",", ":"), ensure_ascii=False)
data_bytes = json_str.encode("utf-8")
encrypted_chunks = []
chunk_size = 244 # RSA-2048 + PKCS1v15 单段最大明文长度
for start in range(0, len(data_bytes), chunk_size):
chunk = data_bytes[start : start + chunk_size]
encrypted_chunks.append(
platform_public_key.encrypt(chunk, padding.PKCS1v15())
)
return base64.b64encode(b"".join(encrypted_chunks)).decode("utf-8")
6.4 GET 请求示例(Python,无加密)
import time
import requests
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
BASE_URL = "https://openapi.suanli.cn"
API_TOKEN = "your-api-token-here"
PRIVATE_KEY_PATH = "./private.key"
API_VERSION = "1.0.0"
with open(PRIVATE_KEY_PATH, "rb") as f:
private_key = serialization.load_pem_private_key(
f.read(), password=None, backend=default_backend()
)
path = "/api/deployment/resource/search"
timestamp = str(int(time.time() * 1000))
body = ""
sign_str = gen_sign(private_key, path, API_VERSION, timestamp, API_TOKEN, body)
headers = {
"Content-Type": "application/json",
"token": API_TOKEN,
"version": API_VERSION,
"timestamp": timestamp,
"sign_str": sign_str,
}
response = requests.get(BASE_URL + path, headers=headers)
print(response.json())
6.5 POST 加密请求示例(Python)
适用于 Apifox 标注「是否需要加密 = 是」的接口(如创建任务)。
import time
import requests
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
BASE_URL = "https://openapi.suanli.cn"
API_TOKEN = "your-api-token-here"
PRIVATE_KEY_PATH = "./private.key" # 您的私钥,用于签名
PLATFORM_PUBLIC_KEY_PATH = "./platform_pub.pem" # 平台公钥,用于加密
API_VERSION = "1.0.0"
with open(PRIVATE_KEY_PATH, "rb") as f:
private_key = serialization.load_pem_private_key(
f.read(), password=None, backend=default_backend()
)
with open(PLATFORM_PUBLIC_KEY_PATH, "rb") as f:
platform_public_key = serialization.load_pem_public_key(
f.read(), backend=default_backend()
)
path = "/api/storage/encrypt/check"
timestamp = str(int(time.time() * 1000))
json_data = {
"storage_name": "demo-oss",
"juicefs_region_id": 3,
"bucket": "demo-bucket",
"dir": "dataset",
"endpoint": "oss-cn-beijing.aliyuncs.com",
"access_key": "access-key",
"secret_key": "secret-key"
}
encrypted_body = encrypt_body(platform_public_key, json_data)
sign_str = gen_sign(
private_key, path, API_VERSION, timestamp, API_TOKEN, encrypted_body
)
headers = {
"Content-Type": "application/json",
"token": API_TOKEN,
"version": API_VERSION,
"timestamp": timestamp,
"sign_str": sign_str,
}
response = requests.post(
BASE_URL + path,
headers=headers,
data=encrypted_body, # 发送加密后的 Base64 字符串
)
print(response.json())
6.6 POST 加密请求示例(Java)
import javax.crypto.Cipher;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class EncryptedPostExample {
private static final String BASE_URL = "https://openapi.suanli.cn";
private static final String API_TOKEN = "your-api-token-here";
private static final String API_VERSION = "1.0.0";
private static final int CHUNK_SIZE = 244;
public static void main(String[] args) throws Exception {
PrivateKey privateKey = loadPrivateKey("./private.key");
PublicKey platformPublicKey = loadPublicKey("./platform_pub.pem");
String path = "/api/deployment/task/create";
String timestamp = String.valueOf(System.currentTimeMillis());
String json = "{\"task_name\":\"test-task\",\"points\":1}";
// 1. 加密
String encryptedBody = encryptBody(platformPublicKey, json);
// 2. 签名(基于加密后的 body)
String signStr = genSign(privateKey, path, API_VERSION, timestamp, API_TOKEN, encryptedBody);
// 3. 发送
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(BASE_URL + path))
.header("Content-Type", "application/json")
.header("token", API_TOKEN)
.header("version", API_VERSION)
.header("timestamp", timestamp)
.header("sign_str", signStr)
.POST(HttpRequest.BodyPublishers.ofString(encryptedBody))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
static String encryptBody(PublicKey publicKey, String plainText) throws Exception {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] data = plainText.getBytes(StandardCharsets.UTF_8);
java.io.ByteArrayOutputStream output = new java.io.ByteArrayOutputStream();
for (int i = 0; i < data.length; i += CHUNK_SIZE) {
int end = Math.min(i + CHUNK_SIZE, data.length);
output.write(cipher.doFinal(data, i, end - i));
}
return Base64.getEncoder().encodeToString(output.toByteArray());
}
static String genSign(PrivateKey privateKey, String path, String version,
String timestamp, String token, String body) throws Exception {
String content = path + "\n" + version + "\n" + timestamp + "\n" + token + "\n" + body;
Signature sig = Signature.getInstance("SHA256withRSA");
sig.initSign(privateKey);
sig.update(content.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(sig.sign());
}
static PrivateKey loadPrivateKey(String path) throws Exception {
String pem = Files.readString(Path.of(path))
.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(pem);
return KeyFactory.getInstance("RSA")
.generatePrivate(new PKCS8EncodedKeySpec(keyBytes));
}
static PublicKey loadPublicKey(String path) throws Exception {
String pem = Files.readString(Path.of(path))
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s", "");
byte[] keyBytes = Base64.getDecoder().decode(pem);
return KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(keyBytes));
}
}
Java 加密注意:分段加密后拼接所有密文字节块,再整体 Base64 编码,与 Python 示例逻辑一致。
6.7 POST 加密请求示例(Go)
package main
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"io"
"net/http"
"os"
"strings"
"time"
)
const (
baseURL = "https://openapi.suanli.cn"
apiToken = "your-api-token-here"
apiVersion = "1.0.0"
chunkSize = 244
)
func main() {
privateKey := loadPrivateKey("./private.key")
platformPublicKey := loadPublicKey("./platform_pub.pem")
path := "/api/deployment/task/create"
timestamp := fmt.Sprintf("%d", time.Now().UnixMilli())
jsonData := `{"task_name":"test-task","points":1}`
// 1. 加密
encryptedBody := encryptBody(platformPublicKey, jsonData)
// 2. 签名
signStr := genSign(privateKey, path, apiVersion, timestamp, apiToken, encryptedBody)
// 3. 发送
req, _ := http.NewRequest(http.MethodPost, baseURL+path, strings.NewReader(encryptedBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("token", apiToken)
req.Header.Set("version", apiVersion)
req.Header.Set("timestamp", timestamp)
req.Header.Set("sign_str", signStr)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
}
func encryptBody(pub *rsa.PublicKey, plain string) string {
data := []byte(plain)
var encrypted []byte
for i := 0; i < len(data); i += chunkSize {
end := i + chunkSize
if end > len(data) {
end = len(data)
}
chunk, _ := rsa.EncryptPKCS1v15(rand.Reader, pub, data[i:end])
encrypted = append(encrypted, chunk...)
}
return base64.StdEncoding.EncodeToString(encrypted)
}
func genSign(priv *rsa.PrivateKey, path, version, timestamp, token, body string) string {
content := path + "\n" + version + "\n" + timestamp + "\n" + token + "\n" + body
sig, _ := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, []byte(content))
return base64.StdEncoding.EncodeToString(sig)
}
func loadPrivateKey(path string) *rsa.PrivateKey {
data, _ := os.ReadFile(path)
block, _ := pem.Decode(data)
key, _ := x509.ParsePKCS8PrivateKey(block.Bytes)
return key.(*rsa.PrivateKey)
}
func loadPublicKey(path string) *rsa.PublicKey {
data, _ := os.ReadFile(path)
block, _ := pem.Decode(data)
pub, _ := x509.ParsePKIXPublicKey(block.Bytes)
return pub.(*rsa.PublicKey)
}
Go 签名注意:genSign 需 import "crypto" 包;平台签名算法为 RSA-SHA256,对原始待签名字符串进行 SHA-256 哈希后签名。
7. 调试与排错
7.1 调试 Checklist
| 检查项 | 正确做法 | 常见错误 |
|---|---|---|
| timestamp | 毫秒级 13 位数字 | 使用秒级 10 位时间戳 |
| version | "1.0.0" 字符串 |
使用整数 1 或平台版本 v1.2.0 |
| path | 以 / 开头,GET 含 query 时一并签名 |
遗漏 query 参数 |
| body | 无 Body 时用 "",非 null/{} |
GET 请求错误填入 {} |
| 签名顺序 | path → version → timestamp → token → body | 字段顺序错误或分隔符非 \n |
| 加密顺序 | 先加密 body,再用加密结果签名 | 先签名后加密 |
| 服务器时间 | 与 NTP 同步,偏差 < 5 分钟 | 本地时间严重偏移 |
7.2 常见错误
签名验证失败
打印待签名字符串逐字段比对;确认 body 与最终发送内容一致;确认私钥与平台公钥为同一密钥对。
私钥加载失败
检查 PEM 格式与文件路径;如有密码保护需传入 password 参数。
时间戳过期
同步系统时间;每次请求重新生成 timestamp,勿复用旧值。
加密后签名仍失败
确认 sign 使用的是加密后的 Base64 字符串,而非原始 JSON。
7.3 调试代码片段
sign_content = f"{uri}\n{version}\n{timestamp}\n{token}\n{body}"
print("--- BEGIN STRING TO SIGN ---")
print(repr(sign_content))
print("--- END STRING TO SIGN ---")
print(f"sign_str: {sign_str}")
8. 安全最佳实践
| 实践 | 说明 |
|---|---|
| 私钥隔离 | 私钥仅存于安全存储(KMS/密钥管理服务),禁止写入代码仓库 |
| 环境分离 | 开发、测试、生产使用独立密钥对 |
| 最小暴露 | 文档与示例一律使用占位符 Token,禁止泄露真实密钥 |
| 定期轮换 | 建议每 90 天轮换密钥对,旧密钥及时在控制台吊销 |
| 传输安全 | 仅通过 HTTPS 调用 API |
| 权限控制 | 团队场景下仅主账号/管理员可管理密钥 |
9. 常见问题
Q1:RSA 模式是否仍需要 token?
Q1:RSA 模式是否仍需要 token?
需要。RSA 模式在 token 鉴权基础上增加 sign_str 签名,二者缺一不可。
Q2:GET 请求的 Query 参数是否参与签名?
Q2:GET 请求的 Query 参数是否参与签名?
是。GET 请求应将 path?key=value 完整路径作为 path 字段参与签名,顺序与编码需与实际请求 URL 一致。
Q3:Body 为空时签名如何处理?
Q3:Body 为空时签名如何处理?
body 字段使用空字符串 "",不要使用 null、{} 或空格。
Q4:加密用哪把公钥?
Q4:加密用哪把公钥?
使用平台提供的公钥加密请求体;您上传的公钥仅用于平台验证您的签名。
Q5:能否在 Token 模式和 RSA 模式之间切换?
Q5:能否在 Token 模式和 RSA 模式之间切换?
不能混用。创建密钥时选定的模式决定了调用方式,需使用对应密钥重新集成。
Q6:私钥丢失怎么办?
Q6:私钥丢失怎么办?
无法恢复。需重新生成密钥对、在控制台创建新密钥,并更新所有集成方配置。
10. 相关文档
| 文档 | 说明 | 链接 |
|---|---|---|
| Open API 接入指南 | 概述、Token 模式、快速开始 | Open API 接入指南 |
| Open API 接口文档 | 接口参数、是否加密/加签 | https://s.apifox.cn/6aa360d3-d8f2-471e-b841-3a35c33a7b7c |
| API 密钥管理 | 控制台密钥创建与管理 | https://console.suanli.cn/settings/key |
| 团队账号 | 密钥管理权限说明 | 团队账号 |