CTAS Work API — v1 (bản nháp tài liệu cho developer.ctas.vn/docs/ctas-work)
Trạng thái: bản nháp 2, 06/09/2026, chưa phát hành. Nguồn sự thật khi phát hành là file OpenAPIctas-api/docs/openapi/work.v1.yaml; tài liệu này là phần *hướng dẫn* bao quanh. Phiên bản API mô tả ở đây:2026-09-01.
1. Giới thiệu
CTAS Work là hệ thống chấm công, lịch làm việc, nhân sự và lương cho doanh nghiệp. API cho phép phần mềm của bạn (POS, ERP, kế toán, máy chấm công…) đọc và ghi dữ liệu của các tổ chức đã kết nối với ứng dụng của bạn trên CTAS Work, và nhận thông báo khi có thay đổi.
Hai cách dùng, cùng một API:
| Ứng dụng nội bộ | Ứng dụng nền tảng | |
|---|---|---|
| Bạn là | doanh nghiệp tự tích hợp hệ thống của mình với CTAS Work | nhà cung cấp phần mềm có nhiều khách hàng dùng CTAS Work |
| Kết nối tới | chính tổ chức của bạn | mọi tổ chức đồng ý kết nối, mỗi tổ chức một kết nối |
| Cần duyệt | không | có, trước khi kết nối tổ chức ngoài tổ chức của bạn |
Bạn có thể:
- Đọc phòng ban, chức danh, nhân sự; tạo và cập nhật nhân sự.
- Đọc chấm công và lịch làm việc theo khoảng ngày.
- Định danh nhân sự bằng mã QR: phần mềm của bạn hiện mã QR, nhân viên quét bằng ứng dụng CTAS Work, bạn nhận về mã nhân sự của người đó — không cần tự dựng đăng nhập cho nhân viên.
- Kích hoạt lượt việc trong Quy trình kèm dữ liệu mồi sẵn.
- Nhận webhook có chữ ký cho mọi sự kiện trên.
Điều kiện
Sandbox (client test) | Production (client live) | |
|---|---|---|
| Tài khoản CTAS tạo ứng dụng là quản trị viên của một tổ chức | ✔ | ✔ |
| Tổ chức được kết nối ở gói Doanh nghiệp (Enterprise) | không cần | bắt buộc |
| Ứng dụng nền tảng đã được CTAS duyệt phát hành | không cần | bắt buộc để kết nối tổ chức khác |
| Dữ liệu | tổ chức sandbox, tạo bao nhiêu cũng được, reset được | tổ chức thật |
| Trần mặc định | 300/phút/ứng dụng · 60/phút/kết nối | 3 000/phút/ứng dụng · 600/phút/kết nối |
2. Bắt đầu trong 10 phút
- Đăng nhập developer.ctas.vn bằng tài khoản CTAS → chọn tổ chức → Tạo ứng dụng → sản phẩm CTAS Work, loại *nội bộ* hoặc *nền tảng*, chọn scope xin.
- Tab Thông tin xác thực › Test: sao chép
client_id(ctas_ci_test_…) vàclient_secret(ctas_cs_test_…). Secret hiện một lần. - Tab Sandbox › Tạo tổ chức sandbox → nhận một tổ chức giả (3 phòng ban, 12 nhân sự, 30 ngày chấm công). Bấm Tạo mã kết nối ngay tại đó →
CTAS-7K2M-9Q4D. - Đổi mã lấy token:
curl -X POST https://api.ctas.vn/api/developer/oauth/token \
-H "Content-Type: application/json" \
-d '{
"grant_type": "urn:ctas:params:oauth:grant-type:connection_code",
"code": "CTAS-7K2M-9Q4D",
"client_id": "ctas_ci_test_…",
"client_secret": "ctas_cs_test_…"
}'
{
"access_token": "ctas_at_…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "ctas_rt_…",
"scope": "organization:read members:read identity:write",
"connection": { "id": "con_…", "organization_id": "org_…", "environment": "test" }
}
- Gọi thử:
curl https://api.ctas.vn/api/developer/v1/work/organization \
-H "Authorization: Bearer ctas_at_…"
- Mở docs khi đang đăng nhập: khung Thử ngay cạnh mỗi endpoint đã gắn sẵn token test của kết nối sandbox.
3. Xác thực
3.1 Ba loại chứng thư
| Là gì | Sống | Dùng ở đâu | |
|---|---|---|---|
client_id + client_secret | danh tính ứng dụng của bạn, mỗi môi trường một cặp | cho đến khi xoay | chỉ trong POST /oauth/token, chỉ từ backend |
Access token ctas_at_… | vé gọi API, gắn với một kết nối (một tổ chức) hoặc với ứng dụng | 1 giờ | header Authorization: Bearer |
Refresh token ctas_rt_… | lấy access token mới cho kết nối đó | 90 ngày, gia hạn mỗi lần dùng | chỉ trong POST /oauth/token |
Không bao giờ dùng client_secret hay refresh token ở ứng dụng di động, mã chạy trên trình duyệt, hay commit vào git. Tiền tố ctas_cs_ / ctas_rt_ được công cụ quét bí mật nhận diện.
3.2 Kết nối là gì
Một kết nối (con_…) là sự cho phép của một tổ chức cho ứng dụng của bạn, với một tập scope, ở một môi trường. Quản trị viên tổ chức cấp nó, và có thể thu hồi bất cứ lúc nào trong ứng dụng CTAS Work. Mọi access token đọc dữ liệu tổ chức đều thuộc về đúng một kết nối, nên phần mềm của bạn phục vụ nhiều khách hàng phải giữ một cặp token cho mỗi kết nối.
Mọi response dữ liệu tổ chức kèm header X-CTAS-Connection và X-CTAS-Organization — hãy đối chiếu trước khi ghi vào CSDL của khách.
3.3 Cách một tổ chức kết nối với ứng dụng của bạn
Cách A — Mã kết nối (khuyến nghị). Quản trị viên mở CTAS Work › Tổ chức › Tích hợp › Kết nối ứng dụng, chọn ứng dụng của bạn (hoặc nhập mã app_… bạn đưa), xem scope, bấm Tạo mã kết nối. Họ nhận một mã dạng CTAS-7K2M-9Q4D, hiệu lực 10 phút, dùng một lần. Phần mềm của bạn cho họ dán mã vào, backend của bạn đổi mã lấy token (mục 3.4). Mã chỉ đổi được bằng client_secret của đúng ứng dụng đó.
Cách B — Uỷ quyền qua web (OAuth authorization code + PKCE). Phần mềm của bạn đưa quản trị viên tới:
https://developer.ctas.vn/oauth/authorize
?client_id=ctas_ci_live_…
&redirect_uri=https://app.example.com/ctas/callback
&scope=organization:read%20members:read
&state=…&code_challenge=…&code_challenge_method=S256
Họ đăng nhập, chọn tổ chức (chỉ nơi họ là quản trị viên và đủ gói), đồng ý, và được đưa về redirect_uri?code=…&state=…. redirect_uri phải khớp tuyệt đối một URL đã đăng ký trong console. Đổi code lấy token với grant_type=authorization_code + code_verifier.
Cả hai cách tạo ra cùng một kết nối; sự kiện connection.created được gửi tới webhook của bạn kèm organization_id.
3.4 POST /oauth/token
Nhận JSON hoặc application/x-www-form-urlencoded. Trả lời theo RFC 6749.
grant_type | Tham số | Trả về |
|---|---|---|
client_credentials | client_id, client_secret, scope? | token ứng dụng (ứng dụng nền tảng: chỉ gọi /connections, /webhooks, /events) — hoặc token kết nối duy nhất (ứng dụng nội bộ) |
urn:ctas:params:oauth:grant-type:connection_code | code, client_id, client_secret | token kết nối + refresh token |
authorization_code | code, code_verifier, redirect_uri, client_id, client_secret | token kết nối + refresh token |
refresh_token | refresh_token, client_id, client_secret, scope? (chỉ được hẹp hơn) | cặp token mới; refresh token cũ hết hiệu lực sau 60 giây |
Lỗi: {"error":"invalid_client"|"invalid_grant"|"invalid_scope"|"unsupported_grant_type", "error_description":"…"} với HTTP 400/401. Mọi thất bại xác thực client trả cùng invalid_client.
3.5 Vòng đời token — bạn phải xử lý
gọi API → 401 TOKEN_EXPIRED
→ POST /oauth/token grant_type=refresh_token
→ 200: lưu CẢ HAI token mới, gọi lại
→ 400 invalid_grant: kết nối đã bị thu hồi, hết hạn, hoặc refresh token đã bị dùng
→ đánh dấu kết nối đứt, yêu cầu quản trị viên cấp mã kết nối lại
- Refresh token dùng một lần. Cái cũ còn được chấp nhận trong 60 giây để hai tiến trình cùng refresh không đá nhau; sau đó, dùng lại refresh token cũ bị coi là rò rỉ: toàn bộ token của kết nối bị thu hồi và bạn nhận
connection.compromised. Hãy khoá (mutex) thao tác refresh theo kết nối phía bạn. - Chủ động refresh khi còn dưới 5 phút thay vì chờ 401.
POST /oauth/revoke{ "token": "…" }khi khách hàng ngừng dùng phần mềm của bạn.POST /oauth/introspect{ "token": "…" }→{ "active": true, "scope": "…", "connection_id": "con_…", "organization_id": "org_…", "expires_at": "…" }— để debug.
3.6 Scope
| Scope | Cho phép |
|---|---|
organization:read | tổ chức, phòng ban, chức danh |
members:read | danh sách và chi tiết nhân sự (không lương, không giấy tờ) |
members:write | tạo, cập nhật, cho nghỉ nhân sự; cấp mã kích hoạt |
members:salary | thêm các trường lương cơ bản vào nhân sự |
attendance:read | chấm công, lịch làm việc |
leave:read / leave:write | đơn nghỉ và duyệt/từ chối |
process:read / process:write | biểu mẫu, phân công, phiếu; kích hoạt lượt việc |
identity:write | tạo và theo dõi yêu cầu định danh QR |
webhooks:manage | quản lý webhook bằng API (token ứng dụng) |
Scope xin khi phát hành ≥ scope tổ chức cấp khi kết nối ≥ scope trong token. Xin members:salary khi phát hành phải giải thích lý do.
Không scope nào trả về: giấy tờ tuỳ thân, địa chỉ thường trú, tài khoản ngân hàng, mã số thuế cá nhân, phiếu lương, email/số điện thoại đăng nhập, id người dùng CTAS.
4. Quy ước
4.1 Base URL và phiên bản
https://api.ctas.vn/api/developer/oauth/… xác thực
https://api.ctas.vn/api/developer/v1/… token ứng dụng: /app, /connections, /webhooks, /events
https://api.ctas.vn/api/developer/v1/work/… token kết nối: dữ liệu tổ chức
v1là phiên bản lớn. Mỗi ứng dụng ghim một ngàyapi_version(ví dụ2026-09-01) lúc tạo; mọi response mangX-CTAS-Api-Version.- Thêm trường/enum/endpoint: không đổi ngày, không phá vỡ — hãy bỏ qua trường lạ.
- Xoá trường, đổi nghĩa: ra ngày mới; ứng dụng cũ giữ nguyên hành vi đến khi bạn đổi trong console. Ngày sắp ngừng có header
DeprecationvàSunsettrước ≥ 90 ngày.
4.2 Mã định danh
| Tiền tố | Đối tượng |
|---|---|
app_ | ứng dụng |
con_ | kết nối |
org_ | tổ chức |
dep_ / pos_ | phòng ban / chức danh |
mem_ | nhân sự — một người trong một tổ chức |
idr_ | yêu cầu định danh QR |
whk_ / dlv_ / evt_ | webhook / lần giao / sự kiện |
mem_ là mã theo tổ chức: cùng một người ở hai tổ chức có hai mã khác nhau, không suy ra được tài khoản CTAS. Đây là mã bạn nên lưu.
4.3 Định dạng dữ liệu
| Loại | Định dạng |
|---|---|
| ngày | YYYY-MM-DD |
| ngày-giờ | ISO-8601 có múi giờ |
| giờ trong ca | HH:mm |
| tiền | số nguyên theo currency_code của tổ chức |
| ngày công / phép | số thực 1 chữ số lẻ |
Body application/json, tối đa 1 MB. Trường không có trong tài liệu — cả trong body lẫn query — → 422 UNKNOWN_FIELD kèm details.unknown_fields (cố ý, để deparment= không lặng lẽ trả về danh sách chưa lọc).
4.4 Phân trang
GET /members?limit=50 → { "data": [...], "meta": { "next_cursor": "…", "has_more": true } }
GET /members?limit=50&cursor=…
limit 1–100 (mặc định 50); next_cursor null khi hết; con trỏ sống 24 giờ.
4.5 Lỗi (API dữ liệu)
{ "error": { "code": "INSUFFICIENT_SCOPE", "message": "…", "retryable": false,
"details": { "required_scope": "members:write" }, "request_id": "req_…" } }
| HTTP | code | Ý nghĩa | Thử lại? |
|---|---|---|---|
| 401 | INVALID_TOKEN | token sai hoặc đã thu hồi | không |
| 401 | TOKEN_EXPIRED | hết hạn → refresh | sau khi refresh |
| 403 | INSUFFICIENT_SCOPE | thiếu scope | không |
| 403 | CONNECTION_REQUIRED | dùng token ứng dụng cho endpoint tổ chức | không |
| 403 | CONNECTION_REVOKED | tổ chức đã ngắt kết nối | không |
| 403 | PLAN_REQUIRED | tổ chức không còn ở gói Doanh nghiệp (kết nối được giữ) | khi họ mua lại |
| 404 | NOT_FOUND | không có, hoặc thuộc tổ chức khác | không |
| 409 | CONFLICT / IDEMPOTENCY_IN_FLIGHT | tuỳ | |
| 422 | VALIDATION_FAILED / UNKNOWN_FIELD | không | |
| 429 | RATE_LIMITED | xem Retry-After | có |
| 5xx | INTERNAL | có, backoff |
4.6 Idempotency
Idempotency-Key: <uuid> với mọi POST/PATCH/DELETE; cùng key + cùng kết nối trong 24 giờ → trả lại response cũ kèm Idempotent-Replay: true.
4.7 Giới hạn tốc độ
Hai tầng: theo ứng dụng và theo kết nối; header phản ánh tầng chặt hơn:
X-RateLimit-Scope: connection
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 597
X-RateLimit-Reset: 1757127660
/oauth/token giới hạn 10 lần/phút/client. Vượt → 429 + Retry-After.
5. Tài nguyên — token ứng dụng
GET /app
GET /connections?status=active|revoked&cursor=
GET /connections/{id} DELETE /connections/{id} (chủ động ngắt)
GET /webhooks POST /webhooks DELETE /webhooks/{id} POST /webhooks/{id}/rotate POST /webhooks/{id}/test
GET /events?since=&connection=&cursor=
{ "id": "con_…", "organization_id": "org_…", "organization_name": "Công ty ABC",
"environment": "live", "scopes": ["organization:read", "members:read"],
"status": "active", "granted_at": "…", "last_used_at": "…" }
Ứng dụng nội bộ cũng gọi được các endpoint này bằng token kết nối duy nhất của mình.
6. Tài nguyên — token kết nối (/v1/work)
6.1 Tổ chức
GET /organization — organization:read
{ "data": { "id": "org_…", "name": "Công ty ABC", "environment": "live",
"currency_code": "VND", "timezone": "Asia/Ho_Chi_Minh",
"pay_cycle": "monthly", "cutoff_day": 25, "payday": 5 } }
6.2 Phòng ban & chức danh
GET /departments · GET /departments/{id} · GET /positions
{ "id": "dep_…", "name": "Cửa hàng Quận 1", "kind": "store", "address": "…",
"lat": 10.77, "lng": 106.70, "radius_m": 100, "lead_member_id": "mem_…" }
6.3 Nhân sự
GET /members?department=&status=active|paused|left&q=&limit=&cursor=
GET /members/{id}
POST /members PATCH /members/{id}
POST /members/{id}/deactivate POST /members/{id}/activation-code
{ "id": "mem_Kd7p…", "name": "Nguyễn Văn A", "department_id": "dep_…",
"position_id": "pos_…", "position": "Thu ngân", "role": "staff", "status": "active",
"join_date": "2026-03-01", "awaits_activation": false, "created_at": "…", "updated_at": "…" }
Với members:salary thêm base_salary, salary_basis (month|day|hour), rate.
Tạo — POST /members (members:write): name, phone (khoá nhận diện tài khoản), department_id, position_id, role, join_date, base_salary, salary_basis. Người chưa có tài khoản CTAS được tạo ở trạng thái chờ kích hoạt và response có meta.activation_code để bạn chuyển cho nhân viên. Vượt trần gói → 403 PLAN_LIMIT (details.limit = "max_active_members"). Trùng số điện thoại trong tổ chức → 409. Không tạo được quản trị viên qua API.
Cho nghỉ — POST /members/{id}/deactivate { "effective_date", "reason" } → status: left. CTAS Work không xoá hồ sơ nhân sự (lương và chấm công phải giữ), nên không có DELETE.
6.4 Chấm công & lịch
GET /attendance?from=&to=&member=&department=&limit=&cursor= (tối đa 92 ngày)
GET /schedule?member=&from=&to= (một nhân sự, tối đa 92 ngày)
{ "id": "…", "member_id": "mem_…", "department_id": "dep_…", "date": "2026-09-06",
"status": "late",
"check_in": "2026-09-06T08:12:00+07:00", "check_out": "2026-09-06T17:03:40+07:00",
"sessions": [ { "check_in": "…", "check_out": "…", "verified_by": "geofence" } ],
"worked_minutes": 531, "late_minutes": 12, "early_leave_minutes": null, "leave_type": null,
"shift": { "name": "Ca sáng", "start": "08:00", "end": "17:00", "kind": "shift", "standing": false, "credit_day": false } }
late_minuteslànullkhi không có ca để so, không phải0.shiftlànullkhi hôm đó không có ca.- Chấm công trả theo thứ tự tạo bản ghi và phân trang cursor: đồng bộ dở dang thì tiếp tục đúng chỗ dừng. Không có toạ độ.
- Lịch trả từng ngày có ca:
{ "date", "is_working_day", "shift" }, gồm cả ca xếp tay lẫn ca cố định (standing: true). Giá trị ngày công bằng tiền không có ở đây.
6.5 Đơn nghỉ
GET /leave-requests?status=&from=&to= · POST /leave-requests/{id}/approve · POST /leave-requests/{id}/reject { "reason" }
6.6 Quy trình
GET /process/forms GET /process/assignments
POST /process/assignments/{id}/trigger
GET /process/submissions?since=&assignment=&cursor= GET /process/submissions/{id}
trigger tạo lượt việc ngoài chu kỳ, mồi sẵn dữ liệu để nhân viên chỉ xác nhận:
{ "external_ref": "PO-2026-0912", "scope": { "type": "department", "id": "dep_…" },
"due_at": "2026-09-06T17:00:00+07:00",
"context": { "mat_hang": [ { "ten": {"id":"sku_123","label":"Sữa tươi 1L"}, "kl_du_kien": 12 } ] } }
Ảnh trong phiếu là URL có chữ ký, hạn 15 phút.
7. Định danh nhân sự bằng mã QR
7.1 Bài toán
POS của khách hàng cần biết *ai* đang thao tác nhưng không muốn quản lý mật khẩu từng nhân viên. Nhân viên đã có CTAS Work để chấm công. Hãy để họ quét thay vì đăng nhập.
7.2 Luồng
- Backend của bạn, bằng token kết nối của tổ chức đó, tạo yêu cầu định danh → nhận
qr_text. - Hiển thị
qr_textdưới dạng mã QR. - Nhân viên mở CTAS Work › Tổng quan › QR Code (hoặc quét bằng máy ảnh iPhone — mã mở thẳng ứng dụng).
- Ứng dụng hiện tên tổ chức, tên ứng dụng của bạn, và dữ liệu sẽ chia sẻ (chỉ mã nhân sự). Nhân viên bấm Đồng ý.
- Bạn nhận webhook
identity.confirmed— hoặc pollGET /identity-requests/{id}.
7.3 Tạo yêu cầu — POST /identity-requests (identity:write)
{ "reference": "TERMINAL-01", "ttl_seconds": 300,
"constraints": { "department_ids": ["dep_2Hs8…"], "member_ids": [] } }
{ "data": { "id": "idr_Tt9…", "reference": "TERMINAL-01", "status": "pending",
"qr_text": "https://developer.ctas.vn/i/8fJ2kQ…",
"expires_at": "2026-09-06T09:05:00+07:00" } }
| Trường | Ghi chú |
|---|---|
reference | chuỗi của bạn (≤ 120), trả lại nguyên vẹn trong webhook |
ttl_seconds | 30–900, mặc định 300 |
constraints.department_ids | chỉ nhân sự thuộc các phòng ban/cửa hàng này |
constraints.member_ids | chỉ đúng những người này |
| ngầm định | nhân sự đang hoạt động của tổ chức của kết nối |
Tối đa 200 yêu cầu pending cùng lúc mỗi kết nối → 429 TOO_MANY_PENDING.
7.4 Theo dõi
GET /identity-requests/{id} · POST /identity-requests/{id}/cancel. status: pending → confirmed | declined | expired | canceled; khi confirmed có member_id, department_id, confirmed_at.
7.5 Webhook identity.confirmed
{ "id": "evt_01J9…", "type": "identity.confirmed", "api_version": "2026-09-01",
"created_at": "2026-09-06T09:01:12+07:00",
"connection_id": "con_…", "organization_id": "org_…",
"data": { "identity_request_id": "idr_Tt9…", "reference": "TERMINAL-01",
"member_id": "mem_Kd7p…", "department_id": "dep_2Hs8…",
"confirmed_at": "2026-09-06T09:01:12+07:00" } }
Payload chỉ có mã nhân sự. Cần tên để hiện lên POS? Gọi GET /members/{member_id} bằng token kết nối có members:read.
7.6 Điều gì không xảy ra
- Quét không chấm công.
- Người ngoài tổ chức hoặc không thoả
constraintsthấy "Mã này không dành cho bạn", không biết mã của tổ chức nào. - Một mã dùng đúng một lần.
- Hiện chỉ ứng dụng iOS hỗ trợ quét.
8. Webhooks
8.1 Đăng ký
Console › Webhooks › Thêm endpoint (theo môi trường) hoặc API với token ứng dụng (webhooks:manage). Một bộ endpoint phục vụ mọi kết nối; mỗi sự kiện mang connection_id + organization_id. Secret whsec_… hiện một lần. Live bắt buộc https://, cấm địa chỉ nội bộ; test nhận http:// để thử qua tunnel.
8.2 Định dạng gửi
POST {url}
Content-Type: application/json
X-CTAS-Event: identity.confirmed
X-CTAS-Event-Id: evt_01J9…-whk_…
X-CTAS-Timestamp: 1757127672
X-CTAS-Signature: t=1757127672,v1=5f1a…
X-CTAS-Api-Version: 2026-09-01
8.3 Kiểm chữ ký — bắt buộc
HMAC-SHA256 với secret của endpoint trên chuỗi "{timestamp}.{raw body}". Từ chối nếu |now − timestamp| > 300s. So sánh bằng hàm thời gian hằng. Dùng raw body, không parse rồi stringify lại.
import crypto from 'node:crypto'
export function verifyCtas(rawBody, headers, secret) {
const ts = headers['x-ctas-timestamp']
const sig = Object.fromEntries(headers['x-ctas-signature'].split(',').map(p => p.split('=')))
if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false
const expected = crypto.createHmac('sha256', secret).update(`${ts}.${rawBody}`).digest('hex')
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig.v1 ?? ''))
}
function verifyCtas(string $rawBody, array $headers, string $secret): bool {
$ts = (int) ($headers['X-CTAS-Timestamp'] ?? 0);
if (abs(time() - $ts) > 300) return false;
$parts = [];
foreach (explode(',', $headers['X-CTAS-Signature'] ?? '') as $p) { [$k, $v] = explode('=', $p, 2) + [null, null]; $parts[$k] = $v; }
return hash_equals(hash_hmac('sha256', "{$ts}.{$rawBody}", $secret), (string) ($parts['v1'] ?? ''));
}
8.4 Trả lời & thử lại
- Trả
2xxtrong 8 giây; xử lý nặng thì ghi hàng đợi rồi trả200. - Không nghe
2xx(timeout,5xx,408,429): thử lại sau 1s, 5s, 30s, 2 phút, 10 phút; sau 5 lần →failed, gửi lại được trong console. 4xxkhác: không thử lại.- Hỏng 20 lần liên tiếp → endpoint bị tắt, email chủ ứng dụng.
X-CTAS-Event-Idkhông đổi giữa các lần thử — khử trùng theo id này. Thứ tự không đảm bảo.
8.5 Sự kiện
| Sự kiện | Khi |
|---|---|
connection.created / connection.revoked / connection.compromised | tổ chức kết nối / ngắt / refresh token bị dùng lại |
identity.confirmed / identity.declined / identity.expired | định danh QR |
member.created / member.updated / member.left | roster thay đổi (từ app hoặc API) |
attendance.checked_in / attendance.checked_out | chấm công |
leave.requested / leave.decided | đơn nghỉ |
process.submission.created / process.submission.reviewed / process.occurrence.missed | quy trình |
Không có webhook? GET /v1/events?since=&type=&connection=&cursor= trả cùng payload theo thứ tự thời gian, giữ 30 ngày. Token ứng dụng thấy mọi sự kiện của môi trường; token kết nối chỉ thấy sự kiện của kết nối đó.
Bấm Gửi thử trong console (hoặc POST /v1/webhooks/{id}/test) gửi một sự kiện webhook.test ngay lập tức và trả về kết quả lần giao — cách nhanh nhất để kiểm chữ ký trước khi nối thật.
9. Sandbox
- Tạo bao nhiêu tổ chức sandbox tuỳ ý trong console để giả lập nhiều khách hàng; mỗi tổ chức seed sẵn 3 phòng ban, 4 chức danh, 12 nhân sự (2 chờ kích hoạt), 30 ngày chấm công, 1 biểu mẫu quy trình.
- Bạn và thành viên ứng dụng là quản trị viên của các tổ chức đó — mở CTAS Work, đổi sang tổ chức sandbox để cấp mã kết nối hoặc quét QR thử bằng chính điện thoại của bạn.
- Client
testchỉ kết nối được tổ chức sandbox; clientlivechỉ tổ chức thật. - Reset trả sandbox về trạng thái seed. Sandbox không gửi thông báo đẩy, không tính vào giới hạn gói, không xuất hiện trong báo cáo.
10. Phát hành ứng dụng nền tảng
Trước khi duyệt, ứng dụng nền tảng chỉ kết nối được tổ chức của bạn và sandbox. Để kết nối tổ chức khác:
- Tổ chức của bạn đã xác minh doanh nghiệp trên CTAS Work.
- Console › Phát hành: mục đích, website, chính sách bảo mật, giải thích từng scope xin (đặc biệt
members:salary). - CTAS xem xét trong 2 ngày làm việc. Sau khi duyệt, ứng dụng xuất hiện trong danh sách "Kết nối ứng dụng" của mọi tổ chức.
Đổi scope xin sau khi phát hành → duyệt lại; các kết nối cũ giữ scope cũ đến khi tổ chức cấp lại.
11. Bảng tra nhanh
members.status | active · paused · left |
connections.status | active · revoked |
identity-requests.status | pending · confirmed · declined · expired · canceled |
leave-requests.status | pending · approved · rejected · canceled |
attendance.source | app · manual · adjusted |
deliveries.status | pending · sent · failed |
12. Changelog
2026-09-01 (phiên bản đầu)
- OAuth 2.0 (
client_credentials,connection_code,authorization_code+ PKCE,refresh_token), kết nối theo tổ chức, tổ chức/phòng ban/chức danh/nhân sự (đọc-ghi), chấm công, lịch, đơn nghỉ, quy trình, định danh QR, webhooks, sổ sự kiện. - Chưa có:
attendance:write, device flow, SDK. Xem lộ trình tại developer.ctas.vn/roadmap.