CONTACT API

Contact & Group Management

Full CRUD over contacts and groups — single or bulk (up to 50,000 per request), with tags, custom fields and opt-out controls.

Reference

Manage your contacts and groups programmatically using your vendor API key. All endpoints accept and return JSON, are scoped to a single WhatsApp number (encodedPhoneId) and require an r/w-scoped Bearer token.

Resources

Download the collection

Endpoints

Base URLs

Base URLDescription
https://your-api.com/apiBackend API — direct connection
https://your-domain.com/apiFrontend Proxy — same body format, same token

Security

Authentication

Every request must include a valid Bearer token. Generate one from WhatsApp Settings → API & Webhook → API Keys.

terminal
curl https://your-api.com/api/external/contacts/{encodedPhoneId} \
  -H "Authorization: Bearer <your_api_token>"

Access control

Permissions

PermissionGrants access to
read_contactsGET (list, get single, list groups, get group)
write_contactsPOST, PUT, DELETE (create, update, delete contacts & groups; bulk import)
A token may hold both permissions simultaneously.

Routes

Endpoints overview

MethodPathPermission
GET/api/external/contacts/{phoneId}read_contacts
POST/api/external/contacts/{phoneId}write_contacts
GET/api/external/contacts/{phoneId}/{id}read_contacts
PUT/api/external/contacts/{phoneId}/{id}write_contacts
DELETE/api/external/contacts/{phoneId}/{id}write_contacts
POST/api/external/contacts/{phoneId}/bulkwrite_contacts
GET/api/external/contacts/{phoneId}/groupsread_contacts
POST/api/external/contacts/{phoneId}/groupswrite_contacts
GET/api/external/contacts/{phoneId}/groups/{groupId}read_contacts
PUT/api/external/contacts/{phoneId}/groups/{groupId}write_contacts
DELETE/api/external/contacts/{phoneId}/groups/{groupId}write_contacts
POST/api/external/contacts/{phoneId}/groups/{groupId}/addwrite_contacts
POST/api/external/contacts/{phoneId}/groups/{groupId}/removewrite_contacts

Schema

Contact object

contact.json
{
  "_id": "64f1a2b3c4d5e6f7a8b9c0d1",
  "name": "John Doe",
  "phone": "919876543210",
  "email": "john@example.com",
  "language_code": "en",
  "tags": ["vip", "newsletter"],
  "notes": "Preferred contact via WhatsApp.",
  "opt_out": false,
  "opt_out_marketing": false,
  "reply_bot_enabled": true,
  "custom_fields": {
    "city": "Mumbai",
    "loyalty_tier": "gold"
  },
  "createdAt": "2024-01-15T10:30:00.000Z",
  "updatedAt": "2024-01-20T14:22:00.000Z"
}

GET

1. List contacts

GET/api/external/contacts/{encodedPhoneId}

Query parameters

ParameterTypeDescription
searchstringSearch by name or phone
tagstringFilter by a single tag
opt_outbooleanFilter opted-out contacts
pagenumberPage number (default: 1)
limitnumberResults per page (default: 20, max: 100)
terminal
curl "https://your-api.com/api/external/contacts/{phoneId}?search=john&tag=vip&page=1&limit=20" \
  -H "Authorization: Bearer <token>"

Response

response.json
{
  "success": true,
  "data": {
    "contacts": [
      {
        "_id": "64f1a2b3c4d5e6f7a8b9c0d1",
        "name": "John Doe",
        "phone": "919876543210",
        "email": "john@example.com",
        "tags": ["vip"],
        "opt_out": false,
        "createdAt": "2024-01-15T10:30:00.000Z"
      }
    ],
    "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }
  },
  "message": "Contacts retrieved successfully."
}

GET

2. Get contact

GET/api/external/contacts/{encodedPhoneId}/{contactId}
response.json
{
  "success": true,
  "data": { "contact": { /* ...contactObject */ } },
  "message": "Contact retrieved successfully."
}

POST

3. Create contact

POST/api/external/contacts/{encodedPhoneId}

Body

FieldTypeRequiredDescription
namestringYesFull name
phonestringYesPhone in E.164 format (e.g. +919876543210)
emailstringNoEmail address
language_codestringNoe.g. en, hi, ar
tagsstring[]NoArray of label strings
notesstringNoFree-text notes (max 2000 chars)
opt_outbooleanNoBlock all outbound messages (default: false)
opt_out_marketingbooleanNoExclude from campaigns (default: false)
reply_bot_enabledbooleanNoAllow chatbot to reply (default: true)
custom_fieldsobjectNoKey-value map of custom field values
terminal
curl -X POST https://your-api.com/api/external/contacts/{phoneId} \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Smith",
    "phone": "+919876543210",
    "email": "jane@example.com",
    "language_code": "en",
    "tags": ["customer", "vip"],
    "notes": "High-value customer",
    "reply_bot_enabled": true,
    "custom_fields": {
      "city": "Delhi",
      "loyalty_tier": "platinum"
    }
  }'

