Chiến dịchQuản lý Contacts

Quản lý Contacts

Nhữ Hào Nam·4/23/2026

API Campaign Contacts

Authentication chung: Tất cả API sử dụng Kong dual-auth: Header Authorization (API key) bắt buộc. Header X-Tenant-ID do Kong inject — nếu test internal không qua Kong thì bỏ header này, backend tự resolve tenantId theo Authorization key. Không dùng JWT (x-access-token) trong luồng này.


GET /v1/campaigns/{id}/contact-lists

Lấy tất cả contact list thuộc 1 campaign.

Authentication: Header X-Api-Key (scope: campaign). Kong dual-auth: ưu tiên X-Tenant-ID header, fallback query DB theo Authorization key.

Base URL: Dev: https://xapi-dev.alohub.vn  |  Prod: https://xapi.alohub.vn

Tham số

Tham số

Vị trí

Bắt buộc

Kiểu

Mô tả

Ví dụ

{id}

path

number

campaignId

1042

Request Body

Code mẫu

curl -X GET "https://xapi.alohub.vn/v1/campaigns/1042/contact-lists" \
  -H "X-Api-Key: sk_live_xxx" \
  -H "X-Tenant-ID: 20260310"
const axios = require('axios');
const response = await axios.get(
  '{{host}}/api/v1/campaigns/{{id}}/contact-lists',
  { headers: { 'Authorization': '{{api-key}}', 'X-Tenant-ID': '{{tenant-id}}', 'Content-Type': 'application/json' } }
);
console.log(response.data);
import requests

headers = {"Authorization": "{{api-key}}", "X-Tenant-ID": "{{tenant-id}}", "Content-Type": "application/json"}
response = requests.get(
    '{{host}}/api/v1/campaigns/{{id}}/contact-lists',
    headers=headers
)
print(response.json())

Response 200

{
  "success": "1",
  "totalRecord": 2,
  "data": [
    {
      "listId": 501,
      "listName": "Danh sach thang 4",
      "contactCount": 150
    },
    {
      "listId": 502,
      "listName": "Default List",
      "contactCount": 30
    }
  ]
}

Response Fields

Field

Kiểu

Mô tả

success

string

"1" = thành công

totalRecord

number

Tổng số list

data[].listId

number

ID contact list — dùng làm {listId}

data[].listName

string

Tên list

data[].contactCount

number

Số contact trong list

Error Codes

HTTP

error_code

Mô tả

FE xử lý

401

UNAUTHORIZED

Thiếu hoặc sai API key

Redirect nhập lại key

403

INSUFFICIENT_SCOPE

Key không có scope campaign

Hiện thông báo

404

NOT_FOUND

Không tìm thấy

Hiện thông báo

429

RATE_LIMIT_EXCEEDED

Vượt giới hạn request

Retry sau Retry-After giây

500

FAIL

Lỗi hệ thống

Toast lỗi chung

Rate Limit Headers

Header

Mô tả

X-RateLimit-Limit-Tenant

Giới hạn tenant/10s

X-RateLimit-Remaining-Tenant

Còn lại tenant/10s

X-RateLimit-Limit-Route

Giới hạn route/10s

X-RateLimit-Remaining-Route

Còn lại route/10s

Retry-After

Giây cần chờ khi bị 429


GET /v1/campaigns/{id}/contact-lists/{listId}/contacts

Lấy danh sách contacts trong 1 contact list — có phân trang.

Authentication: Header X-Api-Key (scope: campaign). Kong dual-auth: ưu tiên X-Tenant-ID header, fallback query DB theo Authorization key.

Base URL: Dev: https://xapi-dev.alohub.vn  |  Prod: https://xapi.alohub.vn

Tham số

Tham số

Vị trí

Bắt buộc

Kiểu

Mô tả

Ví dụ

{id}

path

number

campaignId

1042

{listId}

path

number

listId (từ GET /contact-lists)

501

page

query

Không

number

Trang (default: 0)

0

size

query

Không

number

Số record/trang (default: 20)

20

Request Body

Code mẫu

