List contacts API with GET /api/v1/contacts
The list contacts API is GET /api/v1/contacts: it returns your business’s customers from WhatsApp, Messenger and Instagram, plus the ones your team added, newest first, 50 to a page. It needs a key with the contacts.read scope.
What does the contacts list return?
Section titled “What does the contacts list return?”It returns one page of customers in data, from the most recently first seen to the oldest, with a nextCursor for the next page, or null on the last page. A key reads its own business’s customers only.
Which parameters does it take?
Section titled “Which parameters does it take?”All parameters are optional, and any other parameter returns a 400:
| Parameter | Type | Default | Meaning |
|---|---|---|---|
limit | integer | 50 | Customers per page, up to 100 |
cursor | string | The previous page’s nextCursor. See cursor pagination | |
since | ISO instant | Customers first seen at or after this instant |
since needs a date and a time, with Z or an offset, such as 2026-10-01T00:00:00Z. A date alone is refused. If you write a + offset into the URL yourself, write it as %2B, since a + in a URL reads as a space.
How do I send the request?
Section titled “How do I send the request?”curl "https://api.mujib.ai/api/v1/contacts?limit=50&since=2026-10-01T00:00:00Z" \ -H "Authorization: Bearer $MUJIB_API_KEY"const url = new URL('https://api.mujib.ai/api/v1/contacts');url.searchParams.set('limit', '50');url.searchParams.set('since', '2026-10-01T00:00:00Z');
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.MUJIB_API_KEY}` },});const body = await res.json();if (!res.ok) throw new Error(`${res.status} ${body.error.code}: ${body.error.message}`);console.log(body.data.length, body.nextCursor);import osimport requests
res = requests.get( "https://api.mujib.ai/api/v1/contacts", params={"limit": 50, "since": "2026-10-01T00:00:00Z"}, headers={"Authorization": f"Bearer {os.environ['MUJIB_API_KEY']}"}, timeout=30,)body = res.json()if not res.ok: raise RuntimeError(f"{res.status_code} {body['error']['code']}: {body['error']['message']}")print(len(body["data"]), body["nextCursor"])To read every page to the end, use the function in cursor pagination.
What does the response look like?
Section titled “What does the response look like?”A 200. The data below is made up:
{ "data": [ { "id": "5d8f2a61-0c4e-4b7a-9f13-6e2b8c0d4a57", "name": "سارة", "phone": "962790000000", "channel": "whatsapp", "stage": "qualified", "tags": ["استشارة"], "createdAt": "2026-11-02T09:14:37.205Z", "lastActiveAt": "2026-11-03T16:40:02.918Z" }, { "id": "9b1e3c74-2a5d-4f08-8e6b-1c7d0a3f5e92", "name": null, "phone": null, "channel": "instagram", "stage": "new", "tags": [], "createdAt": "2026-10-28T14:05:12.481Z", "lastActiveAt": "2026-10-28T14:07:55.030Z" } ], "nextCursor": "MjAyNi0xMC0yOFQxNDowNToxMi40ODFafDliMWUzYzc0LTJhNWQtNGYwOC04ZTZiLTFjN2QwYTNmNWU5Mg"}Every customer always carries these fields; a field with no value comes as null, never missing:
| Field | Type | Meaning |
|---|---|---|
id | string | The customer’s stable id, for get a contact |
name | string or null | The customer’s name, or null when it is not known |
phone | string or null | The number as stored, often international digits without + such as 962790000000, or null when it is not known |
channel | string | Where the customer came from (see the next table) |
stage | string | The customer’s stage (see the table after it) |
tags | array of strings | The customer’s tags; an empty array when none |
createdAt | UTC instant | When the customer was first seen |
lastActiveAt | UTC instant | The customer’s last activity |
channel values:
| Value | Meaning |
|---|---|
whatsapp | Wrote to you on WhatsApp |
facebook | Wrote to you on Messenger |
instagram | Wrote to you on Instagram |
manual | Added by your team in the dashboard |
import | Imported from a file |
stage values, and what the dashboard calls them:
| Value | In the dashboard |
|---|---|
new | New |
engaged | Engaged |
qualified | Qualified |
won | Won |
lost | Lost |
What errors can it return?
Section titled “What errors can it return?”| HTTP | code | Why |
|---|---|---|
| 400 | VALIDATION_ERROR | An unknown parameter, a limit out of range, a since that is not a valid instant, or a cursor that cannot be read |
| 401 | UNAUTHORIZED | No key, or a key that is not valid |
| 403 | FORBIDDEN | The key lacks contacts.read |
| 429 | RATE_LIMITED | You went over a rate limit |
| 500 | INTERNAL | An unexpected server error |
The details, and what to do about each, are in API errors and rate limits.
Frequently asked questions
Does the list include Messenger and Instagram customers?
Yes. It includes customers from WhatsApp, Messenger and Instagram, the ones your team added by hand and the ones imported from a file. The channel field says where each came from.
Why is phone empty for some customers?
Because Mujib takes no phone number from Messenger and Instagram messages. A number appears when the customer gives it in the conversation or your team adds it.
Can I search by name or phone number?
No. The list takes limit, cursor and since only, and any other parameter returns a 400.
Do my team's notes about a customer come out?
No. Team notes, custom fields and what the agent remembers never leave through the API.