Skip to Content
卖家指南API 集成

18. API 集成

◀ 目录

Inkica 的 API 让您自己的系统自动向 Inkica 发送订单——无需登录控制台逐个手动创建订单。适用于以下情况:

  • 您在自己的网站或 Inkica 尚未预置连接的渠道上销售。
  • 您有自己的工具/软件管理订单,并希望直接推送给工厂。
  • 您想全面自动化:订单进入 → 创建 Inkica 订单 → 跟踪 tracking。

如果您在 eBay、Etsy、TikTok Shop、Shopify 或 Amazon 上销售,更简单的方式是连接店铺——订单自动进入,无需编程。API 适用于其余情况。

本页面既写给您,也写给负责集成的开发人员——您可以直接把本页链接发给他们。

工作原理概览

  1. 在 Inkica 控制台创建 API 令牌(只需做一次)。
  2. 查询目录,获取想要销售的产品的 variant_id(T 恤款式、颜色、尺码)。
  3. 创建订单——提交收件人地址 + 印刷文件。订单以草稿状态创建,尚未扣款。
  4. 提交生产——Inkica 从钱包扣款,并将订单转交给工厂。
  5. 跟踪订单——读取状态,以及订单交给承运商后的 tracking 单号;或注册 webhook,由 Inkica 主动通知。

1. 创建 API 令牌

  1. 打开账户菜单(侧边栏最底部)→ API。
  2. 点击 创建令牌,起一个好记的名称(例如 “Website sync”)。
  3. 立即复制令牌——令牌形如 ink_pat_...,只显示 1 次。关闭对话框后就无法再查看,只能创建新令牌。

🔒 请像保管密码一样保管令牌。 任何拥有令牌的人都可以创建订单并花费您钱包里的钱。不要把令牌放进在浏览器中运行的代码里,不要通过聊天工具发送,不要提交到 GitHub。怀疑泄露时,进入 设置 → API 点击 撤销 立即吊销,该令牌会马上失效。

每个账户同时最多可有 10 个令牌。建议为每个系统/工具各创建 1 个令牌,这样需要吊销其中一个时,其他的仍可继续运行。

2. 调用 API

Base URLhttps://api.inkica.com/api/v1
身份验证请求头 Authorization: Bearer ink_pat_...
格式JSON(Content-Type: application/json),货币为 USD
完整参考文档(可直接试用 API)api.inkica.com/api/v1/docs 

通过获取产品列表来快速测试令牌:

curl https://api.inkica.com/api/v1/catalog/blueprints?limit=5 \ -H "Authorization: Bearer ink_pat_xxxxxxxxxxxx"

如果返回了产品列表,说明令牌可以使用。

3. 选择产品(目录)

目录分为 2 层:

  • Blueprint——原始产品模板,例如 “US Unisex Heavy Cotton Tee”。
  • Variant——该 blueprint 的某个具体颜色 × 尺码组合,例如 Black / L。创建订单时,您通过 variant_id 来选择。

Blueprint 列表

GET /v1/catalog/blueprints?q=tee&page=1&limit=20

还可以按 category 筛选(例如 clothing)。每个 blueprint 包含 id、name、product_type、图片以及 print_areas——可印刷的位置。

单个 blueprint 的详情

GET /v1/catalog/blueprints/1
{ "id": 1, "name": "US Unisex Heavy Cotton Tee 2D", "colors": [{ "name": "Black", "hex": "#000000" }], "sizes": ["S", "M", "L", "XL", "2XL"], "included_print_area": "front", "print_areas": [ { "position": "front", "fee": 4.2, "width": 38, "height": 58, "unit": "cm" }, { "position": "back", "fee": 4.2, "width": 38, "height": 58, "unit": "cm" }, { "position": "sleeve_left", "fee": 3.35, "width": 4, "height": 3.5, "unit": "inch" } ] }
  • print_areas[].width / height / unit——印刷区域的尺寸,用于按正确比例制作印刷文件。
  • fee——该位置的印刷费。

Variant 列表(含价格)

GET /v1/catalog/blueprints/1/variants?page=1&limit=100
{ "data": [ { "id": 20139, "sku": "IUSG5000-S-ASH", "color": "ASH", "size": "S", "is_available": true, "price": 7.58 } ], "page": 1, "limit": 100, "total": 821 }

