概览
所有接口都挂在 /api/open/v1 下,请求体和响应体都是 JSON(UTF-8)。服务端按下面的顺序处理每个请求,任何一步被拒绝都会直接返回对应的状态码:
- 01凭证鉴权401 / 403
- 02QPM 限速429
- 03月度配额429 · 仅控制面写操作
- 04Scope 校验403
- 05业务处理4xx / 5xx
* 月度配额只对控制面的写操作生效。GET 查询和数据面接口(流式追加行)不计配额,但同样受凭证级 QPM 限速。
快速开始
下面的例子演示一条最短的接入链路:选打印机 → 取模板 → 提交任务。示例使用 bash 数组 AUTH 复用鉴权头。
# 1. 在控制台「开放平台 → API 凭证」创建凭证,并勾选所需的 Scope
export VARILABEL_APP_ID="<your-app-id>"
export VARILABEL_APP_SECRET="<your-app-secret>"
BASE="https://api.varilabel.com/api/open/v1"
AUTH=(-H "X-App-Id: $VARILABEL_APP_ID" -H "X-App-Secret: $VARILABEL_APP_SECRET")
# 2. 查询打印机,记下 items[].code(提交任务用的是 printer_code,不是 id)
curl -sS "$BASE/printers" "${AUTH[@]}"
# 可以再调用 /printers/for-print,按 id 确认这台打印机 online=true
# 3. 按槽位编码确认模板条目可以打印(share_code 可以在控制台的企业模板详情中查看)
curl -sS "$BASE/template-shares/by-code/S-7K2M9Q" "${AUTH[@]}"
# → { "share_id": "...", "release_id": "...", "can_print": true, ... }
# 4. 提交打印任务(inline 模式:数据行直接放在请求体里,最多 200 行)
curl -sS -X POST "$BASE/print-jobs" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d '{
"template_code": "S-7K2M9Q",
"printer_code": "<printer-code>",
"upload_mode": "inline",
"params": { "copies": 1 },
"rows": [
{ "data": { "sku": "A001", "barcode": "690123456789012345" } }
]
}'
# → 201 { "id": "<job-id>", "job_no": "<job-no>", "status": "pending", ... }
# 5. 轮询任务状态,直到进入终态(completed / partial / failed / cancelled)
JOB_ID="<job-id>"
curl -sS "$BASE/print-jobs/$JOB_ID" "${AUTH[@]}"鉴权与 Scope
请在控制台的「开放平台 → API 凭证」中创建凭证,拿到 AppID 和 AppSecret。每个请求都要通过请求头带上它们(推荐):
GET /api/open/v1/template-groups HTTP/1.1
Host: api.varilabel.com
X-App-Id: <your-app-id>
X-App-Secret: <your-app-secret>也可以使用 HTTP Basic Auth,方便 curl 等标准工具调用:
# 等价写法:HTTP Basic Auth(用户名 = AppID,密码 = AppSecret)
curl -sS -u "$VARILABEL_APP_ID:$VARILABEL_APP_SECRET" "https://api.varilabel.com/api/open/v1/template-groups"- 妥善保管 AppSecret。只能在服务端使用,不要放进前端页面、App 安装包或代码仓库。
- 鉴权失败统一返回 401,不区分「AppID 不存在 / 密钥错误 / 凭证停用或过期 / IP 不在白名单」。排查时请把响应头
X-Request-Id提供给我们,我们可以查到具体原因。 - 轮换密钥:重置密钥后,旧密钥在灰度期内仍然可用,但响应会带上
X-Credential-Deprecated: true和X-Credential-Expires-At(旧密钥失效时间)。建议监控这两个响应头,在旧密钥失效前完成替换。
Scope
每个接口都需要对应的 Scope。创建凭证时请只勾选业务确实需要的 Scope(最小权限原则)。缺少 Scope 的请求会返回403。除 Scope 外,模板等资源还受资源级授权约束:凭证只能看到被授权的分组和条目。
| Scope | 说明 | 涉及接口数 |
|---|---|---|
print_job:read | 读取打印任务、上传进度 | 4 |
print_job:create | 提交 / 重试打印任务、流式上传与封口 | 4 |
print_job:cancel | 取消打印任务 | 1 |
template:read | 读取模板条目、发布记录、模板内容与分组 | 7 |
printer:read | 读取打印机列表与详情 | 3 |
storage:read | 查看存储用量、文件列表与下载地址 | 4 |
storage:write | 上传、确认与删除文件 | 3 |
数据约定
- ID
- 所有 ID 都是 64 位整数,在 JSON 里以字符串返回(如
"1938475610293847552")。请按字符串存储,不要转成 JavaScript number,否则会丢失精度。 - 请求中的 ID
- 请求体里的 ID 字段(如
template_release_id、source_file_id)同样必须传字符串。传成 JSON 数字会返回400 invalid_field_type。 - 请求体
- 必须是恰好一个 JSON 对象。未定义的字段会被静默忽略,不会报错,请对照接口参考核对字段名(例如提交任务用
template_code,不是 share_code)。 - 打印数据中的数字
- 条码、批号、编码等请以字符串传递(如
"0690123456789")。JSON 数字无法表达前导 0,也容易在你自己的系统里被转成浮点数而丢失精度。 - 时间
- RFC 3339 格式,带时区偏移,如
2025-01-01T10:00:00+08:00。 - 分页
- Query 参数
page(从 1 开始)和page_size(默认 20,最大100,超出会按最大值处理)。响应统一为{ items, total, page, page_size }。 - 尺寸
width/height是数字,单位由size_unit决定:mm、cm、in、px。其中 px 指 CSS 像素(1px = 1/96 英寸),不是打印机点(dot)。- 可空字段
- 没有值的字段有两种表现:模板接口返回
null,打印机和打印任务接口直接省略这个字段。各接口的数据结构里都有标注,请两种情况都做好判断。 - 临时地址
- 封面图、文件下载地址都是带签名的临时 URL,附带
expires_at。请在过期前重新拉取,不要长期保存 URL。
限速与配额
凭证级 QPM 限速
按凭证计算每分钟请求数,默认 60 次/分钟,企业版可以调高。所有接口(包括 GET 和数据面)都受限速约束。被限速拒绝的请求不消耗月度配额。
月度调用配额
只有控制面的写操作(POST / DELETE)消耗套餐的月度配额,每次 1 次。GET 查询(包括轮询任务状态)和流式追加行/rows 不计配额。配额按自然月重置。
| 请求类型 | 月度配额 |
|---|---|
| GET 查询(列表、详情、进度、模板内容) | 不计 |
| POST / DELETE(提交、重试、取消、封口、上传、删除) | 每次 1 次 |
POST /print-jobs/:id/rows | 不计 |
| 被 QPM 限速拒绝的请求 | 不计 |
| 写请求被 Scope 校验等业务规则拒绝(4xx) | 计 1 次 |
| 服务端返回 5xx 的请求 | 自动退还 |
* Scope 校验在月度配额之后执行,所以缺少 Scope 的写请求也会消耗 1 次配额。打印任务另外还有按月计算的标签额度和任务数额度,用尽时返回 403(label_quota_exceeded / print_quota_exceeded),见打印任务对接指南。
响应头
X-RateLimit-Limit:当前窗口的请求上限X-RateLimit-Remaining:当前窗口的剩余次数X-RateLimit-Reset:窗口重置时间(Unix 秒)Retry-After:被拒绝时建议等待的秒数X-RateLimit-Mode: degraded:限速服务处于降级模式,计数精度较低,限额不变X-Quota-Limit:套餐的月度配额上限(不限量的套餐不返回)X-Quota-Period:本次请求计入的月份(只在计费请求上返回)
超过 QPM 限速
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1735689600
Retry-After: 42
{
"code": "TOO_MANY_REQUESTS",
"message": "请求频率超过凭证限制,请稍后重试"
}月度配额用尽
同样返回 429,但错误码是 API_QUOTA_EXCEEDED。这种情况重试永远不会成功,请升级套餐或等到 reset_at。
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-Quota-Limit: 1000
X-Quota-Period: 2025-01
Retry-After: 1209600
{
"code": "API_QUOTA_EXCEEDED",
"message": "本月 API 调用配额已用尽,请升级套餐或等待下月重置",
"data": {
"month": "2025-01",
"limit": 1000,
"reset_at": "2025-02-01T00:00:00+08:00"
}
}建议:根据 code 区分两种 429,只对TOO_MANY_REQUESTS 按Retry-After 退避重试;批量场景请自己控制并发,不要无限重试。
错误处理
出错时返回非 2xx 状态码,响应体包含机器可读的 code 和可读的 message,部分错误还会带上data:
{
"code": "not_found",
"message": "template share not found"
}请用「HTTP 状态码 + code」做判断,code 按完整字符串精确匹配。message 只供人阅读,内容可能调整。
| 状态码 | code | 含义 | 建议处理 |
|---|---|---|---|
| 400 | invalid_parameterinvalid_requestinvalid_jsoninvalid_field_type | 请求参数或请求体不合法。打印任务接口还会返回更具体的 code(如 upload_mode_required、row_no_mixed),见各接口说明 | 修正后再调用,不要自动重试 |
| 401 | UNAUTHORIZED | 凭证缺失或无效:AppID 不存在、密钥错误、凭证已停用或过期、IP 不在白名单(统一返回,不区分具体原因) | 检查凭证配置;联系支持时提供响应头 X-Request-Id |
| 403 | FORBIDDENforbiddenpermission_denied | 工作空间已禁用、当前套餐不含 OpenAPI、凭证缺少接口所需的 Scope,或无权访问该资源 | 按 message 处理,不要重试 |
| 403 | label_quota_exceededprint_quota_exceeded | 本月标签额度或打印任务数额度用尽。它们和 API 调用配额是不同的额度 | 重试不会成功:升级套餐,或等到下个月 |
| 404 | not_found | 资源不存在、不属于当前企业,或当前凭证无权查看(不区分) | 检查 ID 和凭证授权范围 |
| 409 | share_not_listednot_retryablerows_mismatch… | 资源状态冲突 | 见各接口的错误说明 |
| 410 | endpoint_removeddata_purged | 接口已下线,或打印数据已过保留期被清理 | 按迁移指引改用新接口;数据已清理的任务只能重新提交 |
| 413 | payload_too_largeinline_payload_too_large | 请求体过大 | 缩小单次请求;大批量数据请用 streaming 模式 |
| 429 | TOO_MANY_REQUESTS | 触发凭证级 QPM 限速 | 按 Retry-After 退避后重试 |
| 429 | API_QUOTA_EXCEEDED | 本月调用配额已用尽 | 重试不会成功:升级套餐,或等到 data.reset_at |
| 502 | data_write_failed | 打印任务已创建,但数据行写入失败;任务已被标记失败并清理 | 直接重新提交,不会重复打印 |
| 5xx | internal_error | 服务端异常 | GET 请求可以指数退避重试;POST /print-jobs 不幂等,重试前先查询确认任务是否已经创建。这类请求不消耗月度配额 |
模板对接指南
对外接口只开放企业模板库。理解下面四个概念,就能理解所有模板接口:
分组group
企业模板库的分类。可以按分组给凭证授权。
条目share
某个模板在某个分组里的固定槽位。share_id 和 share_code 在条目的整个生命周期内不变。同一模板发布到两个分组,就是两个条目。
发布记录release
条目的一次正式生效(审核通过、免审直发或管理员回滚)。它固定了版本以及名称、尺寸等快照,只增不改。
内容content
发布记录对应的模板设计内容,附带 SHA-256 内容指纹 content_hash。
release_id 才会变化。产线不会因为作者的一次误操作而受影响。
推荐流程
- 1
授权
在控制台把模板发布到分组,给凭证授予该分组(或单个条目)的访问权限,并勾选 template:read。
- 2
保存 share_code
在业务系统的配置里保存条目的 share_code(S-XXXXXX),不要保存模板 ID。
- 3
定位条目
运行时调用 GET /template-shares/by-code/:shareCode,拿到 share_id、当前 release_id 和 can_print。
- 4
获取内容
调用 GET /template-shares/:shareId/content。同一 release_id 的内容永远不变,可以按 release_id 或 content_hash 缓存。
- 5
历史补打
先用 GET /template-shares/:shareId/releases 找到当时的发布记录,再调用 content?release_id= 取当时的内容。
export VARILABEL_APP_ID="<your-app-id>"
export VARILABEL_APP_SECRET="<your-app-secret>"
BASE="https://api.varilabel.com/api/open/v1"
AUTH=(-H "X-App-Id: $VARILABEL_APP_ID" -H "X-App-Secret: $VARILABEL_APP_SECRET")
# ① 按槽位编码定位条目,拿到 share_id 与当前 release_id
curl -sS "$BASE/template-shares/by-code/S-7K2M9Q" "${AUTH[@]}"
SHARE_ID="<share-id>"
# ② 获取当前生效的模板内容(同一 release_id 的内容不会变化,可以缓存)
curl -sS "$BASE/template-shares/$SHARE_ID/content" "${AUTH[@]}"
# ③ 历史补打:先查发布记录,再按 release_id 取当时的内容
curl -sS "$BASE/template-shares/$SHARE_ID/releases?page=1&page_size=20" "${AUTH[@]}"
RELEASE_ID="<release-id>"
curl -sS "$BASE/template-shares/$SHARE_ID/content?release_id=$RELEASE_ID" "${AUTH[@]}"- • 模板接口都是 GET,不消耗月度配额,但受 QPM 限速。建议按 release_id 缓存内容,不要每次打印前都重新拉取。
- • 同一模板发布到多个分组时是多个条目,版本可能不同。请用 share_id 或 share_code 区分,不要用模板名称。
- • 条目下架后,按 share_id / share_code 查询都会返回 404。重新上架后,原来的 share_id 和 share_code 会恢复可用。
打印任务对接指南
提交打印任务只需要两个对外编码,不需要任何内部 ID:
- •
template_code:企业模板条目的槽位编码(即 share_code,S-XXXXXX)。只能打印企业模板库里已生效的发布记录,不能打印个人模板(L- 编码)或草稿。不传template_release_id时使用当前生效版本。 - •
printer_code:打印机的 code(见 GET /printers)。目标终端由打印机的绑定关系自动确定,不需要传。
上传模式
upload_mode 必填,没有默认值。模式和 rows / rows_expected 的组合不匹配时直接返回 400。
| upload_mode | 适用场景 | rows | rows_expected | 封口 |
|---|---|---|---|---|
none | 纯常量标签(模板里没有变量),只按份数打印 | 不传 | 不传或 0 | 不需要,提交时自动封口 |
inline | 不超过 200 行,且序列化后不超过 512 KiB | 必填,放在 rows 里 | 可省略;填写时必须等于 rows 的长度 | 不需要,提交时自动封口 |
streaming | 大批量数据,最多 2,000,000 行 | 提交时不传,之后通过 /rows 分批上传 | 必填,1 ~ 2,000,000 | 必须调用 /seal |
none 请求体示例
{
"template_code": "S-7K2M9Q",
"printer_code": "<printer-code>",
"upload_mode": "none",
"params": {
"copies": 10
}
}inline 请求体示例
{
"template_code": "S-7K2M9Q",
"printer_code": "<printer-code>",
"upload_mode": "inline",
"params": {
"copies": 1
},
"rows": [
{
"data": {
"sku": "A001",
"barcode": "690123456789012345"
}
},
{
"data": {
"sku": "A002",
"barcode": "690123456789012346"
},
"copies": 2
}
]
}streaming 请求体示例
{
"template_code": "S-7K2M9Q",
"printer_code": "<printer-code>",
"upload_mode": "streaming",
"rows_expected": 2000000,
"params": {
"copies": 1
}
}数据行
- •
data是模板变量的键值对。纯常量行可以省略 data 或传{}。 - •
copies是行级份数,0 或省略时使用params.copies;不能为负,最大 1,000。任务的打印总张数等于各行份数之和。 - •
row_no:inline 模式要么全部省略(按数组顺序从 1 编号),要么全部给出并构成 1..N 的排列,不能混用;streaming 模式必须全部给出,且在整个任务内全局唯一。
任务状态
| status | 含义 | 终态 | 可取消 | 可重试 |
|---|---|---|---|---|
pending | 已提交,等待下发。streaming 任务在封口前一直是这个状态 | — | 是 | — |
dispatching | 已投递给终端,等待终端确认 | — | — | — |
queued | 终端已确认接收,任务在设备队列中,随时可能开始打印 | — | 是 | — |
printing | 打印中 | — | — | — |
completed | 全部完成 | 是 | — | — |
partial | 部分完成:有行打印失败。不要当作完成处理;可以重试,只补打失败行 | 是 | — | 是 * |
failed | 失败,原因见 error_message | 是 | — | 是 * |
cancelled | 已取消 | 是 | — | — |
retrying | 历史状态,新任务不会出现,只为兼容旧数据保留 | — | — | — |
* 还要求没有达到 max_retry,且数据没有被清理。请直接以响应中的 retryable 为准。
rows_failed 大于 0。请在业务侧把它当作需要处理的异常(调用
retry 补打失败行,或人工介入),不要当作完成后直接发货。
重试、取消与超时
- • 提交不幂等。请求超时或返回 500 时,先用 GET /print-jobs 查询最近的任务确认是否已经创建,再决定是否重新提交,否则可能重复打印。
- • retry:partial 任务只补打失败行;重试复用提交时的模板快照,不会使用之后发布的新版本。超过数据保留期后(
data_purged=true)不能重试,只能重新提交。 - • cancel:只能取消 pending 和 queued 状态的任务。queued 表示任务已经进入设备队列,取消时可能已经打出了部分标签,这部分照常计费。
计费
- • API 调用配额:提交、重试、取消、封口各计 1 次;GET 查询和
/rows不计。 - • 标签额度:按实际打印的标签张数计费,不按任务数。提交时预留计划张数(streaming 任务在封口时按实际总份数修正),任务结束后按实际打印张数结算,没有打印的部分退还。重试补打不会对已结算的张数重复计费。额度不足时返回
403 label_quota_exceeded。 - • 任务数额度:部分套餐还限制每月的打印任务数,用尽时返回
403 print_quota_exceeded。
大批量流式上传
数据超过 200 行或 512 KiB 时,请使用 streaming 模式。单个任务最多2,000,000 行。
- 1
创建任务
POST /print-jobs,upload_mode=streaming,并声明 rows_expected(总行数)。计 1 次 API 配额。
- 2
分批追加
多次调用 POST /print-jobs/:id/rows,每批最多 1,000 行,每行带全局 row_no(1..rows_expected)。批次可以乱序。不计月度配额,但受 QPM 限速。
- 3
断点续传
中断后调用 GET /print-jobs/:id/upload-progress 查看 rows_uploaded 和 max_row_no,从缺少的行继续。重传已写入的行是安全的:它们会计入 duplicated,不会覆盖原数据。
- 4
封口
POST /print-jobs/:id/seal。服务端校验行数等于 rows_expected,且 row_no 连续无缺口,通过后立即开始下发。重复封口返回 200。
- • 没有封口的 streaming 任务永远不会下发打印。
- • row_no 是全局行号,不要每批都从 1 开始:否则第二批起会全部计入 duplicated 并被丢弃,最后封口时报 rows_mismatch。首次上传时 duplicated 大于 0,就说明行号算错了。
- • 长时间没有追加活动的未封口任务,会被平台判定为上传中断并标记为失败。不再继续上传时,请主动调用 cancel 释放预留的标签额度。
- • 按默认 60 次/分钟计算,传满 2,000,000 行至少需要约34 分钟,而且轮询等其他请求也占用同一个 QPM 配额。需要更快时请联系我们调高 QPM。
export VARILABEL_APP_ID="<your-app-id>"
export VARILABEL_APP_SECRET="<your-app-secret>"
BASE="https://api.varilabel.com/api/open/v1"
AUTH=(-H "X-App-Id: $VARILABEL_APP_ID" -H "X-App-Secret: $VARILABEL_APP_SECRET")
# ① 创建 streaming 任务,声明总行数(计 1 次 API 配额)
curl -sS -X POST "$BASE/print-jobs" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d '{
"template_code": "S-7K2M9Q",
"printer_code": "<printer-code>",
"upload_mode": "streaming",
"rows_expected": 2000000,
"params": { "copies": 1 }
}'
# → 201 { "id": "<job-id>", "status": "pending", "data_sealed": false, ... }
JOB_ID="<job-id>"
# ② 分批追加(不计月度配额,受 QPM 限速)
# row_no 是全局行号:第 1 批 1..1000,第 2 批 1001..2000,以此类推
curl -sS -X POST "$BASE/print-jobs/$JOB_ID/rows" "${AUTH[@]}" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{ "row_no": 1, "data": { "sku": "A000001" } },
{ "row_no": 2, "data": { "sku": "A000002" }, "copies": 2 }
]
}'
# → { "inserted": 2, "duplicated": 0, "next_row_no": 3, "rows_uploaded": 2 }
# ③ 中断后续传:先确认已经写入到哪一行(GET,不计配额)
curl -sS "$BASE/print-jobs/$JOB_ID/upload-progress" "${AUTH[@]}"
# → { "rows_expected": 2000000, "rows_uploaded": 1000, "max_row_no": 1000, "sealed": false }
# ④ 全部传完后封口(计 1 次 API 配额)。封口成功后立即开始下发
curl -sS -X POST "$BASE/print-jobs/$JOB_ID/seal" "${AUTH[@]}"
# 上传放弃时请取消任务,释放预留的标签额度
curl -sS -X POST "$BASE/print-jobs/$JOB_ID/cancel" "${AUTH[@]}"接口参考
下面的路径都相对于 https://api.varilabel.com/api/open/v1。带计配额的接口每次调用消耗 1 次月度配额(服务端 5xx 除外)。点击「参数与响应」可以展开详情。存储接口的字段说明正在补充中。
打印任务
用企业模板编码(template_code)和打印机编码(printer_code)提交打印任务,并查询、重试或取消。上传模式、状态流转和计费规则见「打印任务对接指南」。
- •POST /print-jobs 暂不幂等:idempotency_key 还没有实现,传了会返回 400。请求超时或返回 500 时不要直接重新提交,先查询确认任务是否已经创建,否则可能重复打印。
- •job_no 是平台生成的任务编号,不是你的业务单号。它在提交响应里返回,可以用 by-job-no 查询。请求体里没有业务单号字段,多传的字段会被忽略。
- •status 是字符串。partial(部分完成)表示有行打印失败,不能当作 completed 处理。
- •打印任务接口中没有值的字段会被省略,不会返回 null。
- GET
/print-jobsprint_job:read分页查询打印任务列表
参数与响应
参数
名称 位置 类型 说明 status Query string 按状态筛选:pending / dispatching / queued / printing / completed / partial / failed / cancelled / retrying。也兼容数字状态值,其他值返回 400 source Query string 按来源筛选:api / web / batch job_no Query string 按任务编号筛选 virtual_printer_id Query string 按打印机 ID 筛选,必须是正整数 template_id Query string 按内部模板 ID 筛选,必须是正整数 terminal_id Query string 按终端 ID 筛选,必须是正整数 page Query integer 页码,从 1 开始,默认 1 page_size Query integer 每页条数,默认 20,最大 100 响应 · 分页列表<PrintJob>
{ "items": [ { "id": "1938475610293890001", "job_no": "<job-no>", "status": "completed", "source": "api", "template_id": "1938475610293800001", "template_version_id": "1938475610293810001", "template_release_id": "1938475610293850112", "virtual_printer_id": "1938475610293860001", "terminal_id": "1938475610293870001", "upload_mode": "inline", "data_sealed": true, "data_purged": false, "rows_total": 2, "rows_printed": 2, "rows_failed": 0, "total_pages": 3, "pages_printed": 3, "retry_count": 0, "max_retry": 3, "retryable": false, "created_at": "2025-01-01T10:00:00+08:00", "queued_at": "2025-01-01T10:00:01+08:00", "printed_at": "2025-01-01T10:00:05+08:00" } ], "total": 1, "page": 1, "page_size": 20 }错误
400invalid_request— status 不是已知状态,或 ID 类参数不是正整数
- GET
/print-jobs/by-job-no/:job_noprint_job:read按任务编号查询任务
job_no 来自提交响应。适合在业务系统里保存 job_no 后对账。
参数与响应
参数
名称 位置 类型 说明 job_no* 路径 string 平台生成的任务编号 响应 · PrintJob
{ "id": "1938475610293890001", "job_no": "<job-no>", "status": "completed", "source": "api", "template_id": "1938475610293800001", "template_version_id": "1938475610293810001", "template_release_id": "1938475610293850112", "virtual_printer_id": "1938475610293860001", "terminal_id": "1938475610293870001", "upload_mode": "inline", "data_sealed": true, "data_purged": false, "rows_total": 2, "rows_printed": 2, "rows_failed": 0, "total_pages": 3, "pages_printed": 3, "retry_count": 0, "max_retry": 3, "retryable": false, "created_at": "2025-01-01T10:00:00+08:00", "queued_at": "2025-01-01T10:00:01+08:00", "printed_at": "2025-01-01T10:00:05+08:00" }错误
404not_found— 任务不存在
- GET
/print-jobs/:idprint_job:read查询任务详情
轮询任务状态用这个接口。GET 不计月度配额,但受 QPM 限速,建议轮询间隔不低于数秒。
参数与响应
参数
名称 位置 类型 说明 id* 路径 string 任务 ID 响应 · PrintJob
{ "id": "1938475610293890001", "job_no": "<job-no>", "status": "completed", "source": "api", "template_id": "1938475610293800001", "template_version_id": "1938475610293810001", "template_release_id": "1938475610293850112", "virtual_printer_id": "1938475610293860001", "terminal_id": "1938475610293870001", "upload_mode": "inline", "data_sealed": true, "data_purged": false, "rows_total": 2, "rows_printed": 2, "rows_failed": 0, "total_pages": 3, "pages_printed": 3, "retry_count": 0, "max_retry": 3, "retryable": false, "created_at": "2025-01-01T10:00:00+08:00", "queued_at": "2025-01-01T10:00:01+08:00", "printed_at": "2025-01-01T10:00:05+08:00" }错误
400invalid_parameter— id 不是正整数404not_found— 任务不存在
- POST
/print-jobsprint_job:create计配额提交打印任务
upload_mode 必填。inline 示例见下;none 和 streaming 的请求体见「打印任务对接指南」。成功返回 201。
参数与响应
请求体 · SubmitRequest
{ "template_code": "S-7K2M9Q", "printer_code": "<printer-code>", "upload_mode": "inline", "params": { "copies": 1 }, "rows": [ { "data": { "sku": "A001", "barcode": "690123456789012345" } }, { "data": { "sku": "A002", "barcode": "690123456789012346" }, "copies": 2 } ] }响应 · 201 · PrintJob
{ "id": "1938475610293890001", "job_no": "<job-no>", "status": "pending", "source": "api", "template_id": "1938475610293800001", "template_version_id": "1938475610293810001", "template_release_id": "1938475610293850112", "virtual_printer_id": "1938475610293860001", "terminal_id": "1938475610293870001", "upload_mode": "inline", "data_sealed": true, "data_purged": false, "rows_total": 2, "rows_printed": 0, "rows_failed": 0, "total_pages": 3, "pages_printed": 0, "retry_count": 0, "max_retry": 3, "retryable": false, "created_at": "2025-01-01T10:00:00+08:00" }错误
400invalid_request— 缺少 template_code / printer_code,或 template_release_id 不合法400idempotency_not_supported— 传了 idempotency_key(暂未实现)400upload_mode_required— 没有传 upload_mode400invalid_upload_mode— upload_mode 取值非法,或与 rows / rows_expected 的组合不匹配400rows_expected_invalid— streaming 模式下 rows_expected 不在 1 ~ 2,000,000 之间400rows_expected_mismatch— inline 模式下 rows_expected 与 rows 的长度不一致400inline_rows_too_many— inline 行数超过 200,请改用 streaming413inline_payload_too_large— inline 数据超过 512 KiB,请改用 streaming400row_no_mixed— row_no 有的给了有的没给400row_no_out_of_range— row_no 为负,或不在 1..N 范围内400row_no_duplicated— row_no 重复400copies_invalid— 份数为负400copies_too_many— 份数超过 1,000400total_pages_invalid— total_pages 不在 0 ~ 100,000 之间400template_not_found— template_code 不存在、未上架,或当前凭证没有授权(不区分)400template_release_not_found— template_release_id 不属于这个 template_code409template_content_missing— 模板内容缺失,需要模板作者重新保存并发布409template_content_corrupted— 模板内容指纹不一致,请联系模板分组管理员400printer_not_found— printer_code 不存在400printer_disabled— 打印机已禁用400printer_not_bound— 打印机没有绑定终端400terminal_unavailable— 终端没有激活或已被吊销400source_file_not_found— source_file_id 不存在或无权使用400source_file_not_ready— 文件还没有确认上传,请先调用 /storage/uploads/:id/confirm400source_file_category_mismatch— 文件分类不是 print_data409source_file_in_use— 文件已经绑定到其他任务(一个文件只能绑定一个任务)502data_write_failed— 任务已创建,但数据行写入失败;任务已被标记失败并清理,直接重新提交即可。message 里带 job_no
- POST
/print-jobs/:id/retryprint_job:create计配额重试失败或部分完成的任务
只有 retryable=true 时才能重试。partial 任务只补打失败行,不会重打已经成功的行。重试复用提交时的模板快照,不会使用模板之后发布的新版本。
参数与响应
参数
名称 位置 类型 说明 id* 路径 string 任务 ID 响应 · { id, status }
{ "id": "1938475610293890001", "status": "pending" }错误
404not_found— 任务不存在409not_retryable— 任务不是 failed / partial,或已达到 max_retry410data_purged— 行数据已过保留期被清理,不能重打
- POST
/print-jobs/:id/cancelprint_job:cancel计配额取消任务
pending 和 queued 状态可以取消。queued 表示任务已经进入设备队列,取消时可能已经打出了部分标签,这部分照常计费。
参数与响应
参数
名称 位置 类型 说明 id* 路径 string 任务 ID 响应 · { id, status }
{ "id": "1938475610293890001", "status": "cancelled" }错误
404not_found— 任务不存在409not_cancellable— 任务当前状态不允许取消(只能取消 pending / queued)
打印任务接口错误码
| 400 | invalid_json | 请求体不是合法 JSON,被截断,或包含多个 JSON 对象 |
| 400 | invalid_field_type | 字段类型错误。最常见的是 ID 字段传成了数字(ID 必须是字符串) |
| 400 | invalid_request | 请求体为空,或参数不合法 |
| 404 | not_found | 任务不存在 |
| 413 | payload_too_large | 请求体超过大小限制 |
| 403 | permission_denied | 凭证没有被授权访问所请求的资源(模板条目或打印机) |
| 403 | label_quota_exceeded | 本月标签额度用尽(按打印张数计费)。重试不会成功:请升级套餐或等下个月 |
| 403 | print_quota_exceeded | 本月打印任务数额度用尽 |
| 403 | tenant_disabled | 企业账户已停用 |
| 500 | internal_error | 服务端异常。GET 可以退避重试;POST 请先查询确认结果再决定是否重试 |
数据结构
SubmitRequest
提交打印任务的请求体。请求体里没有内部模板 ID、打印机 ID 和业务单号字段;未定义的字段会被静默忽略。
| 字段 | 类型 | 说明 |
|---|---|---|
| template_code* | string | 企业模板条目的槽位编码(share_code,S-XXXXXX)。只能使用企业模板库里已生效的模板,不能用个人模板的 L- 编码 |
| template_release_id | string | 可选。指定一条历史发布记录,用于补打。不传时使用当前生效版本。必须是该条目下的发布记录 |
| printer_code* | string | 打印机编码(Printer.code)。目标终端由打印机的绑定关系自动确定 |
| upload_mode* | string | 上传模式:none / inline / streaming。没有默认值,见「打印任务对接指南」 |
| rows | SubmitRow[] | inline 模式必填,最多 200 行,序列化后不超过 512 KiB;none / streaming 模式必须为空 |
| rows_expected | integer | streaming 模式必填,取值 1 ~ 2,000,000;inline 模式可省略,填写时必须等于 rows 的长度;none 模式必须为 0 或省略 |
| source_file_id | string | 可选,只用于审计:原始数据文件的 ID。文件必须已通过存储接口上传并确认,分类为 print_data;一个文件只能绑定一个任务。服务端不会解析文件内容,数据行仍需通过 rows 或 /rows 提交 |
| params | PrintParams | 打印参数,可选 |
| total_pages | integer | 计划打印张数,可选,取值 0 ~ 100,000。有数据行的任务在封口后以服务端统计的各行份数之和为准 |
| idempotency_key | string | 暂未实现。传入非空值会返回 400 idempotency_not_supported |
SubmitRow
一行打印数据。inline 提交(rows)和流式追加(/rows)使用同一个结构。
| 字段 | 类型 | 说明 |
|---|---|---|
| row_no | integer | 行号,从 1 开始。inline 模式要么全部省略(按数组顺序编号),要么全部给出并构成 1..N 的排列,不能混用;streaming 模式必须给出,且在整个任务内全局唯一 |
| row_key | string | 可选,业务键(如订单行号),方便对账 |
| data | object | 模板变量的键值对。纯常量行可以省略或传 {}。条码、批号等长数字请以字符串传递 |
| copies | integer | 行级份数,0 或省略时使用 params.copies。不能为负,最大 1,000 |
PrintParams
打印参数,字段都可选。
| 字段 | 类型 | 说明 |
|---|---|---|
| copies | integer | 默认份数(行上没有 copies 时使用),不能为负,最大 1,000 |
| dpi | integer | 分辨率 |
| darkness | integer | 打印浓度,1 ~ 15 |
| speed | integer | 打印速度 |
| rotation | integer | 旋转角度:0 / 90 / 180 / 270 |
| mirror | boolean | 是否镜像 |
| lang | string | 指令语言,如 TSPL / ZPL |
| mode | string | 打印模式 |
| copies_field | string | 份数取自数据里的哪一列,只用于审计记录,不影响实际份数 |
PrintJob
打印任务。标注「可省略」的字段在没有值时不出现在响应里(不会返回 null)。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 任务 ID,后续接口的路径参数 |
| job_no | string | 平台生成的任务编号,全局唯一且永不复用。不是你的业务单号 |
| status | string | 任务状态,见「任务状态」表 |
| source | string | 来源:api(OpenAPI 提交)/ web / batch |
| template_id | string | 内部模板 ID,只供对账。可省略 |
| template_version_id | string | 内部模板版本 ID,只供对账。可省略 |
| template_release_id | string | 本次打印依据的企业模板发布记录 ID,用于补打和对账。可省略 |
| virtual_printer_id | string | 目标打印机 ID。可省略 |
| terminal_id | string | 目标终端 ID。可省略 |
| upload_mode | string | none / inline / streaming |
| data_sealed | boolean | 数据是否已封口。为 false 的任务不会被下发 |
| data_purged | boolean | 行数据是否已过保留期被清理。清理后任务记录保留,但不能重试 |
| rows_total | integer | 封口后的实际行数;封口前为 0。上传期间的行数请看 upload-progress |
| rows_printed | integer | 已打印行数(定期同步的快照,可能稍有滞后) |
| rows_failed | integer | 失败行数(快照) |
| total_pages | integer | 计划打印的标签张数。有数据行的任务封口后等于各行份数之和 |
| pages_printed | integer | 已打印的标签张数 |
| retry_count | integer | 已重试次数 |
| max_retry | integer | 最大重试次数 |
| retryable | boolean | 当前能否调用 retry。由服务端综合状态、重试次数和数据是否可用计算,请直接用它判断 |
| error_message | string | 错误信息。可省略 |
| created_at | string | 创建时间 |
| queued_at | string | 终端确认接收的时间。可省略 |
| printed_at | string | 打印完成时间。可省略 |
| failed_at | string | 失败时间。可省略 |
| cancelled_at | string | 取消时间。可省略 |
分页列表
分页列表接口的统一结构。模板分组列表({ groups })和可打印的打印机列表(for-print)不分页,结构单独说明。
| 字段 | 类型 | 说明 |
|---|---|---|
| items | array | 当前页数据 |
| total | integer | 总条数 |
| page | integer | 当前页码 |
| page_size | integer | 每页条数(服务端修正后的实际值) |
流式上传
只用于 upload_mode=streaming 的任务。提交后分批追加数据行,全部传完后封口,任务才会开始下发。单个任务最多 2,000,000 行。
- •row_no 是整个任务内的全局行号(1..rows_expected),不是每批都从 1 开始。每批从 1 开始的话,第二批会全部被当作重复行丢弃。
- •重传是安全的:已经写入的 row_no 会计入 duplicated,不会被覆盖。这也意味着已经写入的行不能再通过重传修改。
- •批次可以乱序上传,但封口时 1..rows_expected 必须完整、没有缺口。
- •/rows 不计月度配额,但和其他接口一起受凭证级 QPM 限速。按默认 60 次/分钟、每批 1,000 行计算,传满 2,000,000 行至少需要约 34 分钟。
- POST
/print-jobs/:id/rowsprint_job:create不计配额追加数据行
只对未封口的 streaming 任务有效。不计月度配额,但受 QPM 限速。
参数与响应
参数
名称 位置 类型 说明 id* 路径 string 任务 ID 请求体 · AppendRowsRequest
{ "rows": [ { "row_no": 1001, "data": { "sku": "A001001" } }, { "row_no": 1002, "data": { "sku": "A001002" }, "copies": 2 } ] }响应 · AppendResult
{ "inserted": 2, "duplicated": 0, "next_row_no": 1003, "rows_uploaded": 1002 }错误
400invalid_request— rows 为空400append_rows_too_many— 单批超过 1,000 行400row_no_required— 有行没有给 row_no,或 row_no ≤ 0400row_no_duplicated— 同一批内 row_no 重复400row_no_out_of_range— row_no 不在 [1, rows_expected] 范围内400copies_invalid— 份数为负400copies_too_many— 份数超过 1,000409rows_exceed_expected— 累计行数会超过提交时声明的 rows_expected409job_not_streaming— 任务不是 streaming 模式409no_data_expected— 任务以 upload_mode=none 提交,不接受数据行409job_not_appendable— 任务已取消、已失败或已封口,不再接受数据409job_already_sealed— 任务已封口
- POST
/print-jobs/:id/sealprint_job:create计配额封口任务,开始下发打印
服务端校验实际行数等于 rows_expected,且 row_no 连续没有缺口,通过后立即尝试下发。对已封口的任务重复调用返回 200。响应是任务的最新状态。
参数与响应
参数
名称 位置 类型 说明 id* 路径 string 任务 ID 请求体(可省略) · SealRequest(可选)
{ "checksum": "<optional-checksum>" }响应 · PrintJob
{ "id": "1938475610293890001", "job_no": "<job-no>", "status": "pending", "source": "api", "template_id": "1938475610293800001", "template_version_id": "1938475610293810001", "template_release_id": "1938475610293850112", "virtual_printer_id": "1938475610293860001", "terminal_id": "1938475610293870001", "upload_mode": "streaming", "data_sealed": true, "data_purged": false, "rows_total": 2000000, "rows_printed": 0, "rows_failed": 0, "total_pages": 2000000, "pages_printed": 0, "retry_count": 0, "max_retry": 3, "retryable": false, "created_at": "2025-01-01T10:00:00+08:00" }错误
409rows_mismatch— 已上传行数不等于 rows_expected。先查 upload-progress,补齐缺少的行后再封口409rows_not_continuous— row_no 有缺口(如 1..99、101)409job_not_streaming— 任务不是 streaming 模式404not_found— 任务不存在
- GET
/print-jobs/:id/upload-progressprint_job:read查询上传进度
网络中断后,用它确认数据已经写入到哪一行,再从断点续传。
参数与响应
参数
名称 位置 类型 说明 id* 路径 string 任务 ID 响应 · UploadProgress
{ "id": "1938475610293890001", "rows_expected": 2000000, "rows_uploaded": 1002, "max_row_no": 1002, "sealed": false }错误
404not_found— 任务不存在
数据结构
AppendRowsRequest
| 字段 | 类型 | 说明 |
|---|---|---|
| rows* | SubmitRow[] | 本批数据行,1 ~ 1,000 行。每行必须带 row_no(> 0) |
AppendResult
| 字段 | 类型 | 说明 |
|---|---|---|
| inserted | integer | 本批新写入的行数 |
| duplicated | integer | 本批中已经存在的行号数量。这些行不会被覆盖。重传时出现是正常的;首次上传出现,说明 row_no 算错了 |
| next_row_no | integer | 本批最大 row_no + 1。只在按顺序上传时有参考意义 |
| rows_uploaded | integer | 任务累计已写入的行数 |
UploadProgress
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 任务 ID |
| rows_expected | integer | 提交时声明的总行数 |
| rows_uploaded | integer | 已写入的行数 |
| max_row_no | integer | 已写入的最大行号。等于 rows_uploaded 时说明 1..max_row_no 没有缺口 |
| sealed | boolean | 是否已封口 |
SealRequest
请求体可以省略。
| 字段 | 类型 | 说明 |
|---|---|---|
| checksum | string | 可选。客户端计算的数据指纹,只存档用于对账,服务端不校验 |
模板
企业侧按「条目」(template share)寻址模板,可以用 share_id,也可以用槽位编码 share_code(S-XXXXXX)。所有展示字段和内容都来自已生效的发布记录。概念和推荐流程见「模板对接指南」。
- GET
/templatestemplate:read查询当前凭证可访问的全部模板条目
包括按分组授权和按单个条目授权的条目。同一模板发布到两个分组时,会返回两个条目,它们的版本可能不同。
参数与响应
参数
名称 位置 类型 说明 name Query string 按模板名称筛选 tags Query string[] 按标签筛选,可以重复传:tags=a&tags=b status Query integer 已废弃只为兼容旧集成保留:不传或传 1 时正常返回,传其他值返回 400。include_inactive 会被忽略。 page Query integer 页码,从 1 开始,默认 1 page_size Query integer 每页条数,默认 20,最大 100 响应 · 分页列表<TemplateItem>
{ "items": [ { "share_id": "1938475610293847552", "group_id": "1938475610293840001", "share_code": "S-7K2M9Q", "release_id": "1938475610293850112", "version_no": 3, "name": "发货标签 100×150", "description": null, "width": 100, "height": 150, "size_unit": "mm", "source": 1, "released_at": "2025-01-01T10:00:00+08:00", "thumbnail": { "url": "https://<oss-domain>/<signed-path>", "expires_at": "2025-01-01T11:00:00+08:00" }, "can_print": true } ], "total": 1, "page": 1, "page_size": 20 }错误
400invalid_parameter— status 传了 1 以外的值
- GET
/template-groupstemplate:read列出模板分组
参数与响应
{ "groups": [ { "id": "1938475610293840001", "name": "物流标签", "description": "仓库发货使用", "sort_order": 0 } ] } - GET
/template-groups/:groupId/templatestemplate:read列出分组下的模板条目
参数与响应
参数
名称 位置 类型 说明 groupId* 路径 string 分组 ID name Query string 按模板名称筛选 tags Query string[] 按标签筛选,可以重复传:tags=a&tags=b status Query integer 已废弃只为兼容旧集成保留:不传或传 1 时正常返回,传其他值返回 400。include_inactive 会被忽略。 page Query integer 页码,从 1 开始,默认 1 page_size Query integer 每页条数,默认 20,最大 100 响应 · 分页列表<TemplateItem>
{ "items": [ { "share_id": "1938475610293847552", "group_id": "1938475610293840001", "share_code": "S-7K2M9Q", "release_id": "1938475610293850112", "version_no": 3, "name": "发货标签 100×150", "description": null, "width": 100, "height": 150, "size_unit": "mm", "source": 1, "released_at": "2025-01-01T10:00:00+08:00", "thumbnail": { "url": "https://<oss-domain>/<signed-path>", "expires_at": "2025-01-01T11:00:00+08:00" }, "can_print": true } ], "total": 1, "page": 1, "page_size": 20 }错误
400invalid_parameter— status 传了 1 以外的值403forbidden— 无权访问该分组404not_found— 分组不存在
模板接口错误码
| 400 | invalid_parameter | 参数不合法,修正后再调用 |
| 403 | forbidden | 无权访问该分组或条目(不区分具体原因) |
| 404 | not_found | 资源不存在、不属于当前企业,或无权查看 |
| 409 | share_not_listed | 条目存在,但当前没有在分组中上架。请联系分组管理员 |
| 409 | content_hash_mismatch | 内容指纹不一致,平台已拒绝下发。请勿重试,联系平台支持 |
| 409 | template_content_missing | 模板内容缺失,需要模板作者重新保存 |
| 410 | endpoint_removed | 调用了已下线的旧接口,响应里有迁移指引 |
数据结构
TemplateItem
企业模板条目。所有展示字段都来自当前生效的发布记录快照,与作者个人库里模板的当前状态无关。
| 字段 | 类型 | 说明 |
|---|---|---|
| share_id | string | 条目 ID,企业侧的主键 |
| group_id | string | 所属分组 ID |
| share_code | string | 槽位编码,格式 S-XXXXXX。条目生命周期内不变 |
| release_id | string | 当前生效的发布记录 ID。它变了,就说明生效版本变了(包括回滚) |
| version_no | integer | 生效版本号 |
| name | string | 模板名称(发布时快照) |
| description | string | null | 模板描述(发布时快照) |
| width | number | 标签宽度,单位见 size_unit |
| height | number | 标签高度,单位见 size_unit |
| size_unit | string | 尺寸单位:mm / cm / in / px |
| source | integer | 生效来源:1 审核通过,2 免审直发,3 管理员回滚 |
| released_at | string | 生效时间(RFC 3339) |
| thumbnail | FileURL | null | 封面图临时地址;封面还在异步生成时为 null |
| can_print | boolean | 当前凭证能否用这个条目提交打印 |
ReleaseItem
条目的一条发布记录。发布记录只增不改;回滚会新增一条指向旧版本的记录,不会复用旧记录。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 发布记录 ID,可作为 content 接口的 release_id |
| version_no | integer | 版本号 |
| content_hash | string | 内容指纹(SHA-256,64 位十六进制) |
| name | string | 模板名称快照 |
| width | number | 标签宽度快照 |
| height | number | 标签高度快照 |
| size_unit | string | 尺寸单位快照 |
| source | integer | 1 审核通过,2 免审直发,3 管理员回滚 |
| released_at | string | 生效时间 |
| superseded_at | string | null | 被替代或下架的时间;null 表示当前生效 |
| is_current | boolean | 是否为当前生效记录 |
ContentResponse
某条发布记录对应的模板内容。
| 字段 | 类型 | 说明 |
|---|---|---|
| version_no | integer | 版本号 |
| content_hash | string | 内容指纹,可作为缓存键 |
| width | number | 标签宽度 |
| height | number | 标签高度 |
| size_unit | string | 尺寸单位 |
| title | string | 打印标题 |
| content | object | 模板设计内容 |
GroupItem
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 分组 ID |
| name | string | 分组名称 |
| description | string | null | 分组描述 |
| sort_order | integer | 排序权重 |
FileURL
带签名的临时地址。请在 expires_at 之前重新拉取,不要等到图片加载失败再处理。
| 字段 | 类型 | 说明 |
|---|---|---|
| url | string | 临时访问地址 |
| expires_at | string | 地址失效时间(服务端签名的真实过期时间) |
分页列表
分页列表接口的统一结构。模板分组列表({ groups })和可打印的打印机列表(for-print)不分页,结构单独说明。
| 字段 | 类型 | 说明 |
|---|---|---|
| items | array | 当前页数据 |
| total | integer | 总条数 |
| page | integer | 当前页码 |
| page_size | integer | 每页条数(服务端修正后的实际值) |
打印机
查询打印机及其运行状态。提交打印任务前,可以用 for-print 拿到已绑定且已启用的打印机,以及它们的在线状态。
- •提交打印任务使用打印机的 code(printer_code),不是 id。for-print 不返回 code,请用 GET /printers 或 /printers/:id 获取;code 为空的打印机不能通过 OpenAPI 提交任务。
- •GET /printers 默认只返回 status=active 且 bind_status=bound 的打印机。要查看全部,请传 include_unusable=true。
- •GET /printers/:id 不按状态过滤,可能返回已禁用或已解绑的打印机。使用前请检查 status 和 bind_status。
- •online 由服务端根据 last_reported_at 计算;runtime_status 是打印机最后一次上报的值。打印机掉线后,runtime_status 可能仍停留在 READY,判断是否可用时请同时看这两个字段。
- •打印机接口中没有值的字段会被省略,不会返回 null,请按字段可能不存在处理。
- GET
/printers/for-printprinter:read列出可用于打印的打印机(按终端分组)
只返回已绑定且已启用的打印机,附带在线状态。不分页。
参数与响应
响应 · ListForPrintResponse
{ "groups": [ { "terminal_id": "1938475610293870001", "terminal_name": "仓库前台电脑", "terminal_code": "<terminal-code>", "terminal_online": true, "printers": [ { "id": "1938475610293860001", "name": "仓库 1 号机", "device_key": "<device-key>", "conn_type": "USB_DIRECT", "model_name": "ZD421", "default_dpi": 203, "default_lang": "ZPL", "print_width_mm": 104, "print_height_mm": 150, "runtime_status": "READY", "online": true, "last_reported_at": "2025-01-01T10:00:00+08:00" } ] } ], "total_count": 1, "online_count": 1 } - GET
/printersprinter:read分页查询打印机列表
默认只返回已启用且已绑定的打印机。
参数与响应
参数
名称 位置 类型 说明 name Query string 按名称筛选 device_key Query string 按设备标识筛选 tag Query string 按标签筛选(单个) conn_type Query string 按连接类型筛选:USB_DIRECT / WINDOWS_SPOOLER / CUPS / NETWORK include_unusable Query string 传 true(小写)时返回所有状态的打印机,其他值都按不传处理 status Query integer 业务状态:1 启用,2 禁用。只在 include_unusable=true 时生效,否则会被忽略 bind_status Query integer 绑定状态:0 已发现,1 已绑定,2 已解绑。只在 include_unusable=true 时生效,否则会被忽略 page Query integer 页码,从 1 开始,默认 1 page_size Query integer 每页条数,默认 20,最大 100 响应 · 分页列表<Printer>
{ "items": [ { "id": "1938475610293860001", "code": "<printer-code>", "name": "仓库 1 号机", "device_key": "<device-key>", "conn_type": "USB_DIRECT", "terminal_id": "1938475610293870001", "group_id": "1938475610293880001", "status": "active", "bind_status": "bound", "model_name": "ZD421", "manufacturer": "Zebra", "default_dpi": 203, "default_lang": "ZPL", "print_width_mm": 104, "print_height_mm": 150, "runtime_status": "READY", "online": true, "last_reported_at": "2025-01-01T10:00:00+08:00", "capabilities": { "max_width_mm": 104, "supported_dpi": [203, 300], "supported_langs": ["ZPL", "EPL"], "has_cutter": true }, "tags": ["仓库A"], "firmware_version": "V84.20.21Z", "bound_at": "2024-12-01T09:00:00+08:00", "updated_at": "2025-01-01T10:00:00+08:00", "created_at": "2024-12-01T09:00:00+08:00" } ], "total": 1, "page": 1, "page_size": 20 }错误
400invalid_parameter— status 或 bind_status 不是整数
- GET
/printers/:idprinter:read查询打印机详情
不按状态过滤,可能返回已禁用或已解绑的打印机。
参数与响应
参数
名称 位置 类型 说明 id* 路径 string 打印机 ID 响应 · Printer
{ "id": "1938475610293860001", "code": "<printer-code>", "name": "仓库 1 号机", "device_key": "<device-key>", "conn_type": "USB_DIRECT", "terminal_id": "1938475610293870001", "group_id": "1938475610293880001", "status": "active", "bind_status": "bound", "model_name": "ZD421", "manufacturer": "Zebra", "default_dpi": 203, "default_lang": "ZPL", "print_width_mm": 104, "print_height_mm": 150, "runtime_status": "READY", "online": true, "last_reported_at": "2025-01-01T10:00:00+08:00", "capabilities": { "max_width_mm": 104, "supported_dpi": [203, 300], "supported_langs": ["ZPL", "EPL"], "has_cutter": true }, "tags": ["仓库A"], "firmware_version": "V84.20.21Z", "bound_at": "2024-12-01T09:00:00+08:00", "updated_at": "2025-01-01T10:00:00+08:00", "created_at": "2024-12-01T09:00:00+08:00" }错误
400invalid_parameter— id 不是正整数404not_found— 打印机不存在或不属于当前企业
打印机接口错误码
| 400 | invalid_parameter | 参数不合法,修正后再调用 |
| 404 | not_found | 打印机不存在或不属于当前企业 |
| 500 | internal_error | 服务端异常,可以退避重试 |
数据结构
Printer
打印机详情。标注「可省略」的字段在没有值时不出现在响应里(不会返回 null),请按字段可能不存在处理。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 打印机 ID,用于查询详情和筛选任务 |
| code | string | 打印机编码,提交打印任务时作为 printer_code 使用。可能为空字符串:没有编码的打印机不能通过 OpenAPI 提交任务 |
| name | string | 打印机名称 |
| device_key | string | 设备唯一标识 |
| conn_type | string | 连接类型:USB_DIRECT / WINDOWS_SPOOLER / CUPS / NETWORK |
| terminal_id | string | 所属终端 ID |
| group_id | string | 所属打印机分组 ID。可省略:未分组时不返回 |
| status | string | 业务状态:active 启用,disabled 禁用 |
| bind_status | string | 绑定状态:discovered 已发现,bound 已绑定,unbound 已解绑 |
| model_name | string | 型号。可省略 |
| manufacturer | string | 制造商。可省略 |
| firmware_version | string | 固件版本。可省略 |
| default_dpi | integer | 默认分辨率(DPI),未配置时为 203 |
| default_lang | string | 默认指令语言,如 TSPL / ZPL。可省略 |
| print_width_mm | number | 可打印宽度(毫米),未配置时为 0 |
| print_height_mm | number | 可打印高度(毫米),未配置时为 0 |
| runtime_status | string | 打印机最近一次上报的运行状态,如 READY / ERROR / OFFLINE / BUSY。可省略:从未上报时不返回 |
| status_message | string | 运行状态的说明文字。可省略 |
| online | boolean | 服务端计算:last_reported_at 在最近 60 秒内为 true,否则为 false |
| last_reported_at | string | 最近一次上报状态的时间。可省略:从未上报时不返回 |
| capabilities | PrinterCapabilities | 打印机能力。可省略 |
| tags | string[] | 标签。可省略:没有标签时不返回 |
| bound_at | string | 绑定时间。可省略 |
| unbound_at | string | 解绑时间。可省略 |
| created_at | string | 创建时间 |
| updated_at | string | 更新时间 |
PrinterCapabilities
以下字段都可省略:未上报、值为 0、false 或空数组时不返回。
| 字段 | 类型 | 说明 |
|---|---|---|
| max_width_mm | integer | 最大打印宽度(毫米) |
| max_height_mm | integer | 最大打印高度(毫米) |
| supported_dpi | integer[] | 支持的分辨率 |
| supported_langs | string[] | 支持的指令语言,如 TSPL、ZPL、EPL、CPCL、ESC/POS |
| has_cutter | boolean | 是否有切刀 |
| has_peeler | boolean | 是否有剥离器 |
| color_support | boolean | 是否支持彩色 |
ListForPrintResponse
按终端分组的可打印打印机列表,不分页。
| 字段 | 类型 | 说明 |
|---|---|---|
| groups | array | 按终端分组的列表,每项结构见下面的 groups[] 字段 |
| groups[].terminal_id | string | 终端 ID |
| groups[].terminal_name | string | 终端名称 |
| groups[].terminal_code | string | 终端编码 |
| groups[].terminal_online | boolean | 终端在线状态 |
| groups[].printers | array | 该终端下的打印机,字段见 PrinterForPrintItem |
| total_count | integer | 打印机总数 |
| online_count | integer | 其中在线的打印机数 |
PrinterForPrintItem
Printer 的精简版,字段含义与 Printer 相同。不含 code、status、bind_status、capabilities 等字段。
| 字段 | 类型 | 说明 |
|---|---|---|
| id | string | 打印机 ID |
| name | string | 打印机名称 |
| device_key | string | 设备唯一标识 |
| conn_type | string | 连接类型 |
| model_name | string | 型号。可省略 |
| default_dpi | integer | 默认分辨率(DPI) |
| default_lang | string | 默认指令语言。可省略 |
| print_width_mm | number | 可打印宽度(毫米) |
| print_height_mm | number | 可打印高度(毫米) |
| runtime_status | string | 最近一次上报的运行状态。可省略 |
| online | boolean | 根据 last_reported_at 计算的在线状态 |
| last_reported_at | string | 最近一次上报状态的时间。可省略 |
分页列表
分页列表接口的统一结构。模板分组列表({ groups })和可打印的打印机列表(for-print)不分页,结构单独说明。
| 字段 | 类型 | 说明 |
|---|---|---|
| items | array | 当前页数据 |
| total | integer | 总条数 |
| page | integer | 当前页码 |
| page_size | integer | 每页条数(服务端修正后的实际值) |
存储
上传模板会用到的图片、字体等文件。流程分三步:申请上传 → 直传 → 确认。
- GET
/storage/usagestorage:read查询存储用量
- POST
/storage/uploadsstorage:write计配额申请上传,获取直传地址
- POST
/storage/uploads/:id/confirmstorage:write计配额确认上传完成
- GET
/storage/filesstorage:read分页查询文件列表
- GET
/storage/files/:idstorage:read查询文件详情
- GET
/storage/files/:id/urlstorage:read获取临时下载地址
- DELETE
/storage/files/:idstorage:write计配额删除文件
已下线接口
旧版模板接口按模板 ID 寻址,已经下线。调用时返回 410 Gone(code 为 endpoint_removed)和迁移指引。新接口按条目寻址,迁移时请注意:
- • 主键从 template_id 换成 share_id。也可以直接用 share_code 定位条目。
- • 「版本列表」换成「发布记录」:只包含在企业侧正式生效过的版本,不含作者的草稿。
- • 取历史版本内容时,参数从 versionId 换成
release_id。 - • 列表接口的
status筛选已废弃:只返回已上架的条目。传 1 仍然兼容,传其他值返回 400。
| 旧接口 | 替代接口 |
|---|---|
| GET /templates/:id | GET /template-shares/:shareId |
| GET /templates/:id/versions | GET /template-shares/:shareId/releases |
| GET /templates/:id/versions/:versionId | GET /template-shares/:shareId/content?release_id= |
准备好开始对接了吗?
企业版提供沙箱环境、更高的 QPM 和专属技术支持,帮你更快完成与 ERP / WMS / MES 的集成。