API công khai và SDK¶
Về HTTP và stream của chat công khai, xem Chat API và Xác thực bên thứ ba. Helper SDK trên trang này mô tả workflow và chat headless. Phần chat đã có trong mã nguồn, chờ đợt phát hành package tiếp theo được chủ dự án duyệt.
Dịch vụ khác khởi chạy workflow qua HTTP bằng token của workflow, rồi hỏi lại (poll) để lấy kết quả. Trang này mô tả hai endpoint công khai, SDK chính thức cho Python và TypeScript, và các lỗi cần xử lý. Callback, chữ ký và lịch sử gửi webhook nằm ở API trigger và webhook. Mọi trường đều có trong Tham chiếu API công khai.
Khái niệm¶
| Thuật ngữ | Nghĩa |
|---|---|
| Token của workflow | Secret wft_... chỉ khởi chạy được run của một workflow. Gửi dưới dạng X-Workflow-Token: wft_... hoặc Authorization: Bearer wft_.... Ngoài các endpoint này, token chỉ dùng được với API tương thích LangGraph và MCP server của cùng workflow. |
| Run | Một lần thực thi phiên bản đã lưu mới nhất của workflow. input là state ban đầu. |
| Trạng thái | queued và running khi đang chạy; sau đó là ok, error, cancelled, timeout, waiting (dừng ở node Human) hoặc expired. |
| Envelope | Mọi phản hồi đều có dạng {"success", "data", "error"}. Khi lỗi, error.code là mã ổn định; error.message là tiếng Anh, dùng cho log. |
| Phương thức và đường dẫn | Operation | Mục đích |
|---|---|---|
POST /api/hooks/workflows/{wid}/runs |
startRun |
Khởi chạy run. Trả 202 kèm poll_url và header Location, hoặc 200 kèm kết quả ở chế độ sync. |
GET /api/hooks/workflows/{wid}/runs/{run_id} |
getRun |
Trạng thái, và khi đã xong thì có final_state, error, metrics. |
Tạo token¶
- Mở workflow trong trình soạn thảo và lưu lại.
- Mở ⋯ → API, nhập tên rồi chọn Tạo token.
- Sao chép token (
wft_...) và secret ký (whsec_...). Mỗi thứ chỉ hiện một lần; hãy cất vào nơi quản lý secret của bạn.

