You will sign in with an email and password, receive an access token, and use it to list the contacts in your organisation. Every other REST call works the same way.
Before you start
- A Natiq user whose role includes
contacts:read. An admin can check this under Settings → roles (see Roles and permissions). - Your API host. Most workspaces use
https://api.cx.na6iq.com; a Saudi-region workspace useshttps://api.sa.na6iq.com. All REST routes sit under/api/v1.
Use a dedicated user for scripts
Create a user just for your integration and give it a role with only the permissions it needs. See Authentication.
1. Get a token
POST /auth/login takes an email and a password and returns the token.
sh
curl -s https://api.cx.na6iq.com/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"integration@example.com","password":"your-password"}'js
const API = 'https://api.cx.na6iq.com/api/v1'
const res = await fetch(`${API}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: 'integration@example.com', password: process.env.NATIQ_PASSWORD }),
})
const { accessToken } = await res.json()python
import os, requests
API = "https://api.cx.na6iq.com/api/v1"
session = requests.post(
f"{API}/auth/login",
json={"email": "integration@example.com", "password": os.environ["NATIQ_PASSWORD"]},
timeout=30,
).json()
token = session["accessToken"]The response:
json
{
"accessToken": "eyJhbGciOiJIUzI1NiJ9…",
"orgId": 12,
"userId": 34,
"email": "integration@example.com",
"tokenType": "Bearer",
"expiresInHours": 24
}Treat the token like a password.
2. Call GET /contacts
Send the token as a Bearer header. GET /contacts is paginated and returns contacts oldest first (by id).
sh
curl -s 'https://api.cx.na6iq.com/api/v1/contacts?page=0&size=20' \
-H "Authorization: Bearer $TOKEN"js
const page = await fetch(`${API}/contacts?page=0&size=20`, {
headers: { Authorization: `Bearer ${accessToken}` },
}).then((r) => r.json())
console.log(page.totalElements, page.data[0])python
page = requests.get(
f"{API}/contacts",
params={"page": 0, "size": 20},
headers={"Authorization": f"Bearer {token}"},
timeout=30,
).json()
print(page["totalElements"], page["data"][:1])3. Read the page
json
{
"data": [
{
"id": 1842,
"externalId": "crm-55102",
"firstName": null,
"lastName": null,
"displayName": "Layla Haddad",
"phone": "+962791234567",
"email": "layla@example.com",
"avatarUrl": null,
"status": "customer",
"lists": [{ "id": 7, "name": "VIP customers" }]
}
],
"page": 0,
"size": 20,
"totalElements": 1,
"totalPages": 1
}| Field | Meaning |
|---|---|
data | The items on this page. |
page | Zero-based index of this page. |
size | Page size you asked for (default 20). Keep it at 100 or below. |
totalElements | How many contacts match in total. |
totalPages | How many pages exist at this size. |
To walk through everything, request page=1, page=2 … until page reaches totalPages - 1. See Making requests.
If something goes wrong
| You see | Likely cause |
|---|---|
401 INVALID_CREDENTIALS | Wrong email or password. |
401 | The token is missing (UNAUTHENTICATED), was signed out (SESSION_REVOKED), or is expired or malformed (this one may come with no JSON body). Sign in again. |
403 PERMISSION_DENIED | Your role lacks contacts:read. |
Errors share one envelope, described in Making requests.