API DOCUMENTATION
适用于自建 CMS、电商后台、SaaS 等任意网站。通过 API Key 在您的服务端调用 ImgToC 上传与管理接口,将返回的外链嵌入商品详情、文章编辑器等业务页面。
浏览器只请求您自己的后端;后端持有 API Key,依次调用「初始化 → 分片 → 合并」,再把 external_link 返回给前端。切勿在前端 JavaScript 中硬编码 API Key。
Discuz 图床对接插件,下载后按包内说明安装,并在插件中配置本站的 API 密钥与域名白名单(与用户中心「API 接入」一致)。
http://your-domain.com/api
所有API请求都基于此地址,通过 act 参数指定具体操作。
application/json 或 multipart/form-data所有API响应均为JSON格式:
{
"success": true,
"data": { ... },
"message": "操作成功"
}
错误响应:
{
"success": false,
"error_code": 400,
"message": "错误信息"
}
200 - 请求成功400 - 请求参数错误401 - 未登录或登录已过期403 - 无权限访问404 - 资源不存在500 - 服务器内部错误通过网页登录后,系统会自动设置Cookie,API请求会自动携带Cookie进行身份验证。
在用户中心「API 接入」中生成密钥并配置域名白名单,请求头携带:
X-API-Key: YOUR_API_KEY
Authorization: Bearer YOUR_API_KEY
docs/API_THIRD_PARTY_INTEGRATION.md。
| 步骤 | REST 路径(推荐) | 兼容路径 | 方法 |
|---|---|---|---|
| 秒传检查 | POST /api/check |
— | POST |
| 初始化 | POST /api/init |
/api?act=upload-init |
POST |
| 上传分片 | POST /api/upload/chunk |
/api?act=upload-chunk |
POST |
| 合并 | POST /api/merge |
/api?act=upload-merge |
POST |
请求头:X-API-Key 或 Authorization: Bearer。合并成功后使用 data.external_link 作为外链地址。
以下接口路径含 api-discuz 为历史命名,第三方独立站可直接使用,无需安装 Discuz 插件。
| 功能 | 接口 | 方法 |
|---|---|---|
| 文件列表 | /api?mod=file&act=api-discuz-list |
GET |
| 子目录列表 | /api?mod=file&act=api-discuz-folders |
GET |
| 删除文件 | /api?mod=file&act=api-discuz-delete |
POST |
| 批量删除 | /api?mod=file&act=api-discuz-batch-delete |
POST |
{域名}/api?act=file-download&id={file_id}{域名}/directlink/{detail_slug}.扩展名(扩展名仅美化,兼容无后缀旧链){域名}/api?act=file-thumbnail&id={file_id}&size=200<img src="https://imgtoc.com/api?act=file-download&id=FILE_ID" alt="">