curl -X GET "https://xapi.alohub.vn/v1/campaigns/1042/contact-lists/501/contacts?page=0&size=20" \
  -H "X-Api-Key: sk_live_xxx" \
  -H "X-Tenant-ID: 20260310"
const axios = require('axios');
const response = await axios.get(
  '{{host}}/api/v1/campaigns/{{id}}/contact-lists/{{listId}}/contacts?page=0&size=20',
  { headers: { 'Authorization': '{{api-key}}', 'X-Tenant-ID': '{{tenant-id}}', 'Content-Type': 'application/json' } }
);
console.log(response.data);
import requests

params = {"page": "0", "size": "20"}
headers = {"Authorization": "{{api-key}}", "X-Tenant-ID": "{{tenant-id}}", "Content-Type": "application/json"}
response = requests.get(
    '{{host}}/api/v1/campaigns/{{id}}/contact-lists/{{listId}}/contacts',
    headers=headers, params=params
)
print(response.json())

Response 200

{
  "success": "1",
  "totalRecord": 150,
  "data": [
    {
      "contactId": 88001,
      "customerId": 55001,
      "phoneNumber": "0901234567",
      "name": "Nguyen Van A",
      "processStatus": 0,
      "callStatus": null
    }
  ]
}

Response Fields

Field

Kiểu

Mô tả

success

string

"1" = thành công

totalRecord

number

Tổng số contact

data[].contactId

number

ID contact — dùng làm {contactId} khi xoá

data[].customerId

number

ID khách hàng

data[].phoneNumber

string

Số điện thoại

data[].name

string

null

Tên khách hàng

data[].processStatus

number

0=pending, 1=in_call, 2=processed

data[].callStatus

string

null

Trạng thái cuộc gọi

Error Codes

HTTP

error_code

Mô tả

FE xử lý

401

UNAUTHORIZED

Thiếu hoặc sai API key

Redirect nhập lại key

403

INSUFFICIENT_SCOPE

Key không có scope campaign

Hiện thông báo

404

NOT_FOUND

Không tìm thấy

Hiện thông báo

429

RATE_LIMIT_EXCEEDED

Vượt giới hạn request

Retry sau Retry-After giây

500

FAIL

Lỗi hệ thống

Toast lỗi chung

Rate Limit Headers

Header

Mô tả

X-RateLimit-Limit-Tenant

Giới hạn tenant/10s

X-RateLimit-Remaining-Tenant

Còn lại tenant/10s

X-RateLimit-Limit-Route

Giới hạn route/10s

X-RateLimit-Remaining-Route

Còn lại route/10s

Retry-After

Giây cần chờ khi bị 429


POST /v1/campaigns/{id}/contacts

Thêm 1 contact vào campaign. Không truyền listId → dùng list đầu tiên. Chưa có list nào → tự tạo Default List.

Authentication: Header X-Api-Key (scope: campaign). Kong dual-auth: ưu tiên X-Tenant-ID header, fallback query DB theo Authorization key.

Base URL: Dev: https://xapi-dev.alohub.vn  |  Prod: https://xapi.alohub.vn

Tham số

Tham số

Vị trí

Bắt buộc

Kiểu

Mô tả

Ví dụ

{id}

path

number

campaignId

1042

Request Body

{
  "phoneNumber": "0901234567",
  "name": "Nguyen Van A",
  "listId": 501
}

Field

Bắt buộc

Mô tả

phoneNumber

Số điện thoại — bắt buộc

name

Không

Tên khách hàng

listId

Không

ID list đích. Bỏ qua = dùng list đầu tiên / tạo Default List

Code mẫu

curl -X POST "https://xapi.alohub.vn/v1/campaigns/1042/contacts" \
  -H "X-Api-Key: sk_live_xxx" \
  -H "X-Tenant-ID: 20260310" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber":"0901234567","name":"KH A"}'

# Truyền listId cụ thể
curl -X POST "https://xapi.alohub.vn/v1/campaigns/1042/contacts" \
  -H "X-Api-Key: sk_live_xxx" \
  -H "X-Tenant-ID: 20260310" \
  -H "Content-Type: application/json" \
  -d '{"phoneNumber":"0901234567","listId":501}'
