Developer Center

Open APIs & Webhooks to embed customer service into your systems

API overview: TianKey Cloud provides RESTful APIs and Webhook subscriptions. Third-party system integration is recommended via Open Platform app credentials (X-App-Id / X-App-Secret), created in Console → Open Platform. Admin APIs use JWT login. Base URL is /api; online docs (Swagger): /api/docs.

1. Authentication

Option A: Open Platform app credentials (recommended for third parties)

Create an app in Console → Open Platform to get X-App-Id and X-App-Secret (shown once on creation/reset). Call /api/openapi/* endpoints without a login session:

X-App-Id: ap_xxxxxxxxxxxxxxxx
X-App-Secret: tks_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

Rate limits per app: QPS (default 10/s) + daily quota (default 10,000/day), adjustable in console. Bad credentials return 401, disabled app/company 403, rate-limited 429.

Option B: JWT bearer (admin APIs)

Admins and agents log in to call management APIs; tokens last 12 hours:

Authorization: Bearer <access_token>
POST /api/login
{"username": "admin", "password": "******"}

Roles: superadmin (platform), admin (tenant), agent. All endpoints use HTTPS, return JSON and enforce multi-tenant isolation.

2. AI Chat APIs

POST/api/chat/session

Create a session; returns session_id, welcome message and quick questions. Optional bot_id, channel and user tags. Pass client_id (browser-persisted identifier) and session_id (last session) to resume an unfinished session after a page refresh; the WS connection will backfill the latest 50 messages (reused=true in response).

{
  "source": "app",            // channel: web/wechat/wecom/douyin/app...
  "user_id": "u_10001",       // optional business user ID
  "bot_id": 3,                // optional, route to a specific bot
  "client_id": "c_m7x2k9ab",  // optional, browser-persisted visitor ID for session resume
  "session_id": "a1b2c3d4e5f60708"  // optional, previous session ID to resume history
}
WS/api/ws/chat/{session_id}

Realtime chat WebSocket: messages, intent, typing, human handover and CSAT.

// send
{"type": "message", "content": "Which carrier do you ship with?"}
{"type": "transfer"}                      // request human agent
{"type": "rate", "star": 5, "note": "great"}

// receive
{"type": "message", "sender": "ai", "content": "We ship via SF Express by default"}
{"type": "transfer_result", "status": "waiting"}
{"type": "agent_joined", "agent": "Alice"}

3. Knowledge Base APIs

GET/api/admin/knowledge

Knowledge list (keyword/category/status filters).

POST/api/admin/knowledge

Add a knowledge item with similar phrasings (question newline-separated).

{
  "question": "When will it ship?\nWhen do you dispatch?",
  "answer": "In-stock items ship within 24-48 hours.",
  "category": "Logistics",
  "active": true
}
PUT/api/admin/knowledge/{id} DELETE/api/admin/knowledge/{id}

Update / delete a knowledge item.

POST/api/admin/knowledge/import

CSV bulk import — auto-sync FAQs and product data from business systems.

GET/api/admin/knowledge/miss POST/api/admin/knowledge/miss/{id}/resolve

Unresolved questions / promote one to a knowledge item (drives continuous KB improvement).

4. Analytics APIs

GET/api/analytics/overview?days=7

Tenant dashboard: sessions, AI resolution, CSAT, 24h trend, source distribution.

GET/api/analytics/platform?days=7

Platform overview (superadmin): all-tenant metrics + tenant ranking.

GET/api/analytics/reports

Weekly operations report; POST /api/analytics/reports/generate for on-demand generation.

GET/api/analytics/suggestions POST/api/analytics/suggestions/{id}/apply

KB optimization suggestions / apply one (auto-writes to KB and rebuilds the index).

5. Ticket APIs

POST/api/tickets

Create a ticket (auto-assigned, SLA starts).

GET/api/tickets?status=&priority=&q= PUT/api/tickets/{id}

Ticket list / update status and resolution (with transition history).

POST/api/tickets/from-session/{session_id}

Create a ticket from a chat session in one call.

POST/api/tickets/public-check

Customer self-service ticket progress lookup (public, phone-verified to prevent enumeration).

6. Order Integration

Customers type an order number or phone number and agents/AI instantly query order status, logistics and refund progress — a unified order model hides platform differences. platform: mock (demo) / taobao / jd / pdd / douyin.

POST/api/orders/{platform}/query

Query orders (order_no / phone / name — any one required).

POST /api/orders/mock/query
Authorization: Bearer <token>
{"order_no": "TK202608260001"}
GET/api/orders/{platform}/orders/{order_no}

Order detail (items, amount, status, logistics).

GET/api/orders/{platform}/orders/{order_no}/logistics

Logistics tracking trace.

POST/api/orders/{platform}/refunds

Refund / after-sales progress by order number or phone.

POST/api/orders/{platform}/webhook

Receive platform order message push; returns formatted text for agents/AI.

{"event": "order_status", "order_no": "TK202608260001", "payload": {}}

Live integration: create an app on the platform's open portal (open.taobao.com / open.jd.com / open.pinduoduo.com / openapi-fxg.jinritemai.com), complete merchant authorization, then set credentials via environment variables (TAOBAO_* / JD_* / PDD_* / DOUYIN_*). Without keys, mock demo data is returned. In production keep keys server-side, enable HTTPS and IP-allowlist order endpoints.

7. Open Platform APIs

Call with X-App-Id / X-App-Secret (no login session, rate-limited per app):

POST/api/openapi/orders/query

Order query (same as order APIs, with platform param, default mock).

curl -X POST /api/openapi/orders/query \
  -H "X-App-Id: ap_xxxxxxxx" \
  -H "X-App-Secret: tks_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"order_no": "O202608260001", "platform": "taobao"}'
GET/api/openapi/tickets GET/api/openapi/tickets/{id}

Ticket list (status/priority filters) / detail (read-only).

GET/api/openapi/me

Current app's daily quota usage and limits.

GET/api/openapi/export

Export the OpenAPI spec for third-party endpoints (admin; import straight into Postman/Apifox).

8. Flow Runs & Approval

POST/api/flows/{fid}/debug

Debug-run a flow (may be unpublished): returns step-by-step logs and the final reply — no persistence, no suspension.

GET/api/flows/{fid}/runs GET/api/flows/runs/{run_id}

Flow run records (incl. pending approvals) / single run detail.

POST/api/flows/runs/{run_id}/approve

Approve a suspended approval node: "approve" continues along the approve edge, "reject" along the reject edge (or default); the final reply is pushed to the customer.

{"decision": "approve", "note": "Approved"}

9. Audit Logs

All console write operations (POST/PUT/DELETE/PATCH) are automatically logged with operator, role, module, action, path and source IP. Logs are append-only and cannot be deleted; request bodies are never stored (avoids sensitive data), meeting GB/T 47746-2026 audit requirements.

GET/api/audit/logs?module=&action=&username=&page=1&page_size=50

Query audit logs (admin: own tenant; superadmin: all tenants). Filter by module, action (create/update/delete), operator and time.

10. Webhook Events

Configure your callback URL in console (POST /api/webhooks to create, POST /api/webhooks/{id}/test to send a test event, GET /api/webhooks/logs for delivery logs). Events are pushed with signature verification:

EventDescription
session.createdNew session created
message.receivedCustomer message received
message.ai_repliedAI replied
transfer.createdHuman handover triggered (with reason)
ticket.created / updatedTicket created / updated
rating.submittedCSAT submitted
knowledge.missUnresolved question (drives KB optimization)

Signature: X-TianKey-Signature = HMAC-SHA256(Webhook Secret, raw body). Verify before processing.

11. Quick Start

Python: query an order with Open Platform credentials

import requests

API = "https://<your-domain>/api"

resp = requests.post(f"{API}/openapi/orders/query",
    headers={"X-App-Id": "ap_xxx", "X-App-Secret": "tks_xxx"},
    json={"order_no": "TK202608260001", "platform": "mock"})

print(resp.json()["count"])   # matched orders
print(resp.json()["items"])   # order list

JavaScript: webhook verification

const crypto = require("crypto");
// verify incoming callbacks
const sig = crypto
  .createHmac("sha256", process.env.WEBHOOK_SECRET)
  .update(rawBody)
  .digest("hex");
if (req.headers["x-tiankey-signature"] !== sig) return res.status(401).end();
// handle event…

12. Web Embedding (widget.js / iframe)

Besides the backend APIs, the web channel ships in two forms: a floating widget (launcher button + popup, full-screen on mobile) and an iframe embed (drop the full chat window into any page area). Both snippets are generated for you in the console: Channels → Web → Embed code (with a source tag) or Settings → Widget Settings → Copy embed code.

Option 1: Floating widget (recommended)

Paste before </body> (domain and tenant ID are filled in by the console):

<script src="https://<your-domain>/widget.js"></script>
<script>
  window.TKC_CONFIG = {
    chatUrl: "https://<your-domain>/chat?company=1",
    companyId: 1,   // tenant ID; falls back to the company param on chatUrl
    // Optional overrides (omit to follow Console → Widget Settings). Trailing commas are in place — just uncomment:
    // accentColor: "#2563eb",          // launcher theme color
    // bgColor:     "#ffffff",          // window background; "transparent" shows the page behind
    // position:    "bottom-right",     // bottom-right | bottom-left | top-right | top-left
    // offsetX: 24, offsetY: 24,        // distance from edges in px (0-200)
    // logo: "🤖",                       // launcher icon: emoji/text or image URL
    // bubbleText: "Chat with us",      // launcher tooltip
    // autoOpen: 0                      // auto-open delay in ms; 0 = disabled
  };
</script>

Precedence: explicit values in code > settings from Console → Widget Settings. To keep colors, icon and position fully controlled by the console, leave those lines commented out — once a value is set in code, console changes no longer apply.

KeyExampleDescription
chatUrl"https://domain/chat"Chat page URL (required); pass company and source params
companyId1Tenant ID used to load Widget Settings and to attribute sessions
configUrl"/api/chat/widget-config"Config endpoint; derived from chatUrl by default
accentColor"#2563eb"Launcher theme color (overrides console setting)
bgColor"#ffffff"Window background; "transparent" shows the page behind
position"bottom-right"bottom-right / bottom-left / top-right / top-left (right, left also accepted)
offsetX / offsetY24Horizontal / vertical margin from edges in px (0-200)
logo"🤖"Launcher icon: emoji / short text or image URL; empty = built-in
bubbleText"Chat with us"Launcher hover tooltip
autoOpen2500Auto-open delay in ms; 0 or omitted = disabled

Option 2: iframe embed

<iframe
  src="https://<your-domain>/chat?source=Website&company=1&embed=1&transparent=1"
  title="Live chat"
  allow="microphone; camera; autoplay; fullscreen"
  allowtransparency="true"
  style="width:100%;height:600px;min-height:320px;border:0;"></iframe>

Never drop microphone; camera from allow: cross-origin iframes have no media permission by default, so voice messages and photo uploads will fail without it. embed=1 makes the chat card fill the iframe (no padding or rounding) and transparent=1 lets the host page show through. Adjust the height to your layout (keep it ≥320px and the container ≥360px wide).

/chat URL parameters

Append them to chatUrl or the iframe src (first parameter after ?, the rest joined with &). Percent-encode non-ASCII values and # (write %23):

ParameterExampleDescription
companycompany=1Tenant ID (multi-tenant isolation); defaults to the backend default tenant
sourcesource=WebsiteChannel tag shown to agents; defaults to the current page URL
titletitle=SalesWindow title; defaults to the system title
customer_namecustomer_name=JohnPrefilled visitor name
customer_phonecustomer_phone=+8613800000000Prefilled phone for agent callbacks
bgbg=%23ffffffPage background color; bg=transparent for full transparency
transparenttransparent=1Transparent background showing the host page; 0 = system gradient
embedembed=1Chat card fills the iframe; 0 = centered card
phone_verifyphone_verify=00 = no persistent lead form, ask only on "Talk to human"; 1 = always (default)
bot_idbot_id=2Pin a specific bot; otherwise routed by channel and keywords
utm_source / utm_medium / utm_campaignutm_source=googleCampaign attribution stored with the session

Troubleshooting

  • Sessions land in the wrong tenant (multi-tenant): make sure companyId or the company param on chatUrl is set; without either, sessions fall back to the default tenant.
  • Voice or photo upload broken inside the page: the iframe is missing allow="microphone; camera". The floating widget handles this itself.
  • Console color/icon changes have no effect: check whether the snippet hard-codes accentColor — explicit values override console settings, so remove the line.
  • Launcher hidden behind page elements: check for higher z-index elements or overflow: hidden containers on the host page; adjust position and offsetX/offsetY if needed.
📖 Full Swagger/OpenAPI docs are online at /api/docs; see section 12 for web embedding. Manage app secrets, quotas and OpenAPI export in Console → Open Platform. Developer Membership adds sandbox, higher QPS and dedicated support. Apply →