Bắt đầu nhanh
Connectelly External API sử dụng xác thực hai bước. Đổi API key lấy một access token có thời hạn ngắn, sau đó gọi API bằng token đó.
- Đăng ký làm đối tác và nhận API key — quản trị viên chính (master) cấp key sau khi ký hợp đồng.
- Lấy access token —
POST /api/external/v1/token - Gọi API bằng token —
Authorization: Bearer <access_token>
# 1) Lấy token (API key chỉ dùng ở bước này)
curl -X POST https://connectelly.com/api/external/v1/token \
-H "X-Connectelly-Api-Key: ck_live_..."
# → {"access_token":"eyJ...","token_type":"Bearer","expires_in":1800,
# "event_id":"af2f95b4..."} ← eventId nhận được ở đây
# 2) Gửi liên hệ bằng token vừa nhận
curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-d '{"external_id":"REG-001","name":"John Smith","email":"john@example.com"}'
Phản hồi 200 nghĩa là đã lưu thành công. Khi người dùng ứng dụng quét QR của REG-001, lead sẽ được thu thập tự động.
Xác thực
Xác thực hai bước
API key dài hạn chỉ dùng để lấy token; mọi lệnh gọi API thực tế đều dùng access token ngắn hạn. Key không đi kèm lưu lượng thông thường nên không thể bị lộ qua log máy chủ hay proxy của đối tác.
API key
- Định dạng:
ck_live_<32 url-safe base64> - Chỉ gửi qua header
X-Connectelly-Api-KeytạiPOST /api/external/v1/token - Cấp theo từng sự kiện. Không dùng được cho sự kiện khác (404 event_not_found)
- Chỉ dùng phía máy chủ. Không nhúng vào mã phía client hoặc đưa lên kho mã công khai
Access Token
- Hiệu lực 30 phút (1800 giây). Hãy lấy token mới khi hết hạn.
- Gửi
Authorization: Bearer <access_token>trong mọi lệnh gọi API. - Khi key bị thu hồi, các token đã cấp cũng mất hiệu lực ngay lập tức.
Khi key bị lộ
Hãy báo ngay cho quản trị viên để thu hồi key. Ngay khi thu hồi, key đó và mọi token được cấp từ key đó đều bị chặn. Khi được cấp key mới, key cũ vẫn còn hiệu lực trong 24 giờ ân hạn, nên bạn có thể thay key mà không bị gián đoạn.
Giới hạn IP (khuyến nghị)
Khi đăng ký các IP/CIDR được phép, token chỉ có thể được cấp từ những địa chỉ đó. Dù key bị lộ cũng không thể dùng ở nơi khác. Hãy liên hệ quản trị viên để thiết lập.
Token API
Đổi API key lấy access token ngắn hạn. Đây là endpoint duy nhất nhận API key trong header; mọi API còn lại đều gọi bằng token nhận được ở đây.
Yêu cầu
POST /api/external/v1/token
| Header | Bắt buộc | Mô tả |
|---|---|---|
X-Connectelly-Api-Key | Có | API key đã được cấp (ck_live_...) |
Không cần body cho yêu cầu.
curl -X POST https://connectelly.com/api/external/v1/token \
-H "X-Connectelly-Api-Key: ck_live_..."
Phản hồi 200
{
"access_token": "eyJhbGciOiJIUzM4NCJ9...",
"token_type": "Bearer",
"expires_in": 1800,
"expires_at": "2026-09-07T05:18:35Z",
"event_id": "af2f95b402794c8f9289360fc8765b8e"
}
| Trường | Kiểu | Mô tả |
|---|---|---|
| access_token | string | Dùng trong header Authorization của mọi yêu cầu sau đó |
| token_type | string | Luôn là Bearer |
| expires_in | integer | Thời gian hiệu lực còn lại (giây). Mặc định 1800 = 30 phút |
| expires_at | string | Thời điểm hết hạn (ISO-8601 UTC) |
| event_id | string | ID sự kiện gắn với key này. Dùng nguyên giá trị này cho {eventId} trong đường dẫn của mọi endpoint khác |
Lấy eventId ở đâu?
Mỗi API key được cấp gắn với một sự kiện duy nhất, nên bạn không cần tự quản lý eventId. Có hai cách để biết giá trị này:
event_idtrong phản hồi token — lấy trực tiếp từ phản hồi ở trên. Nên dùng giá trị này thay vì hardcode.- Thông báo khi cấp key — người phụ trách sẽ cung cấp kèm khi giao API key.
Dùng eventId của sự kiện khác sẽ trả về 404 event_not_found.
Lỗi
| HTTP | code | Nguyên nhân |
|---|---|---|
| 401 | auth_missing | Thiếu header |
| 401 | auth_invalid | Không nhận dạng được key |
| 401 | key_expired | Key đã hết hạn (hoặc hết thời gian ân hạn khi cấp lại) |
| 401 | key_revoked | Key đã bị thu hồi |
| 403 | ip_not_allowed | IP không được phép |
Mẹo vận hành
- Lưu token vào bộ nhớ đệm thay vì lấy mới cho mỗi yêu cầu. Nên làm mới trước khi hết hạn 1–2 phút.
- Khi nhận 401
token_invalid, hãy lấy token mới và thử lại đúng 1 lần. - Chỉ giữ token trong bộ nhớ máy chủ, không ghi vào log hoặc URL.
Tạo / Cập nhật liên hệ
Tạo hoặc cập nhật một liên hệ. Nếu external_id đã tồn tại thì ghi đè (UPSERT). Gọi API này ngay khi đăng ký để lead được thu thập tự động khi ứng dụng quét QR.
POST /api/external/v1/events/{eventId}/contacts
Header của yêu cầu
| Header | Bắt buộc | Mô tả |
|---|---|---|
Authorization | Có | Bearer <access_token> |
Content-Type | Có | application/json |
Idempotency-Key | Không | Thử lại với cùng key sẽ nhận phản hồi đầu tiên thay vì xử lý lại. Xem mục Idempotency |
Body của yêu cầu
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
| external_id | string | Có | ID duy nhất trong hệ thống đăng ký, tối đa 100 ký tự. Phải khớp với giá trị QR |
| name | string | Không | Họ tên, tối đa 200 ký tự |
| string | Không | Email. Mã hóa AES-256-GCM khi lưu | |
| phone | string | Không | Số điện thoại. Mã hóa khi lưu |
| company | string | Không | Tên công ty, tối đa 200 ký tự |
| position | string | Không | Chức danh, tối đa 100 ký tự |
| extra | object | Không | JSON tự do cho các trường mở rộng của đối tác |
curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-d '{
"external_id": "REG-001",
"name": "John Smith",
"email": "john@example.com",
"phone": "010-1234-5678",
"company": "Acme Inc.",
"position": "CEO",
"extra": { "booth": "A-12" }
}'
Phản hồi 200
Trả về nguyên giá trị bạn vừa gửi (để xác nhận đã ghi). Các trường có cùng định dạng với Lấy liên hệ, riêng qr_image_url trong phản hồi này luôn là null — hãy lấy URL ảnh QR qua Lấy liên hệ hoặc Danh sách liên hệ.
{
"id": "con_af2f95b4_REG-001",
"object": "external_contact",
"event_id": "af2f95b402794c8f9289360fc8765b8e",
"external_id": "REG-001",
"name": "John Smith",
"email": "john@example.com",
"phone": "010-1234-5678",
"company": "Acme Inc.",
"position": "CEO",
"extra": {"booth": "A-12"},
"created_at": "2026-09-07T04:50:38Z",
"updated_at": "2026-09-07T04:50:38Z",
"qr_image_url": null
}
Lỗi
| HTTP | code | Nguyên nhân |
|---|---|---|
| 400 | validation_failed | Thiếu external_id hoặc trường vượt độ dài |
| 400 | invalid_json | Nội dung yêu cầu không phải JSON hợp lệ |
| 401 | token_missing / token_invalid | Thiếu token / token giả mạo hoặc hết hạn |
| 404 | event_not_found | Sự kiện không tồn tại hoặc nằm ngoài phạm vi của key |
| 409 | idempotency_conflict | Cùng Idempotency-Key được dùng cho một yêu cầu khác |
| 409 | idempotency_in_progress | Yêu cầu đầu tiên với Idempotency-Key này vẫn đang được xử lý |
| 429 | rate_limited | Vượt giới hạn tốc độ |
Tải lên hàng loạt
UPSERT tối đa 500 liên hệ trong một lần gọi. Dùng cho lần nạp dữ liệu ban đầu hoặc đồng bộ ban đêm.
POST /api/external/v1/events/{eventId}/contacts/batch
Body của yêu cầu
| Trường | Kiểu | Bắt buộc | Mô tả |
|---|---|---|---|
| contacts | array | Có | Mảng liên hệ, 1–500 mục. Mỗi mục có cùng định dạng với API tạo một liên hệ |
curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts/batch \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-d '{
"contacts": [
{ "external_id": "REG-001", "name": "John Smith", "email": "john@example.com" },
{ "name": "Jane Doe", "email": "jane@example.com" }
]
}'
Phản hồi 200
Mục thứ hai trong ví dụ không có external_id, nên chỉ mục đó thất bại, các mục còn lại vẫn được lưu.
{
"total": 2,
"created": 1,
"updated": 0,
"failed": 1,
"errors": [
{
"external_id": null,
"code": "validation_failed",
"message": "external_id is required.",
"param": "external_id"
}
]
}
| Trường | Kiểu | Mô tả |
|---|---|---|
| total | integer | Tổng số mục trong yêu cầu |
| created | integer | Số liên hệ mới được tạo |
| updated | integer | Số liên hệ hiện có bị ghi đè |
| failed | integer | Số mục không được lưu |
| errors | array | Chỉ gồm các mục thất bại (external_id, code, message, param). Mảng rỗng nếu tất cả thành công |
Lưu ý
- Mảng rỗng hoặc vượt quá 500 mục sẽ khiến toàn bộ yêu cầu trả về 400
validation_failed. - Cho phép thành công một phần. Dù có mục thất bại, các mục hợp lệ vẫn được lưu. Chỉ cần sửa các mục trong
errorsrồi gửi lại; vì là UPSERT nên không tạo bản trùng. - Khi nạp số lượng lớn, hãy giãn cách các lần gọi theo mục Giới hạn tốc độ để tránh 429.
- Hỗ trợ header
Idempotency-Key— thử lại lần gọi bị hết thời gian chờ với cùng key thì yêu cầu chỉ được xử lý một lần. Xem mục Idempotency.
Danh sách liên hệ
Trả về toàn bộ liên hệ đã lưu cho sự kiện này trong một lần gọi. Dùng để đối chiếu dữ liệu đã gửi, hoặc lấy hàng loạt ảnh QR để in thẻ tên.
GET /api/external/v1/events/{eventId}/contacts
curl https://connectelly.com/api/external/v1/events/<eventId>/contacts \
-H "Authorization: Bearer eyJ..."
Phản hồi 200
Không có tham số truy vấn và không phân trang. Mỗi phần tử trong contacts có cùng các trường với phản hồi Lấy liên hệ; họ tên, email và số điện thoại cũng được che theo cùng cách.
{
"total": 2,
"returned": 2,
"truncated": false,
"contacts": [
{
"id": "con_af2f95b4_REG-002",
"object": "external_contact",
"event_id": "af2f95b402794c8f9289360fc8765b8e",
"external_id": "REG-002",
"name": "J******e",
"email": "ja**@example.com",
"phone": null,
"company": null,
"position": null,
"extra": null,
"created_at": "2026-09-07T05:02:11Z",
"updated_at": "2026-09-07T05:02:11Z",
"qr_image_url": "https://cdn.connectelly.com/qr/af2f95b402794c8f9289360fc8765b8e/REG-002.png"
},
{
"id": "con_af2f95b4_REG-001",
"object": "external_contact",
"event_id": "af2f95b402794c8f9289360fc8765b8e",
"external_id": "REG-001",
"name": "J********h",
"email": "jo**@example.com",
"phone": "010-****-5678",
"company": "Acme Inc.",
"position": "CEO",
"extra": {"booth": "A-12"},
"created_at": "2026-09-07T04:50:38Z",
"updated_at": "2026-09-07T04:50:38Z",
"qr_image_url": "https://cdn.connectelly.com/qr/af2f95b402794c8f9289360fc8765b8e/REG-001.png"
}
]
}
| Trường | Kiểu | Mô tả |
|---|---|---|
| total | integer | Tổng số liên hệ đã lưu cho sự kiện này |
| returned | integer | Số liên hệ trong phản hồi này (tối đa 10.000) |
| truncated | boolean | true nghĩa là đã chạm giới hạn 10.000 và chỉ 10.000 liên hệ mới nhất được trả về. Khi đó hãy liên hệ với chúng tôi |
| contacts | array | Danh sách liên hệ, mới đăng ký nhất xếp trước |
- Sắp xếp theo thời điểm đăng ký lần đầu (
created_at), mới nhất trước. Cập nhật (UPSERT) không làm thay đổi thứ tự. - Lấy danh sách không tạo ảnh QR mới.
qr_image_urllà địa chỉ lưu ảnh khi đăng ký, nên liên hệ bị lỗi tạo ảnh lúc đăng ký có thể không mở được liên kết. Gọi Lấy liên hệ cho liên hệ đó một lần là ảnh sẽ được tạo.
Lỗi
| HTTP | code | Nguyên nhân |
|---|---|---|
| 404 | event_not_found | Sự kiện không tồn tại hoặc nằm ngoài phạm vi của key |
Lấy liên hệ
Lấy một liên hệ đã đăng ký.
GET /api/external/v1/events/{eventId}/contacts/{externalId}
Phản hồi 200 — thông tin cá nhân được che
Họ tên, email và số điện thoại trong phản hồi bị che phần giữa. Biện pháp này ngăn việc thu thập liên hệ hàng loạt khi API key hoặc token bị lộ. Đối tác đã có dữ liệu gốc nên không ảnh hưởng đến công việc hằng ngày.
{
"id": "con_af2f95b4_REG-001",
"object": "external_contact",
"event_id": "af2f95b402794c8f9289360fc8765b8e",
"external_id": "REG-001",
"name": "J********h",
"email": "jo**@example.com",
"phone": "010-****-5678",
"company": "Acme Inc.",
"position": "CEO",
"extra": {"booth": "A-12"},
"created_at": "2026-09-07T04:50:38Z",
"updated_at": "2026-09-07T04:50:38Z",
"qr_image_url": "https://cdn.connectelly.com/qr/af2f95b402794c8f9289360fc8765b8e/REG-001.png"
}
| Giá trị gốc | Phản hồi GET |
|---|---|
| john@example.com | jo**@example.com |
| 010-1234-5678 | 010-****-5678 |
| John Smith | J********h |
| 홍길동 | 홍*동 |
Tên công ty, chức danh và extra không bị che. Phản hồi tạo / cập nhật (UPSERT) trả về nguyên giá trị bạn vừa gửi nên không bị che.
Các trường trong phản hồi
| Trường | Kiểu | Mô tả |
|---|---|---|
| id | string | con_ + 8 ký tự đầu của event_id + _ + external_id |
| object | string | Luôn là external_contact |
| event_id | string | ID sự kiện (32 ký tự), giống eventId trong đường dẫn |
| external_id | string | Nguyên external_id bạn đã gửi |
| name / email / phone | string | null | Giá trị đã che. null nếu không gửi |
| company / position | string | null | Nguyên giá trị đã gửi. null nếu không gửi |
| extra | object | null | Trả về nguyên đối tượng extra bạn đã gửi (ví dụ: {"booth": "A-12"}). null nếu không gửi |
| created_at | string | Thời điểm đăng ký lần đầu, ISO 8601 (UTC). Không đổi khi cập nhật sau đó |
| updated_at | string | Thời điểm cập nhật gần nhất, ISO 8601 (UTC) |
| qr_image_url | string | null | URL ảnh QR để in thẻ tên (PNG, 600×600px). Giá trị QR là nguyên external_id. Nếu chưa có ảnh, lần gọi này sẽ tạo ảnh. null nếu không tạo được ảnh |
Lỗi
| HTTP | code | Nguyên nhân |
|---|---|---|
| 404 | contact_not_found | Không có liên hệ với external_id này |
| 404 | event_not_found | Sự kiện không tồn tại hoặc nằm ngoài phạm vi của key |
Xoá liên hệ
Xoá một liên hệ đã đăng ký. Dùng khi khách huỷ tham quan hoặc để sửa đăng ký trùng.
DELETE /api/external/v1/events/{eventId}/contacts/{externalId}
curl -X DELETE https://connectelly.com/api/external/v1/events/<eventId>/contacts/REG-001 \
-H "Authorization: Bearer eyJ..."
Phản hồi 204
Trả về 204 No Content với body rỗng.
Lưu ý
- Sau khi xoá, quét lại QR đó sẽ không thu thập lead.
- Các lead đã thu thập không bị xoá — danh thiếp mà người dùng ứng dụng đã thu thập vẫn được giữ nguyên.
- Không thể hoàn tác. Để đăng ký lại, hãy gọi API UPSERT.
- Hỗ trợ header
Idempotency-Key. Thử lại với cùng key sẽ phát lại phản hồi đầu tiên (204); gửi lại không kèm key sẽ nhận 404contact_not_foundvì liên hệ đã bị xoá.
Lỗi
| HTTP | code | Nguyên nhân |
|---|---|---|
| 404 | contact_not_found | Không có liên hệ với external_id này |
| 409 | idempotency_conflict | Cùng Idempotency-Key được dùng cho một yêu cầu khác |
| 409 | idempotency_in_progress | Yêu cầu đầu tiên với Idempotency-Key này vẫn đang được xử lý |
Mã lỗi
Mọi lỗi đều được trả về theo định dạng kiểu Stripe.
{
"error": {
"type": "invalid_request_error",
"code": "validation_failed",
"message": "external_id must be 100 characters or less.",
"param": "external_id",
"doc_url": null,
"request_id": "req_3f9a1c2b7d4e5f60"
}
}
message dành cho log của lập trình viên và luôn bằng tiếng Anh, không thay đổi theo cài đặt ngôn ngữ. Hãy rẽ nhánh xử lý lỗi theo code, đừng dựa vào nội dung message. param là tên trường gây lỗi, còn request_id giúp truy vết yêu cầu khi bạn liên hệ hỗ trợ.
| Mã | HTTP | Ý nghĩa |
|---|---|---|
| validation_failed | 400 | Dữ liệu yêu cầu không hợp lệ (thiếu trường bắt buộc, vượt độ dài, vượt số lượng, v.v.) |
| invalid_json | 400 | Nội dung yêu cầu không phải JSON hợp lệ |
| auth_missing | 401 | Thiếu header X-Connectelly-Api-Key |
| auth_invalid | 401 | Không nhận dạng được key |
| key_expired | 401 | Key đã hết hạn (hoặc hết thời gian ân hạn khi cấp lại) |
| key_revoked | 401 | Key đã bị thu hồi |
| token_missing | 401 | Thiếu token Authorization: Bearer |
| token_invalid | 401 | Token không hợp lệ hoặc đã hết hạn |
| ip_not_allowed | 403 | IP không được phép |
| event_not_found | 404 | Sự kiện không tồn tại hoặc nằm ngoài phạm vi của key |
| contact_not_found | 404 | Không có liên hệ với external_id này |
| idempotency_conflict | 409 | Cùng Idempotency-Key được dùng cho một yêu cầu khác (phương thức, đường dẫn hoặc body) — hãy dùng key mới |
| idempotency_in_progress | 409 | Yêu cầu đầu tiên với Idempotency-Key này vẫn đang được xử lý — đợi một lát rồi thử lại đúng yêu cầu đó |
| payload_too_large | 413 | Nội dung yêu cầu vượt quá 2 MB (yêu cầu có Idempotency-Key) — hãy chia nhỏ rồi gửi |
| rate_limited | 429 | Vượt giới hạn tốc độ |
| internal_error | 500 | Lỗi máy chủ |
Giới hạn tốc độ
Mặc định 60 req/min per key per task. Connectelly app-api tự động co giãn trong khoảng 2–6 task, nên mức cho phép thực tế là 120–360 req/min.
Mọi phản hồi đều có các header sau:
X-RateLimit-Limit— mức cho phép trên mỗi taskX-RateLimit-Remaining— số yêu cầu còn lại trong cửa sổ hiện tạiRetry-After— số giây cần chờ trước khi thử lại khi nhận 429
Idempotency
Khi một yêu cầu bị hết thời gian chờ, bạn không biết máy chủ đã xử lý hay chưa. Hãy gửi header Idempotency-Key và thử lại với cùng key: yêu cầu chỉ được xử lý một lần, và mỗi lần thử lại đều nhận về phản hồi đầu tiên.
Header
| Header | Bắt buộc | Mô tả |
|---|---|---|
Idempotency-Key | Không | 1–255 ký tự ASCII in được. Khuyến nghị UUID v4. Tạo key mới cho mỗi yêu cầu mới |
- Key rỗng, dài hơn 255 ký tự hoặc chứa ký tự điều khiển sẽ trả về 400
validation_failed(param:Idempotency-Key). - Ký tự ngoài ASCII (ví dụ tiếng Việt có dấu) có thể bị từ chối với 403 trước khi đến API. Chỉ dùng ASCII.
- Áp dụng cho
POST /contacts,POST /contacts/batchvàDELETE /contacts/{externalId}. Yêu cầuGETvàPOST /tokenbỏ qua header này. - Key được phân tách theo API Key — không bao giờ trùng với key của đối tác khác.
- Key được lưu 24 giờ kể từ yêu cầu đầu tiên. Sau đó, cùng key được xử lý như một yêu cầu mới.
- Với header này, nội dung yêu cầu vượt quá 2 MB sẽ trả về 413
payload_too_large. Một lô tối đa 500 liên hệ nằm trong giới hạn này.
Cách hoạt động
| Trường hợp | Kết quả |
|---|---|
| Yêu cầu đầu tiên với một key | Xử lý bình thường; phản hồi được lưu (xem bên dưới) |
| Cùng key, cùng yêu cầu | Không xử lý lại. Trả về nguyên mã trạng thái và body của phản hồi đầu tiên, kèm header Idempotent-Replayed: true |
| Cùng key, yêu cầu khác | 409 idempotency_conflict — hãy dùng key mới |
| Cùng key khi yêu cầu đầu tiên vẫn đang xử lý | 409 idempotency_in_progress — đợi một lát rồi gửi lại đúng yêu cầu đó |
- "Cùng yêu cầu" nghĩa là cùng phương thức, đường dẫn, query string và body, giống nhau từng byte. Chỉ khác khoảng trắng hoặc thứ tự trường cũng là yêu cầu khác, vì vậy hãy gửi lại đúng các byte đã gửi lần đầu.
- Body được phát lại giữ
request_idcủa yêu cầu đầu tiên; header phản hồiX-Request-Idmang giá trị mới của lần thử lại. - Phản hồi được phát lại cũng được tính vào giới hạn tốc độ.
HTTP/1.1 200
Content-Type: application/json
Idempotent-Replayed: true
X-Request-Id: req_8b2e4d1f0a9c3e75
Phản hồi nào được lưu
| Phản hồi | Thử lại với cùng key |
|---|---|
| 2xx, và lỗi phía client như 400, 404 | Được lưu — phát lại cùng phản hồi |
| 5xx, 429, 408, 409, 401, 403 | Không lưu — yêu cầu được xử lý lại |
Vì 400 cũng được phát lại, sau khi sửa một yêu cầu bị 400, hãy dùng key mới. Gửi body đã sửa với key cũ sẽ nhận 409 idempotency_conflict.
Ví dụ: thử lại sau khi hết thời gian chờ
Tạo key một lần cho mỗi yêu cầu và dùng lại key đó ở mọi lần thử lại. Lệnh curl dưới đây thử lại tối đa 3 lần khi hết thời gian chờ, 408, 429 và 5xx, luôn gửi cùng key. Nếu lần thử lại nhận 409 idempotency_in_progress, hãy đợi một lát rồi gửi lại đúng yêu cầu đó.
KEY=$(uuidgen)
curl -X POST https://connectelly.com/api/external/v1/events/<eventId>/contacts \
-H "Authorization: Bearer eyJ..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $KEY" \
--max-time 10 --retry 3 \
-d '{ "external_id": "REG-001", "name": "John Smith" }'
Nhật ký thay đổi
- 2026-10-14 — Hỗ trợ
Idempotency-Key(tạo / hàng loạt / xoá liên hệ), bổ sung tài liệu API danh sách liên hệ, thêm trường cho phản hồi lấy liên hệ,extrađược trả về dưới dạng đối tượng thay vì chuỗi - v1.0 (2026-09) — Phát hành đầu tiên: Contacts API (đơn lẻ / hàng loạt / lấy / xoá)