价格计算方式: variant 的 price 已包含 1 个印刷位置(即 included_print_area 指定的位置,通常是正面)。如果再印其他位置,需加上该位置的印刷费。以上面的例子为例:只印正面 = $7.58;同时印正面 + 背面 = $7.58 + $4.20 = $11.78。

每一行的准确价格始终以创建订单时返回的 unit_price 为准——请以该数字为标准。

只使用 is_available: true 的 variant。大型 blueprint 有数百个 variant——请调大 limit(最大 1000)或翻页 page 来获取全部。

4. 估算运费(非必需)

想在下单前向客户报运费时:

POST /v1/orders/shipping
{ "line_items": [{ "variant_id": 20139, "quantity": 2 }], "address_to": { "country": "US", "region": "CA", "zip": "90001" }, "shipping_method": "standard" }

返回 { "shipping": 7.39, "currency": "USD", "is_estimate": true }。寄往美国的订单必须提供 zip。

如果您自行提供运单,请加上 "shipping_mode": "self"——此时返回的 shipping 是固定处理费(代替运费),is_estimate: false。

5. 创建订单

POST /v1/orders
{ "external_id": "WEB-10023", "shipping_method": "standard", "address_to": { "first_name": "John", "last_name": "Smith", "email": "john@example.com", "phone": "+1 555 123 4567", "country": "US", "region": "CA", "address1": "123 Main St", "address2": "Apt 4", "city": "Los Angeles", "zip": "90001" }, "line_items": [ { "variant_id": 20139, "quantity": 2, "print_areas": { "front": "https://your-cdn.com/designs/front.png", "back": "https://your-cdn.com/designs/back.png" }, "mockups": { "front": "https://your-cdn.com/mockups/front.jpg" } } ] }
字段是否必填说明
external_id否(建议提供)您自己系统中的订单号,最多 100 个字符。必须与您的其他订单不重复。如果用某个仍为草稿的订单的相同 external_id 再次提交,该草稿会被更新,而不会新建订单——因此当您的系统因网络错误而重发时是安全的。已提交生产的订单,其 external_id 会被锁定(报错 409),即使订单已被拆分为 -F1、-F2 也一样——以确保同一个订单永远不会被创建并付款 2 次。
shipping_method否standard(默认)、priority 或 express——见快速发货。
shipping_mode否inkica(默认——由 Inkica 购买运单并收取运费)或 self(您自行提供运单,只收取固定处理费)——见自行提供运单。
shipping_label.label_urlself 时必填运单文件(PDF)的公开链接——工厂下载、打印并贴在包裹上。
shipping_label.tracking_numberself 时必填该运单的 tracking 单号,最多 128 个字符。
shipping_label.carrier否运单所属的承运商,例如 USPS。
address_to.first_name是
address_to.country是2 位国家代码,例如 US。
address_to.region是州/省代码,例如 CA。对于美国,填写完整州名(California)也可以。
address_to.address1是最多 50 个字符——更长的内容请拆到 address2。
address_to.city, zip是
address_to.email, phone否
line_items是每个订单最多 50 行。
line_items[].variant_id是在第 3 步中获取。
line_items[].quantity是1 – 999。
line_items[].print_areas是每个位置的印刷文件:{ "位置": "URL" }。位置必须在该 blueprint 的 print_areas 中(第 3 步)。有正面/背面的产品(T 恤、连帽衫……)至少需要这两面中的 1 面。URL 必须能直接下载到原始图片文件(不能是网页,也不能是预览图)——Inkica 会在创建订单时试下载,如果链接失效或图片长边小于 600px,则返回 400 错误。
line_items[].mockups否每个位置的效果图。留空则直接使用印刷文件。
line_items[].personalization否个性化文字(例如首饰上的刻字),最多 255 个字符。

