Bulk upload contacts into one contact book using a JSON payload.
Upload Contacts
Summary
Bulk upload contacts into one contact book using a JSON payload.
Prerequisites
- Authorization: Bearer w91_live_xxx
- Content-Type: application/json for JSON requests
Related documentation
Endpoint: POST /api/v2/contact-books/{bookUid}/contacts/bulk. Bulk upload is JSON-only. CSV/XLSX multipart upload remains dashboard-only for now.
POST
/api/v2/contact-books/{bookUid}/contacts/bulk| Parameter | Type | Required | Description |
|---|---|---|---|
Authorization | header | Required | Bearer w91_public_token_here. Must be a global public API token. |
Content-Type | header | Required | Content-Type: application/json. |
bookUid | string | Required | Contact book UID, for example grp_abc. |
defaultCountryCode | string | Optional | Country code used to normalize local phone numbers, for example 91. |
contacts | array | Required | Array of contact objects. Maximum 1000 contacts per request. |
contacts[].phone | string | Required | Contact phone number. It is normalized using defaultCountryCode. |
contacts[].displayName | string | Optional | Readable contact name. |
contacts[].firstName | string | Optional | Optional first name. |
contacts[].lastName | string | Optional | Optional last name. |
contacts[].email | string | Optional | Optional email address. |
contacts[].companyName | string | Optional | Optional company name. |
contacts[].customFields | object | Optional | Optional developer-defined metadata. |
Bulk upload contacts
curl -X POST "https://graph.whats91.com/api/v2/contact-books/grp_abc/contacts/bulk" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"defaultCountryCode": "91",
"contacts": [
{
"phone": "7000782082",
"displayName": "Asha Rao",
"firstName": "Asha",
"lastName": "Rao",
"email": "asha@example.com",
"companyName": "Acme",
"customFields": {
"city": "Mumbai"
}
}
]
}'Upload response
{
"success": true,
"message": "Contacts uploaded",
"data": {
"contactBook": {
"contactBookUid": "grp_abc",
"name": "Retail Leads"
},
"summary": {
"total": 3,
"created": 1,
"updated": 1,
"skipped": 1,
"invalid": 0
},
"results": [
{
"row": 1,
"status": "UPDATED",
"contact": { "contactUid": "ct_existing", "phone": "917000782082" }
},
{
"row": 2,
"status": "CREATED",
"contact": { "contactUid": "ct_new", "phone": "917999999999" }
},
{
"row": 3,
"status": "SKIPPED",
"reason": "DUPLICATE_IN_REQUEST",
"phone": "917999999999"
}
]
}
}Bulk Upload Behavior
- Maximum 1000 contacts per request.
- Phone numbers are normalized using defaultCountryCode.
- Existing contacts are updated and linked to the contact book.
- New contacts are created and linked to the contact book.
- Duplicate numbers inside the same request are skipped with DUPLICATE_IN_REQUEST.
- Invalid rows do not fail the whole request; they are returned in row-level results.
Validation Errors
| HTTP | Error code | Scenario |
|---|---|---|
| 401 | MISSING_AUTH_TOKEN | No public API token supplied. |
| 401 | INVALID_AUTH_TOKEN | Token is invalid, expired, revoked, or user inactive. |
| 403 | TOKEN_SCOPE_NOT_ALLOWED | Token is number-scoped; contact books require a global token. |
| 403 | FEATURE_NOT_AVAILABLE | Customer subscription does not include contacts. |
| 400 | VALIDATION_FAILED | Invalid pagination, missing or long name, invalid contacts payload, too many contacts, or invalid custom fields. |
| 404 | CONTACT_BOOK_NOT_FOUND | Contact book UID does not belong to the authenticated customer. |
| 415 | UNSUPPORTED_CONTENT_TYPE | POST request is not JSON. |
SDK Examples
Use these examples as starting points for server-side implementations.
cURL
curl -X POST "https://graph.whats91.com/api/v2/contact-books/{bookUid}/contacts/bulk" \
-H "Authorization: Bearer w91_live_xxx" \
-H "Content-Type: application/json" \
-d 'curl -X POST "https://graph.whats91.com/api/v2/contact-books/grp_abc/contacts/bulk" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"defaultCountryCode": "91",
"contacts": [
{
"phone": "7000782082",
"displayName": "Asha Rao",
"firstName": "Asha",
"lastName": "Rao",
"email": "asha@example.com",
"companyName": "Acme",
"customFields": {
"city": "Mumbai"
}
}
]
}''Node.js
const response = await fetch("https://graph.whats91.com/api/v2/contact-books/{bookUid}/contacts/bulk", {
method: "POST",
headers: {
"Authorization": "Bearer w91_live_xxx",
"Content-Type": "application/json"
},
body: JSON.stringify(curl -X POST "https://graph.whats91.com/api/v2/contact-books/grp_abc/contacts/bulk" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"defaultCountryCode": "91",
"contacts": [
{
"phone": "7000782082",
"displayName": "Asha Rao",
"firstName": "Asha",
"lastName": "Rao",
"email": "asha@example.com",
"companyName": "Acme",
"customFields": {
"city": "Mumbai"
}
}
]
}')
});
const data = await response.json();
console.log(data);PHP
$ch = curl_init("https://graph.whats91.com/api/v2/contact-books/{bookUid}/contacts/bulk");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer w91_live_xxx",
"Content-Type: application/json"
],
CURLOPT_POSTFIELDS => json_encode(curl -X POST "https://graph.whats91.com/api/v2/contact-books/grp_abc/contacts/bulk" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"defaultCountryCode": "91",
"contacts": [
{
"phone": "7000782082",
"displayName": "Asha Rao",
"firstName": "Asha",
"lastName": "Rao",
"email": "asha@example.com",
"companyName": "Acme",
"customFields": {
"city": "Mumbai"
}
}
]
}')
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;Python
import requests
response = requests.request(
"POST",
"https://graph.whats91.com/api/v2/contact-books/{bookUid}/contacts/bulk",
headers={
"Authorization": "Bearer w91_live_xxx",
"Content-Type": "application/json",
},
json=curl -X POST "https://graph.whats91.com/api/v2/contact-books/grp_abc/contacts/bulk" \
-H "Authorization: Bearer w91_public_token_here" \
-H "Content-Type: application/json" \
-d '{
"defaultCountryCode": "91",
"contacts": [
{
"phone": "7000782082",
"displayName": "Asha Rao",
"firstName": "Asha",
"lastName": "Rao",
"email": "asha@example.com",
"companyName": "Acme",
"customFields": {
"city": "Mumbai"
}
}
]
}'
)
print(response.json())C#
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer w91_live_xxx");
var request = new HttpRequestMessage(HttpMethod.Post, "https://graph.whats91.com/api/v2/contact-books/{bookUid}/contacts/bulk");
request.Content = new StringContent(
"""curl -X POST \"https://graph.whats91.com/api/v2/contact-books/grp_abc/contacts/bulk\" \
-H \"Authorization: Bearer w91_public_token_here\" \
-H \"Content-Type: application/json\" \
-d '{
\"defaultCountryCode\": \"91\",
\"contacts\": [
{
\"phone\": \"7000782082\",
\"displayName\": \"Asha Rao\",
\"firstName\": \"Asha\",
\"lastName\": \"Rao\",
\"email\": \"asha@example.com\",
\"companyName\": \"Acme\",
\"customFields\": {
\"city\": \"Mumbai\"
}
}
]
}'""",
Encoding.UTF8,
"application/json"
);
var response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());