Chỉ chủ workflow hoặc admin mới tạo được token. Thu hồi token ngay trong hộp
thoại này; sau đó mọi request dùng token đó bị từ chối với
401 TRIGGER_TOKEN_INVALID. Mã workflow (wid) là phần cuối của URL trình
soạn thảo.
Khởi chạy run¶
Phản hồi là 202 Accepted:
{
"success": true,
"data": {"run_id": "3f9c2a1b7d", "status": "queued",
"poll_url": "https://superstep.example.com/api/hooks/workflows/example/runs/3f9c2a1b7d"},
"error": null
}
| Trường trong body | Nghĩa |
|---|---|
input |
State ban đầu, một JSON object (mặc định {}). |
mode |
async (mặc định) trả lời ngay. sync chờ tối đa STUDIO_SYNC_WAIT_MAX giây (mặc định 30) rồi trả 200 kèm kết quả; nếu run vẫn đang chạy thì trả 202 kèm kết quả hiện tại và poll_url. |
callback_url |
Tuỳ chọn. URL công khai nhận kết quả khi run kết thúc. Xem Xác minh callback. |
Lấy kết quả¶
{
"success": true,
"data": {
"run_id": "3f9c2a1b7d", "workflow_id": "example", "status": "ok", "source": "api",
"final_state": {"intent": "order_status"}, "error": null, "waiting": null,
"metrics": {"duration_ms": 412.0, "tokens_in": 0, "tokens_out": 0, "cost_usd": 0.0, "error_count": 0},
"trace_url": null, "started": 1761292800.0, "ended": 1761292800.4
},
"error": null
}
Hỏi lại mỗi một hoặc hai giây và giãn dần với run dài; việc poll không bị
giới hạn tần suất. Run kết thúc ở error có lỗi của node hỏng trong error;
run ở waiting ghi tên node Human và prompt của nó trong waiting.
Run đang chờ run được gọi của một công cụ workflow
thì có waiting.child_run_id, còn run được gọi có parent_run_id.
Chạy và chờ¶
run_and_wait (Python) và runAndWait (TypeScript) khởi chạy run rồi poll
đến khi xong. Khoảng chờ bắt đầu từ 1 giây, mỗi lần tăng 1,5 lần, tối đa 10
giây. Hàm trả về run bất kể trạng thái cuối, nên hãy kiểm tra status; quá
timeout thì báo WaitTimeoutError kèm trạng thái cuối cùng đã thấy.
from superstep import Client, WaitTimeoutError
client = Client() # SUPERSTEP_WORKFLOW_ID, SUPERSTEP_TOKEN, SUPERSTEP_BASE_URL
try:
run = client.run_and_wait({"message": "hi"}, timeout=120, poll_interval=0.5)
except WaitTimeoutError as err:
print("still", err.run.status)
else:
print(run.status, run.final_state)
AsyncClient có cùng các phương thức, dạng coroutine:
import { Superstep } from '@superstep/sdk'
const client = new Superstep() // SUPERSTEP_WORKFLOW_ID, SUPERSTEP_TOKEN, SUPERSTEP_BASE_URL
const run = await client.runAndWait(
{ message: 'hi' },
{ timeoutMs: 120_000, pollIntervalMs: 500, signal: AbortSignal.timeout(130_000) },
)
console.log(run.status, run.final_state)
Cài SDK¶
| Ngôn ngữ | Cài đặt | Mã nguồn |
|---|---|---|
| Python 3.9+ | pip install superstep |
sdk/python |
| TypeScript, Node 18+ | npm install @superstep/sdk |
sdk/typescript |
Cả hai đọc SUPERSTEP_BASE_URL, SUPERSTEP_TOKEN và SUPERSTEP_WORKFLOW_ID
khi bạn không truyền tuỳ chọn tương ứng. Trước bản phát hành đầu tiên, cài từ
mã nguồn: pip install ./sdk/python hoặc npm install ./sdk/typescript.
Chat headless¶
TypeScript dùng new Superstep({baseUrl}).chat(slug, {getToken}); Python dùng
Client(base_url=...).chat(slug, token=...) hoặc AsyncClient. Client đọc
session/lịch sử, stream sự kiện và kết quả cuối, trả lời Human bằng văn bản
hoặc object biểu mẫu, upload tệp và đánh giá phản hồi. Backend của bạn ký
token user ngắn hạn bằng mintChatToken từ @superstep/sdk/server hoặc
mint_chat_token của Python; secret app key chỉ nằm trên backend đó.
Với mã nguồn hiện tại, build TypeScript SDK trước khi dùng package local;
cài Python bằng pip install './sdk/python[chat]' để có socket. Xem
README TypeScript
và README Python
về callback làm mới token, huỷ chủ động và khôi phục lịch sử có giới hạn,
không tự gửi lại tin nhắn khi kết quả ghi chưa rõ.
Ví dụ chat host chạy Node trên loopback, khác origin với studio; session do host quản lý, hai khách hàng, biểu mẫu xác nhận Human, tệp, đánh giá và thu hồi key. Ví dụ có trang SDK headless, bộ giao diện React và widget dùng chung endpoint cấp token có bảo vệ. Đây là đăng nhập mẫu local; thay phần mẫu trước khi triển khai hệ thống tài khoản. CI lưu screenshot dưới dạng artifact tải về, không đưa ảnh vào Git.
TypeScript hướng tới SDK 0.2.0. Python giữ version chung với CLI/server đến đợt release được duyệt tiếp theo, không hạ version xuống 0.2.0. Publish package và tạo release tag cần chủ dự án duyệt riêng.
Lỗi¶
Lỗi dùng envelope và một code ổn định:
{"success": false, "data": null,
"error": {"code": "TRIGGER_TOKEN_INVALID", "message": "Missing, invalid or revoked workflow token", "details": null}}
| HTTP | Mã | Nguyên nhân | Lỗi trong Python / TypeScript |
|---|---|---|---|
| 401 | TRIGGER_TOKEN_INVALID |
Thiếu token, sai, đã thu hồi, hoặc token của workflow khác | AuthenticationError |
| 404 | RUN_NOT_FOUND |
Run không tồn tại, hoặc thuộc workflow khác | NotFoundError |
| 400 | RUN_INPUT_INVALID |
input không phải JSON object |
InvalidRequestError |
| 400 | CALLBACK_URL_INVALID |
callback_url không phải URL http(s) công khai |
InvalidRequestError |
| 422 | VALIDATION_ERROR |
Body sai dạng; details liệt kê {field, message} |
InvalidRequestError |
| 413 | RUN_INPUT_TOO_LARGE |
input vượt STUDIO_INPUT_MAX_BYTES (mặc định 256 KB) |
PayloadTooLargeError |
| 429 | RATE_LIMITED |
Token này khởi chạy quá nhiều run | RateLimitError (retry_after / retryAfter) |
| 500 | INTERNAL_ERROR |
Lỗi máy chủ | ServerError |
SDK còn có APIConnectionError (lỗi mạng, hoặc phản hồi không phải
envelope), WaitTimeoutError và ConfigError. Toàn bộ mã lỗi nằm ở
Mã lỗi.
Giới hạn tần suất¶
Mỗi token được khởi chạy STUDIO_TRIGGER_RATE_LIMIT run trong mỗi
STUDIO_TRIGGER_RATE_WINDOW giây (mặc định 60 run mỗi 60 giây). Vượt giới hạn
thì nhận 429 RATE_LIMITED kèm header Retry-After tính bằng giây. Việc poll
không bị giới hạn. Có Redis thì mọi process API dùng chung bộ đếm; không có
Redis thì mỗi process đếm riêng.
OpenAPI¶
Các endpoint công khai có spec riêng, không kèm API nội bộ của studio:
| Ở đâu | Nội dung |
|---|---|
/openapi.public.json trên máy chủ đang chạy |
Spec công khai |
/docs/public trên máy chủ đang chạy |
Swagger UI cho spec công khai |
docs/api/openapi.public.json trong repository |
Bản đã commit, nguồn để sinh SDK |
| Tham chiếu API công khai | Spec hiển thị ngay trong handbook |
Bạn có thể sinh client cho ngôn ngữ khác từ file đó bằng bất kỳ công cụ sinh OpenAPI nào.