const axios = require('axios');
const response = await axios.post(
  '{{host}}/api/v1/campaigns/{{id}}/contacts',
  {
  "phoneNumber": "0901234567",
  "name": "Nguyen Van A",
  "listId": 501
},
  { headers: { 'Authorization': '{{api-key}}', 'X-Tenant-ID': '{{tenant-id}}', 'Content-Type': 'application/json' } }
);
console.log(response.data);
import requests

headers = {"Authorization": "{{api-key}}", "X-Tenant-ID": "{{tenant-id}}", "Content-Type": "application/json"}
payload = {
    "phoneNumber": "0901234567",
    "name": "Nguyen Van A",
    "listId": 501
}
response = requests.post(
    '{{host}}/api/v1/campaigns/{{id}}/contacts',
    json=payload,
    headers=headers
)
print(response.json())

Response 200

{
  "success": "1",
  "error_code": "SUCCESS",
  "error_message": "Contact added to list 501"
}

Response Fields

Field

Kiểu

Mô tả

success

string

"1" = thành công

error_code

string

SUCCESS

error_message

string

"Contact added to list {listId}"

Error Codes

HTTP

error_code

Mô tả

FE xử lý

401

UNAUTHORIZED

Thiếu hoặc sai API key

Redirect nhập lại key

403

INSUFFICIENT_SCOPE

Key không có scope campaign

Hiện thông báo

400

INVALID_INPUT

Sai input

Hiện lỗi cụ thể

404

NOT_FOUND

Không tìm thấy

Hiện thông báo

429

RATE_LIMIT_EXCEEDED

Vượt giới hạn request

Retry sau Retry-After giây

500

FAIL

Lỗi hệ thống

Toast lỗi chung

Rate Limit Headers

Header

Mô tả

X-RateLimit-Limit-Tenant

Giới hạn tenant/10s

X-RateLimit-Remaining-Tenant

Còn lại tenant/10s

X-RateLimit-Limit-Route

Giới hạn route/10s

X-RateLimit-Remaining-Route

Còn lại route/10s

Retry-After

Giây cần chờ khi bị 429


POST /v1/campaigns/{id}/contacts/bulk

Import hàng loạt contacts (async). Trả job_id ngay — FE phải poll GET /contacts/import/{job_id}. Contact trùng phone bị bỏ qua (đếm duplicateRows, không phải lỗi).

Authentication: Header X-Api-Key (scope: campaign). Kong dual-auth: ưu tiên X-Tenant-ID header, fallback query DB theo Authorization key.

Base URL: Dev: https://xapi-dev.alohub.vn  |  Prod: https://xapi.alohub.vn

Tham số

Tham số

Vị trí

Bắt buộc

Kiểu

Mô tả

Ví dụ

{id}

path

number

campaignId

1042

Request Body

{
  "listName": "Danh sach thang 4",
  "contacts": [
    {
      "phoneNumber": "0901000001",
      "name": "KH 1"
    },
    {
      "phoneNumber": "0901000002"
    }
  ]
}

Field

Bắt buộc

Mô tả

listName

Không

Tên list. Bỏ qua = tự đặt tên

contacts

Mảng contact — tối thiểu 1 item có phoneNumber

contacts[].phoneNumber

Số điện thoại

contacts[].name

Không

Tên khách hàng

Code mẫu

curl -X POST "https://xapi.alohub.vn/v1/campaigns/1042/contacts/bulk" \
  -H "X-Api-Key: sk_live_xxx" \
  -H "X-Tenant-ID: 20260310" \
  -H "Content-Type: application/json" \
  -d '{"listName":"DS thang 4","contacts":[{"phoneNumber":"0901000001"},{"phoneNumber":"0901000002"}]}'
const axios = require('axios');
const response = await axios.post(
  '{{host}}/api/v1/campaigns/{{id}}/contacts/bulk',
  {
  "listName": "Danh sach thang 4",
  "contacts": [
    {
      "phoneNumber": "0901000001",
      "name": "KH 1"
    },
    {
      "phoneNumber": "0901000002"
    }
  ]
},
  { headers: { 'Authorization': '{{api-key}}', 'X-Tenant-ID': '{{tenant-id}}', 'Content-Type': 'application/json' } }
);
console.log(response.data);
import requests

