Open APIs & Webhooks to embed customer service into your systems
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.
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.
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.
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
}
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"}
Knowledge list (keyword/category/status filters).
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
}
Update / delete a knowledge item.
CSV bulk import — auto-sync FAQs and product data from business systems.
Unresolved questions / promote one to a knowledge item (drives continuous KB improvement).
Tenant dashboard: sessions, AI resolution, CSAT, 24h trend, source distribution.
Platform overview (superadmin): all-tenant metrics + tenant ranking.
Weekly operations report; POST /api/analytics/reports/generate for on-demand generation.
KB optimization suggestions / apply one (auto-writes to KB and rebuilds the index).
Create a ticket (auto-assigned, SLA starts).
Ticket list / update status and resolution (with transition history).
Create a ticket from a chat session in one call.
Customer self-service ticket progress lookup (public, phone-verified to prevent enumeration).
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.
Query orders (order_no / phone / name — any one required).
POST /api/orders/mock/query
Authorization: Bearer <token>
{"order_no": "TK202608260001"}
Order detail (items, amount, status, logistics).
Logistics tracking trace.
Refund / after-sales progress by order number or phone.
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.
Call with X-App-Id / X-App-Secret (no login session, rate-limited per app):
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"}'
Ticket list (status/priority filters) / detail (read-only).
Current app's daily quota usage and limits.
Export the OpenAPI spec for third-party endpoints (admin; import straight into Postman/Apifox).
Debug-run a flow (may be unpublished): returns step-by-step logs and the final reply — no persistence, no suspension.
Flow run records (incl. pending approvals) / single run detail.
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"}
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.
Query audit logs (admin: own tenant; superadmin: all tenants). Filter by module, action (create/update/delete), operator and time.
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:
| Event | Description |
|---|---|
session.created | New session created |
message.received | Customer message received |
message.ai_replied | AI replied |
transfer.created | Human handover triggered (with reason) |
ticket.created / updated | Ticket created / updated |
rating.submitted | CSAT submitted |
knowledge.miss | Unresolved question (drives KB optimization) |
Signature: X-TianKey-Signature = HMAC-SHA256(Webhook Secret, raw body). Verify before processing.
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…
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.
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.
| Key | Example | Description |
|---|---|---|
chatUrl | "https://domain/chat" | Chat page URL (required); pass company and source params |
companyId | 1 | Tenant 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 / offsetY | 24 | Horizontal / 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 |
autoOpen | 2500 | Auto-open delay in ms; 0 or omitted = disabled |
<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).
Append them to chatUrl or the iframe src (first parameter after ?, the rest joined with &). Percent-encode non-ASCII values and # (write %23):
| Parameter | Example | Description |
|---|---|---|
company | company=1 | Tenant ID (multi-tenant isolation); defaults to the backend default tenant |
source | source=Website | Channel tag shown to agents; defaults to the current page URL |
title | title=Sales | Window title; defaults to the system title |
customer_name | customer_name=John | Prefilled visitor name |
customer_phone | customer_phone=+8613800000000 | Prefilled phone for agent callbacks |
bg | bg=%23ffffff | Page background color; bg=transparent for full transparency |
transparent | transparent=1 | Transparent background showing the host page; 0 = system gradient |
embed | embed=1 | Chat card fills the iframe; 0 = centered card |
phone_verify | phone_verify=0 | 0 = no persistent lead form, ask only on "Talk to human"; 1 = always (default) |
bot_id | bot_id=2 | Pin a specific bot; otherwise routed by channel and keywords |
utm_source / utm_medium / utm_campaign | utm_source=google | Campaign attribution stored with the session |
companyId or the company param on chatUrl is set; without either, sessions fall back to the default tenant.allow="microphone; camera". The floating widget handles this itself.accentColor — explicit values override console settings, so remove the line.z-index elements or overflow: hidden containers on the host page; adjust position and offsetX/offsetY if needed./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 →