PUT

4. Update contact

PUT/api/external/contacts/{encodedPhoneId}/{contactId}

Send only the fields you want to update — everything else is preserved.

terminal
curl -X PUT https://your-api.com/api/external/contacts/{phoneId}/{contactId} \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "tags": ["vip", "renewed"],
    "custom_fields": { "loyalty_tier": "gold" }
  }'

DELETE

5. Delete contact

DELETE/api/external/contacts/{encodedPhoneId}/{contactId}

Deletes the contact and removes them from all groups.

POST

6. Bulk import contacts

POST/api/external/contacts/{encodedPhoneId}/bulk

Import or update up to 50,000 contacts in a single request. Contacts are upserted by phone number.

bulk.json
{
  "contacts": [
    {
      "name": "John Doe",
      "phone": "+919876543210",
      "email": "john@example.com",
      "language_code": "en",
      "tags": ["newsletter"],
      "groups": ["VIP Customers"],
      "custom_fields": { "city": "Mumbai" }
    },
    {
      "name": "Jane Smith",
      "phone": "+919812345678"
    }
  ]
}

Bulk field reference

FieldTypeRequiredDescription
namestringNoFull name (or use first_name + last_name)
first_namestringNoCombined with last_name
last_namestringNoCombined with first_name
phonestringYesE.164 format
emailstringNoEmail address
language_codestringNoe.g. en, hi
tagsstring[]NoArray of tag strings
groupsstring[]NoGroup names — auto-created if missing
custom_fieldsobjectNoKey-value custom field values
response.json
{
  "success": true,
  "data": { "created": 150, "updated": 42, "skipped": 3, "errors": [] },
  "message": "Bulk import complete."
}

Groups

7-13. Group operations

List groups

GET/api/external/contacts/{encodedPhoneId}/groups
response.json
{
  "success": true,
  "data": {
    "groups": [
      {
        "_id": "64f1a2b3c4d5e6f7a8b9c0d2",
        "name": "VIP Customers",
        "description": "High-value customers",
        "contacts": ["id1", "id2"],
        "createdAt": "2024-01-10T08:00:00.000Z"
      }
    ],
    "pagination": { "page": 1, "limit": 20, "total": 1, "totalPages": 1 }
  },
  "message": "Groups retrieved successfully."
}

Create group

POST/api/external/contacts/{encodedPhoneId}/groups
body.json
{
  "name": "Newsletter Subscribers",
  "description": "Contacts subscribed to the weekly newsletter"
}

Get group

GET/api/external/contacts/{encodedPhoneId}/groups/{groupId}

Returns the group with its full contact list (populated).

Update group

PUT/api/external/contacts/{encodedPhoneId}/groups/{groupId}
body.json
{
  "name": "Premium Subscribers",
  "description": "Updated description"
}

Delete group

DELETE/api/external/contacts/{encodedPhoneId}/groups/{groupId}

Deletes the group only — contacts are NOT deleted.

Add / remove contacts

POST/api/external/contacts/{encodedPhoneId}/groups/{groupId}/add
POST/api/external/contacts/{encodedPhoneId}/groups/{groupId}/remove
body.json
{
  "contact_ids": ["64f1a2b3c4d5e6f7a8b9c0d1", "64f1a2b3c4d5e6f7a8b9c0d4"]
}

Edge cases

Errors

HTTPMeaning
400Bad Request — missing required fields or invalid data
401Unauthorized — missing, invalid, or expired Bearer token
403Forbidden — token does not have required permission
404Not Found — contact or group id does not exist
409Conflict — phone number already exists (on create)
500Internal Server Error
error.json
{
  "success": false,
  "message": "A contact with this phone number already exists."
}

Advanced

Custom fields

Custom fields must be defined first in the dashboard (Contacts → Fields tab) before values can be stored. The custom_fields object uses the field's internal key as the property name.

custom_fields.json
{
  "custom_fields": {
    "city": "Mumbai",
    "loyalty_tier": "gold"
  }
}
Unknown field names are silently ignored by the backend.
Rate limit: 100 requests / 15 minutes per token.