headers = {"Authorization": "{{api-key}}", "X-Tenant-ID": "{{tenant-id}}", "Content-Type": "application/json"}
payload = {
    "listName": "Danh sach thang 4",
    "contacts": [
        {
            "phoneNumber": "0901000001",
            "name": "KH 1"
        },
        {
            "phoneNumber": "0901000002"
        }
    ]
}
response = requests.post(
    '{{host}}/api/v1/campaigns/{{id}}/contacts/bulk',
    json=payload,
    headers=headers
)
print(response.json())

Response 200

{
  "success": "1",
  "error_code": "SUCCESS",
  "error_message": "Bulk import started",
  "job_id": 5,
  "total_rows": 2
}

Response Fields

Field

Kiểu

Mô tả

success

string

"1" = thành công

error_code

string

SUCCESS

error_message

string

"Bulk import started"

job_id

number

ID job — dùng để poll trạng thái

total_rows

number

Tổng số dòng nhận được

Error Codes

HTTP

error_code

Mô tả

FE xử lý

401

UNAUTHORIZED

Thiếu hoặc sai API key

Redirect nhập lại key

403

INSUFFICIENT_SCOPE

Key không có scope campaign

Hiện thông báo

400

INVALID_INPUT

Sai input

Hiện lỗi cụ thể

404

NOT_FOUND

Không tìm thấy

Hiện thông báo

429

RATE_LIMIT_EXCEEDED

Vượt giới hạn request

Retry sau Retry-After giây

500

FAIL

Lỗi hệ thống

Toast lỗi chung

Rate Limit Headers

Header

Mô tả

X-RateLimit-Limit-Tenant

Giới hạn tenant/10s

X-RateLimit-Remaining-Tenant

Còn lại tenant/10s

X-RateLimit-Limit-Route

Giới hạn route/10s

X-RateLimit-Remaining-Route

Còn lại route/10s

Retry-After

Giây cần chờ khi bị 429


GET /v1/campaigns/{id}/contacts/import/{job_id}

Poll trạng thái bulk import job. FE poll mỗi 2-3 giây cho đến khi status = done hoặc failed. job_id tồn tại trong RAM — server restart sẽ mất.

Authentication: Header X-Api-Key (scope: campaign). Kong dual-auth: ưu tiên X-Tenant-ID header, fallback query DB theo Authorization key.

Base URL: Dev: https://xapi-dev.alohub.vn  |  Prod: https://xapi.alohub.vn

Tham số

Tham số

Vị trí

Bắt buộc

Kiểu

Mô tả

Ví dụ

{id}

path

number

campaignId

1042

{job_id}

path

number

job_id nhận từ POST /contacts/bulk

5

Request Body

Code mẫu

# Poll mỗi 2-3 giây
curl -X GET "https://xapi.alohub.vn/v1/campaigns/1042/contacts/import/5" \
  -H "X-Api-Key: sk_live_xxx" \
  -H "X-Tenant-ID: 20260310"
const axios = require('axios');
const response = await axios.get(
  '{{host}}/api/v1/campaigns/{{id}}/contacts/import/{{job_id}}',
  { headers: { 'Authorization': '{{api-key}}', 'X-Tenant-ID': '{{tenant-id}}', 'Content-Type': 'application/json' } }
);
console.log(response.data);
import requests

headers = {"Authorization": "{{api-key}}", "X-Tenant-ID": "{{tenant-id}}", "Content-Type": "application/json"}
response = requests.get(
    '{{host}}/api/v1/campaigns/{{id}}/contacts/import/{{job_id}}',
    headers=headers
)
print(response.json())

Response 200

{
  "jobId": 5,
  "status": "processing",
  "totalRows": 100,
  "processedRows": 42,
  "failedRows": 0,
  "duplicateRows": 1
}

Response Fields

Field

Kiểu

Mô tả

jobId

number

ID job

status

string

pending / processing / done / failed

totalRows

number

