Chuyển tới nội dung chính

21. Public REST API (External — `X-API-Key`)

REST API for external integrations, authenticated with an API key (no JWT required). All endpoints are prefixed with /api/public/. The orgId is resolved automatically from the API key.

Authentication

Send the API key in the header:

X-API-Key: <your_api_key>

Generate/retrieve the API key in Settings → API & Webhook (or POST /api/v1/settings/api-key/generate). Missing or invalid key → 401.

21.1 List Contacts

GET /api/public/contacts

Query params: search (name/phone/email), status, limit (default 20, max 100).

Response:

{
"contacts": [
{
"id": "contact-123",
"fullName": "Jane Doe",
"phone": "0900000000",
"email": "[email protected]",
"source": "facebook",
"status": "new",
"notes": "Interested in Pro plan",
"tags": ["vip"],
"createdAt": "2026-06-01T03:00:00.000Z",
"updatedAt": "2026-06-10T07:30:00.000Z"
}
]
}

21.2 Get Contact

GET /api/public/contacts/:id

Returns the contact with its 5 most recent appointments and a conversation count. 404 if not found.

21.3 Create Contact

POST /api/public/contacts

Body: (requires at least fullName or phone)

{
"fullName": "Jane Doe",
"phone": "0900000000",
"email": "[email protected]",
"source": "website",
"status": "new",
"notes": "Signed up from landing page",
"tags": ["lead"]
}

Status codes: 201 (created), 400 (missing fullName & phone).

21.4 Update Contact

PUT /api/public/contacts/:id

Body same as 21.3 (provided fields are updated). 404 if not found.

21.5 List Conversations

GET /api/public/conversations

Query params: limit (default 20, max 100).

Response:

{
"conversations": [
{
"id": "conv-123",
"threadType": "user",
"externalThreadId": "zalo-uid-xxx",
"lastMessageAt": "2026-06-10T07:30:00.000Z",
"unreadCount": 2,
"isReplied": false,
"contact": { "id": "contact-123", "fullName": "Jane Doe", "phone": "0900000000", "avatarUrl": null }
}
]
}

21.6 Get Conversation Messages

GET /api/public/conversations/:id/messages

Query params: limit (default 50, max 200). 404 if the conversation does not belong to the organization.

Response:

{
"messages": [
{
"id": "msg-1",
"senderType": "contact",
"senderName": "Jane Doe",
"content": "What's the price?",
"contentType": "text",
"sentAt": "2026-06-10T07:29:00.000Z",
"attachments": []
}
]
}

21.7 List Appointments

GET /api/public/appointments

Query params: from, to (ISO date, filter by appointmentDate). Returns up to 100, including contact info.

21.8 Create Appointment

POST /api/public/appointments

Body: (requires contactId and appointmentDate)

{
"contactId": "contact-123",
"appointmentDate": "2026-06-20",
"appointmentTime": "14:30",
"type": "call",
"notes": "Consultation call for Pro plan"
}

Status codes: 201, 400 (missing fields), 404 (contact not found).

21.9 Send Zalo Message

POST /api/public/messages/send

Send a message through a connected Zalo account of the organization.

Body: (requires zaloAccountId, threadId, content)

{
"zaloAccountId": "zalo-acc-123",
"threadId": "zalo-uid-or-group-id",
"content": "Hello from ZCRM!",
"threadType": "user"
}
  • threadType: "user" (default) or "group".

Response: { "success": true }

Status codes: 200, 400 (missing fields), 404 (account not found), 422 (account not connected / not active in pool).