[img]https://imgtoc.com/api?act=file-download&id=FILE_ID[/img]
// 标准库:初始化 → 分片 → 合并
init, _ := apiJSON("POST", "/api/init", map[string]interface{}{
"filename": filename, "size": size, "folder_id": 0,
})
taskID := init.Data["task_id"].(string)
// multipart 上传:task_id、chunk_index、chunk
uploadChunk(taskID, index, chunkData)
merged, _ := apiJSON("POST", "/api/merge", map[string]string{"task_id": taskID})
url := merged.Data["external_link"].(string)
// 服务端代理:初始化 → 分片 → 合并
$headers = ['X-API-Key: ' . $apiKey, 'Content-Type: application/json'];
$init = json_decode(file_get_contents($base . '/api/init', false, stream_context_create([
'http' => ['method' => 'POST', 'header' => implode("\r\n", $headers),
'content' => json_encode(['filename' => 'a.jpg', 'size' => $size])]
])), true);
// 分片 POST /api/upload/chunk(multipart: task_id, chunk_index, chunk)
// 合并 POST /api/merge {"task_id":"..."} → 使用 data.external_link
接口:POST /api/check
说明:检查文件是否已存在,支持秒传功能。
{
"hash": "文件MD5哈希值",
"filename": "文件名",
"size": 文件大小(字节),
"folder_id": 文件夹ID(可选)
}
{
"success": true,
"data": {
"exists": true,
"skip_upload": true,
"file_id": "文件ID"
}
}
接口:POST /api?act=upload-init
说明:创建上传任务,获取任务ID和上传配置。
{
"filename": "文件名",
"size": 文件大小(字节),
"hash": "文件MD5哈希值(可选)",
"folder_id": 文件夹ID(可选)
}
{
"success": true,
"data": {
"task_id": "任务ID",
"file_id": "文件ID",
"chunk_size": 2097152,
"upload_mode": "direct",
"upload_urls": [
{
"chunk_index": 0,
"upload_url": "预签名URL",
"expires_at": 过期时间戳
}
]
}
}
接口:POST /api?act=upload-chunk
说明:通过服务器代理上传分片(适用于本地存储)。
multipart/form-data
task_id - 任务IDchunk_index - 分片索引(从0开始)chunk - 分片文件数据接口:GET /api?act=upload-chunk-url
说明:获取云存储的预签名上传URL,客户端直接上传到云存储。
task_id - 任务IDchunk_index - 分片索引(从0开始)接口:POST /api?act=upload-merge
说明:所有分片上传完成后,合并文件(本地存储需要,云存储自动合并)。
{
"task_id": "任务ID"
}
接口:GET /api/task/list
说明:查询上传任务列表和进度。
接口:GET /api?act=file-download
参数:id - 文件ID
说明:下载文件,支持断点续传。
接口:GET /api?act=file-thumbnail
参数:
id - 文件IDsize - 缩略图尺寸(200或800,默认200)接口:GET /api?act=file-compressed
参数:id - 文件ID
说明:获取压缩后的图片,用于预览。
接口:GET /directlink/短ID.扩展名(扩展名可选,仅美化 URL)
说明:通过短ID直接访问文件,无需登录。
接口:GET /api?mod=file&act=list
参数:
page - 页码(默认1)page_size - 每页数量(默认20)folder_id - 文件夹ID(可选)keyword - 搜索关键词(可选)type - 文件类型(可选)接口:GET /api?mod=file&act=info
参数:file_id - 文件ID
接口:POST /api?mod=file&act=rename
参数:
file_id - 文件IDnew_filename - 新文件名接口:POST /api?mod=file&act=delete
参数:file_id - 文件ID
接口:GET /api?mod=file&act=external-link
参数:file_id - 文件ID
说明:获取文件的各种外链格式(Markdown、UBB、HTML等)。
接口:GET /api?mod=folder&act=list
参数:parent_id - 父文件夹ID(可选,默认0)
接口:POST /api?mod=folder&act=create
参数:
folder_name - 文件夹名称parent_id - 父文件夹ID(可选,默认0)description - 描述(可选)接口:POST /api?mod=folder&act=rename
参数:
folder_id - 文件夹ID(可选)new_folder_name - 新文件夹名称接口:POST /api?mod=folder&act=delete
参数:folder_id - 文件夹ID(可选)
接口:GET /api?mod=user&act=info
说明:获取当前登录用户的基本信息。
接口:GET /api?mod=user&act=stats
说明:获取用户的存储使用情况、文件数量等统计信息。
接口:POST /api?mod=user&act=update
参数:
username - 用户名(可选)email - 邮箱(可选)avatar - 头像URL(可选)接口:GET /api?act=vip-plans-public
说明:获取所有可用的VIP方案信息(公开接口,无需登录)。
接口:GET /api?act=vip-plan-permissions-public
说明:获取各VIP等级的权限对比(公开接口,无需登录)。
接口:POST /api?act=vip-order-create
参数:
plan_id - VIP方案IDsku_id - SKU ID(可选)payment_method - 支付方式(alipay/wxpay)接口:GET /api?act=vip-order-status
参数:order_id - 订单ID
// 初始化上传
$.ajax({
url: '/api?act=upload-init',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify({
filename: 'example.jpg',
size: 1024000,
hash: 'md5_hash_value'
}),
success: function(response) {
if (response.success) {
var taskId = response.data.task_id;
// 开始上传分片
uploadChunks(taskId, response.data.upload_urls);
}
}
});
// 上传分片
function uploadChunks(taskId, uploadUrls) {
uploadUrls.forEach(function(item, index) {
// 使用预签名URL直接上传到云存储
$.ajax({
url: item.upload_url,
method: 'PUT',
contentType: 'application/octet-stream',
data: chunkData,
success: function() {
// 分片上传成功
}
});
});
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"mime/multipart"
"net/http"
"os"
)
const baseURL = "https://imgtoc.com"
const apiKey = "YOUR_API_KEY" // 仅从服务端环境变量读取
func main() {
data, _ := os.ReadFile("example.jpg")
// 1) 初始化
initBody, _ := json.Marshal(map[string]interface{}{
"filename": "example.jpg", "size": len(data), "folder_id": 0,
})
req, _ := http.NewRequest("POST", baseURL+"/api/init", bytes.NewReader(initBody))
req.Header.Set("X-API-Key", apiKey)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
var init struct {
Success bool `json:"success"`
Data struct {
TaskID string `json:"task_id"`
ChunkSize int `json:"chunk_size"`
InstantUpload bool `json:"instant_upload"`
ExternalLink string `json:"external_link"`
} `json:"data"`
}
json.NewDecoder(resp.Body).Decode(&init)
resp.Body.Close()
if init.Data.InstantUpload {
fmt.Println(init.Data.ExternalLink)
return
}
// 2) 分片上传(字段名必须为 chunk)
taskID := init.Data.TaskID
chunkSize := init.Data.ChunkSize
if chunkSize <= 0 { chunkSize = len(data) }
for i, off := 0, 0; off < len(data); i, off = i+1, off+chunkSize {
end := off + chunkSize
if end > len(data) { end = len(data) }
var buf bytes.Buffer
w := multipart.NewWriter(&buf)
w.WriteField("task_id", taskID)
w.WriteField("chunk_index", fmt.Sprintf("%d", i))
part, _ := w.CreateFormFile("chunk", "chunk")
part.Write(data[off:end])
w.Close()
cr, _ := http.NewRequest("POST", baseURL+"/api/upload/chunk", &buf)
cr.Header.Set("X-API-Key", apiKey)
cr.Header.Set("Content-Type", w.FormDataContentType())
http.DefaultClient.Do(cr)
}
// 3) 合并,取外链
mergeBody, _ := json.Marshal(map[string]string{"task_id": taskID})
mr, _ := http.NewRequest("POST", baseURL+"/api/merge", bytes.NewReader(mergeBody))
mr.Header.Set("X-API-Key", apiKey)
mr.Header.Set("Content-Type", "application/json")
mresp, _ := http.DefaultClient.Do(mr)
var merged struct {
Data struct{ ExternalLink string `json:"external_link"` } `json:"data"`
}
json.NewDecoder(mresp.Body).Decode(&merged)
fmt.Println(merged.Data.ExternalLink)
}
import requests
# 初始化上传
response = requests.post(
'http://your-domain.com/api?act=upload-init',
json={
'filename': 'example.jpg',
'size': 1024000,
'hash': 'md5_hash_value'
},
cookies={'session': 'your_session_cookie'}
)
if response.json()['success']:
task_data = response.json()['data']
task_id = task_data['task_id']
# 上传分片
for chunk_info in task_data['upload_urls']:
chunk_index = chunk_info['chunk_index']
upload_url = chunk_info['upload_url']
# 读取分片数据
with open(f'chunk_{chunk_index}', 'rb') as f:
chunk_data = f.read()
# 上传到云存储
requests.put(upload_url, data=chunk_data)
| 错误码 | 说明 |
|---|---|
| 400 | 请求参数错误 |
| 401 | 未登录或登录已过期 |
| 403 | 无权限访问 |
| 404 | 资源不存在 |
| 413 | 文件大小超出限制 |
| 500 | 服务器内部错误 |