Tổng số dòng

processedRows

number

Số dòng đã xử lý

failedRows

number

Số dòng lỗi

duplicateRows

number

Số dòng trùng bị bỏ qua

errorMessage

string

null

Mô tả lỗi khi status=failed

Error Codes

HTTP

error_code

Mô tả

FE xử lý

401

UNAUTHORIZED

Thiếu hoặc sai API key

Redirect nhập lại key

403

INSUFFICIENT_SCOPE

Key không có scope campaign

Hiện thông báo

404

NOT_FOUND

Không tìm thấy

Hiện thông báo

429

RATE_LIMIT_EXCEEDED

Vượt giới hạn request

Retry sau Retry-After giây

500

FAIL

Lỗi hệ thống

Toast lỗi chung

Rate Limit Headers

Header

Mô tả

X-RateLimit-Limit-Tenant

Giới hạn tenant/10s

X-RateLimit-Remaining-Tenant

Còn lại tenant/10s

X-RateLimit-Limit-Route

Giới hạn route/10s

X-RateLimit-Remaining-Route

Còn lại route/10s

Retry-After

Giây cần chờ khi bị 429


DELETE /v1/campaigns/{id}/contacts/{contactId}

Xoá 1 contact khỏi campaign. Chỉ xoá được contact có processStatus=0 (pending). Contact đang gọi (1) hoặc đã xử lý (2) không thể xoá.

Authentication: Header X-Api-Key (scope: campaign). Kong dual-auth: ưu tiên X-Tenant-ID header, fallback query DB theo Authorization key.

Base URL: Dev: https://xapi-dev.alohub.vn  |  Prod: https://xapi.alohub.vn

Tham số

Tham số

Vị trí

Bắt buộc

Kiểu

Mô tả

Ví dụ

{id}

path

number

campaignId

1042

{contactId}

path

number

contactId (từ GET /contacts — field contactId)

88001

Request Body

Code mẫu

curl -X DELETE "https://xapi.alohub.vn/v1/campaigns/1042/contacts/88001" \
  -H "X-Api-Key: sk_live_xxx" \
  -H "X-Tenant-ID: 20260310"
const axios = require('axios');
const response = await axios.delete(
  '{{host}}/api/v1/campaigns/{{id}}/contacts/{{contactId}}',
  { headers: { 'Authorization': '{{api-key}}', 'X-Tenant-ID': '{{tenant-id}}', 'Content-Type': 'application/json' } }
);
console.log(response.data);
import requests

headers = {"Authorization": "{{api-key}}", "X-Tenant-ID": "{{tenant-id}}", "Content-Type": "application/json"}
response = requests.delete(
    '{{host}}/api/v1/campaigns/{{id}}/contacts/{{contactId}}',
    headers=headers
)
print(response.json())

Response 200

{
  "success": "1",
  "error_code": "SUCCESS",
  "error_message": "Contact deleted successfully"
}

Response Fields

Field

Kiểu

Mô tả

success

string

"1" = thành công

error_code

string

SUCCESS

error_message

string

"Contact deleted successfully"

Error Codes

HTTP

error_code

Mô tả

FE xử lý

401

UNAUTHORIZED

Thiếu hoặc sai API key

Redirect nhập lại key

403

INSUFFICIENT_SCOPE

Key không có scope campaign

Hiện thông báo

404

NOT_FOUND

Không tìm thấy

Hiện thông báo

400

INVALID_STATE

Sai trạng thái (xem state machine)

Disable nút theo state

429

RATE_LIMIT_EXCEEDED

Vượt giới hạn request

Retry sau Retry-After giây

500

FAIL

Lỗi hệ thống

Toast lỗi chung

Rate Limit Headers

Header

Mô tả

X-RateLimit-Limit-Tenant

Giới hạn tenant/10s

X-RateLimit-Remaining-Tenant

Còn lại tenant/10s

X-RateLimit-Limit-Route

Giới hạn route/10s

X-RateLimit-Remaining-Route

Còn lại route/10s

Retry-After

Giây cần chờ khi bị 429


Was this article helpful?
Updated: 4/23/2026
để chuyển bài