对印刷文件的要求: URL 必须是公开链接(https://...),无需登录即可直接下载,并且在订单送达之前保持该链接不变——工厂在生产时会从该链接下载文件。文件为透明背景的 PNG,且分辨率须满足第 3 步中印刷区域尺寸的要求。

返回结果是 draft 状态的订单:

{ "id": "4821", "external_id": "WEB-10023", "status": "draft", "line_items": [ { "id": "9150", "variant_id": 20139, "sku": "IUSG5000-S-ASH", "quantity": 2, "unit_price": 11.78, "print_areas": { "front": "...", "back": "..." } } ], "subtotal": 23.56, "shipping": 0, "total": 23.56, "currency": "USD", "shipment": null }

草稿订单尚未扣款,也尚未生产。此时运费始终为 0——运费在提交生产时计算。通过 API 创建的订单也会显示在控制台的 订单 栏目中,与其他订单在同一处。

自行提供运单(self-ship)

已经有运单了(自己购买,或由平台提供)?随订单一起发送——工厂打印您的运单并贴在包裹上,Inkica 不购买运单,也不收取运费,只收取一笔小额的固定处理费(具体金额可通过 POST /v1/orders/shipping 或 dry_run 查看)。

{ "external_id": "WEB-10024", "shipping_mode": "self", "shipping_label": { "label_url": "https://your-cdn.com/labels/WEB-10024.pdf", "tracking_number": "9400111899223197428490", "carrier": "USPS" }, "address_to": { "...": "..." }, "line_items": [ { "...": "..." } ] }
  • shipping_mode: "self" 和 shipping_label 必须同时提供——只提供其中一个会返回 400。
  • 运单必须寄往订单完全相同的 address_to。Inkica 不读取运单内容:地址错误、已过期或已使用过的运单会导致包裹寄错,责任由您承担。
  • label_url 必须可以直接下载(无需登录),并且在订单送达前保持链接不变,与印刷文件相同。
  • 仅支持标准发货——与 priority/express 一起使用会返回 400(送达速度由您的运单决定)。
  • 一张运单只能贴在一个包裹上,因此订单中所有产品必须由同一家工厂制作;而且并非每家工厂都接受外部运单。订单不满足条件时,提交生产会返回 400——请先用 dry_run 检查。此时可拆分为多个订单,或去掉 shipping_mode/shipping_label,由 Inkica 购买运单。
  • 订单仍是草稿时想改主意:用同一个 external_id 重新发送且不带 shipping_label → 订单改回由 Inkica 购买运单,旧运单被丢弃。
  • 返回结果包含 "shipping_mode": "self",shipment 会立即显示您的运单和 tracking。如果使用 webhook,该订单的 order:shipment:created 事件会在创建/提交订单后立即到达,无需等待工厂发货。

6. 提交生产

POST /v1/orders/4821/send_to_production

Inkica 会计算运费,从钱包扣除总金额,并将订单转交给工厂。钱包余额不足时 API 会报错,订单仍保持草稿状态,请充值后再重新提交。

正式提交前试运行(dry_run)

正在做集成,不想花真钱?请附带 "dry_run": true:

POST /v1/orders/4821/send_to_production
{ "dry_run": true }

Inkica 会执行与正式提交完全相同的所有检查步骤——地址、印刷文件、是否有货、是否有工厂能印该位置、运费——然后返回将要扣除的金额,但不扣款、不生产任何东西,订单仍是草稿:

{ "dry_run": true, "orders": [ { "external_id": "WEB-10023", "subtotal": 23.56, "shipping": 7.39, "total": 30.95 } ], "total": 30.95, "currency": "USD", "wallet_balance": 26.66, "sufficient_balance": false }
  • total 是此刻立即正式提交时将被扣除的准确金额。
  • sufficient_balance: false → 钱包余额不足,正式提交会被拒绝——请先充值。
  • 订单有问题(缺货、印刷位置无法制作……)→ 会收到与正式提交时完全相同的 400 错误。

试运行可以执行任意多次。一切正常后,再次提交时不带 dry_run(或带 "dry_run": false)即可正式提交生产。

试运行不会经过提交之后的各个步骤(订单变为 in_production → shipped、产生 tracking)。如需测试状态/tracking 的读取部分,请使用 1 个小额的真实订单——需要时立即取消,款项会退回钱包。

⚠️ 此步骤之后订单会有新的 id。 草稿订单会被正式订单取代,因此旧的 id(4821)不能再使用。请保存返回结果中的 orders[].id,以便后续跟踪:

{ "orders": [ { "id": "4822", "external_id": "WEB-10023", "status": "in_production", "shipping": 7.39, "total": 30.95 } ] }

通常 orders 中只有 1 个订单。如果订单中的产品必须在多个不同的工厂制作,订单会被拆分为多个订单——此时 external_id 会加上后缀 -F1、-F2……

不小心丢失了返回结果(例如网络中途断开)?不要重新提交——请按 external_id 查找订单:

GET /v1/orders?external_id=WEB-10023

如果订单已被拆分,结果中也会包含 -F1、-F2 等部分。

7. 跟踪订单

GET /v1/orders/4822 GET /v1/orders?status=shipped&page=1&limit=50
status含义
draft草稿订单——尚未提交生产,尚未扣款。
pending已提交,Inkica 正在选择工厂。
in_production工厂正在生产。
on_hold暂停——Inkica 需要进一步核查(例如地址有问题)。如果持续时间较长,请联系客服。
shipped已交给承运商——已有 tracking 单号。
delivered已送达收件人。
cancelled已取消。
rejected被拒绝(例如印刷文件不合格)——请在控制台查看订单或联系客服。
split订单已按工厂拆分——请在 split_orders 中查看子订单。

订单交给承运商后,shipment 字段会包含 tracking 信息,供您发给客户:

"shipment": { "carrier": "usps", "tracking_number": "9400111899223456789012", "tracking_url": "https://tools.usps.com/go/TrackConfirmAction?tLabels=9400111899223456789012", "label_url": "https://cdn.inkica.com/labels/4822.pdf", "status": "in_transit", "delivered_at": null }

label_url 是贴在包裹上的运单文件(PDF)——当工厂自行购买运单并且只回传 tracking 单号时为 null。tracking_url 也可能为 null;此时请在 carrier 对应的网站上按 tracking_number 查询。

对于自行提供运单的订单,shipment 就是您发送的运单和 tracking 单号,从创建订单起即可看到。

想让 Inkica 在订单每次变更状态或有 tracking 时主动通知,而不是让您的系统不停地轮询?请使用 webhook。如果不使用 webhook,建议大约每 1 小时检查一次处于 pending/in_production 的订单。

8. 取消订单

POST /v1/orders/4822/cancel

只有在工厂尚未开始生产时才能取消。已付款的订单会退回钱包。取消草稿订单则无需退款,因为尚未扣款。超过可取消的时间点后,API 会返回错误——如仍需处理,请联系客服。

9. Webhook——自动接收通知

在您的服务器上注册 1 个地址(URL)——每当有变化时,Inkica 都会自动发送(POST)到该地址,无需不停地轮询。

注册

最快的方式: 打开账户菜单 → API → Webhook 部分 → 添加 Webhook,输入 URL 并选择事件。在这里您还可以看到每个 webhook 的状态(运行中 / 已被停用及原因)、最近一次投递成功还是失败、发送测试 按钮和删除按钮。

或者通过 API 注册:

POST /v1/webhooks
{ "url": "https://your-server.com/inkica/webhooks", "events": ["order:updated", "order:shipment:created"] }
事件触发时机
order:updated订单状态变更(例如 in_production → shipped)。附带 previous_status。
order:shipment:created订单有了 tracking 单号——可以立即发给客户。

events 留空 = 接收全部事件。返回结果中包含形如 whsec_... 的 secret——只显示 1 次,请保存下来用于验证签名(见下文)。

  • url 必须是公开的 https://——不接受内部地址(localhost、局域网 IP……)。
  • 每个账户最多 5 个 webhook,每个 URL 只能注册 1 次。查看列表:GET /v1/webhooks · 删除:DELETE /v1/webhooks/{id}。
  • 立即发送测试:POST /v1/webhooks/{id}/test——Inkica 会发送 1 个 ping 事件并返回结果(delivered、status_code、error)。

Inkica 发送的内容

{ "id": "dlv_1042", "event": "order:updated", "created_at": "2026-10-17T08:06:10.000Z", "data": { "previous_status": "in_production", "order": { "id": "4822", "external_id": "WEB-10023", "status": "shipped", "shipment": { "tracking_number": "9400111899223456789012", "...": "..." }, "...": "..." } } }

data.order 的结构与 GET /v1/orders/{id} 完全相同——可以复用现有的订单处理代码。

您的服务器需要在 10 秒内返回 2xx 状态码。建议先保存再立即返回 200,之后再处理。

验证签名(强烈建议)

为确认请求确实来自 Inkica(而非有人冒充),每个请求都带有以下请求头:

请求头内容
X-Inkica-Event事件名称
X-Inkica-Delivery本次投递的编号(与内容中的 id 相同)
X-Inkica-Timestamp发送时间(Unix 时间戳,单位为秒)
X-Inkica-Signaturesha256= + 对字符串 {timestamp}.{原始内容} 做 HMAC-SHA256 的结果,密钥为 secret

请基于原始内容(尚未解析 JSON)重新计算签名并比较:

// Node.js (Express) — 使用 express.raw() 以保留原始内容 const crypto = require('crypto'); app.post('/inkica/webhooks', express.raw({ type: 'application/json' }), (req, res) => { const ts = req.get('X-Inkica-Timestamp'); const expected = 'sha256=' + crypto.createHmac('sha256', process.env.INKICA_WEBHOOK_SECRET) .update(`${ts}.${req.body}`).digest('hex'); const got = req.get('X-Inkica-Signature') || ''; const valid = got.length === expected.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected)); if (!valid || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401); const event = JSON.parse(req.body); // ... 保存 event,稍后处理 res.sendStatus(200); });
# Python (Flask) import hmac, hashlib, time from flask import request, abort @app.post("/inkica/webhooks") def inkica_webhook(): ts = request.headers.get("X-Inkica-Timestamp", "") body = request.get_data() # 原始内容(bytes) expected = "sha256=" + hmac.new(SECRET.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, request.headers.get("X-Inkica-Signature", "")) or abs(time.time() - int(ts or 0)) > 300: abort(401) event = request.get_json() return "", 200
// PHP $body = file_get_contents('php://input'); $ts = $_SERVER['HTTP_X_INKICA_TIMESTAMP'] ?? ''; $expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $body, $secret); if (!hash_equals($expected, $_SERVER['HTTP_X_INKICA_SIGNATURE'] ?? '') || abs(time() - (int)$ts) > 300) { http_response_code(401); exit; } $event = json_decode($body, true); http_response_code(200);

另外请检查 X-Inkica-Timestamp 与当前时间相差不超过 5 分钟,以防止有人重放旧请求。

出错时重发

  • 您的服务器没有返回 2xx(出错、超过 10 秒、无法访问)→ Inkica 会在 1、5、15、60 分钟,然后 3、6、12 小时后自动重发——约 1 天内共 8 次。
  • 同一个事件可能会收到不止 1 次,事件也可能乱序到达——请用 id 忽略重复项,并始终以最新的 data.order.status 为准(或调用 GET /v1/orders/{id}),不要假定顺序。
  • 持续出错时间过长(连续 20 次彻底投递失败)→ webhook 会自动停用(active: false)。修复服务器后,在 API 页面(账户菜单)点击 发送测试(或调用 POST /v1/webhooks/{id}/test)——ping 成功后会重新启用。webhook 停用期间发生的变更不会补发——重新启用后,请调用 GET /v1/orders 更新您正在跟踪的订单状态。
  • 您通过控制台创建的订单或来自平台(eBay、Etsy……)的订单也会被通知——如果只关心通过 API 创建的订单,请按 external_id 筛选。

常见错误

出错时,API 会返回 HTTP 状态码,并在 message 中给出说明:

{ "statusCode": 400, "error": "Bad Request", "message": "line_items[0].print_areas: this blueprint has no \"hood\" print position" }
状态码含义处理方法
400提交的数据有误/缺失,或无法执行(钱包余额不足、订单已不能取消……)阅读 message——对于数据校验错误,message 可能是包含多个错误的列表。修正后重新提交。
401缺少令牌、令牌错误或令牌已被吊销检查 Authorization 请求头,必要时创建新令牌。
404未找到(id 错误、属于其他账户的订单,或草稿订单的 id 在提交生产后已被替换)检查 id,或按 external_id 查找。
409external_id 已被某个已提交生产的订单使用该订单已存在——请用 GET /v1/orders?external_id=... 重新找到它,而不是新建。如果确实是另一个订单,请使用不同的 external_id。
429调用过快等待 1 分钟后再继续调用。

限制

  • 每分钟 600 次调用。
  • 每个订单最多 50 个产品行,每个账户最多 10 个令牌。
  • 只能基于 Inkica 目录(按 variant_id)创建订单;在 我的产品 栏目中已创建的产品暂时不能通过 API 直接使用。
  • 每个账户最多 5 个 webhook。
  • 暂无独立的测试环境——请使用 dry_run 在不花钱的情况下检查订单。

◀ 通知 · 目录 · 下一篇:推荐计划 ▶

Last updated on