Zernio
Zernio
PlatformsWhatsAppConnection & SetupBroadcastsTemplatesContacts & ProfilePhone NumbersCallingSandboxGroup ChatsInboxMeta Business AgentFlowsClick-to-WhatsApp AdsPricing & CostsMedia & Limits
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
WhatsApp

Contacts & Profile

Create and import contacts with a WhatsApp channel for broadcasts, and read or update the WhatsApp business profile.


When you finish this page you have contacts with a WhatsApp channel that broadcasts can target by tag, and the business profile customers see is up to date. You need a connected WhatsApp account, its accountId and its profileId. A contact is a person in your CRM; the channel on it is the phone number Zernio messages through your WhatsApp account.

Step 1: Create a contact

Call POST /v1/contacts with profileId and name. Add accountId, platform: "whatsapp" and platformIdentifier (the phone in E.164) together to create the WhatsApp channel in the same request; the three are all-or-nothing.

import Zernio from '@zernio/node';

const zernio = new Zernio();
const profileId = '66a1f0c2a4b9d3e8f1a2b3c4';
const accountId = '66b2e19d8c3f5a7e9d0b1c2d';

const { data: created } = await zernio.contacts.createContact({
  body: {
    profileId,
    name: 'Ana Costa',
    email: 'ana@example.com',
    tags: ['vip', 'newsletter'],
    accountId,
    platform: 'whatsapp',
    platformIdentifier: '+13105551234'
  }
});

const contactId = created.contact.id;

Response (200):

{
  "success": true,
  "contact": {
    "id": "66e5b2c3d4f5a6b7c8d9e0f1",
    "name": "Ana Costa",
    "email": "ana@example.com",
    "tags": ["vip", "newsletter"],
    "isSubscribed": true,
    "isBlocked": false,
    "createdAt": "2027-01-01T09:00:00Z"
  },
  "channel": {
    "id": "66e5b2c3d4f5a6b7c8d9e0f9",
    "platform": "whatsapp",
    "platformIdentifier": "13105551234"
  }
}

contact.id is the id broadcasts take in contactIds.

Step 2: Import contacts in bulk

Call POST /v1/contacts/bulk with up to 1,000 contacts. With accountId set, every row needs a platformIdentifier; on WhatsApp it is normalized to digits, and a value that is not phone-shaped is rejected per row in errors[] rather than failing the import. Duplicates are skipped and their new tags merged onto the existing contact.

const { data: imported } = await zernio.contacts.bulkCreateContacts({
  body: {
    profileId,
    accountId,
    contacts: [
      { name: 'Ana Costa', platformIdentifier: '+13105551234', tags: ['vip'] },
      { name: 'Ben Okafor', platformIdentifier: '+442071234567', tags: ['newsletter'] }
    ]
  }
});

console.log(imported.created, imported.skipped, imported.errors);

Response (200):

{
  "success": true,
  "created": 1,
  "skipped": 1,
  "errors": [],
  "total": 2
}

Ana was skipped because Step 1 already created her; her vip tag was already there.

Step 3: Update a contact

Call PATCH /v1/contacts/{contactId} with the fields to change. Only the fields you send are written. isSubscribed: false drops the contact from segment-targeted broadcasts.

const { data: updated } = await zernio.contacts.updateContact({
  path: { contactId },
  body: { tags: ['vip', 'promo-2027'], isSubscribed: true }
});

console.log(updated.contact.tags);

Response (200):

{
  "success": true,
  "contact": {
    "id": "66e5b2c3d4f5a6b7c8d9e0f1",
    "name": "Ana Costa",
    "tags": ["vip", "promo-2027"],
    "isSubscribed": true,
    "isBlocked": false,
    "updatedAt": "2027-01-01T09:05:00Z"
  }
}

Business profile

The business profile is what customers see when they open your number in WhatsApp. Read it with GET /v1/whatsapp/business-profile and change it with POST /v1/whatsapp/business-profile; only the fields you send are updated. about is at most 139 characters, description at most 512, and websites holds at most 2 entries.

const { data: profile } = await zernio.whatsapp.getWhatsAppBusinessProfile({
  query: { accountId }
});

console.log(profile.businessProfile.about);

await zernio.whatsapp.updateWhatsAppBusinessProfile({
  body: {
    accountId,
    about: 'Widgets, shipped the same day',
    description: 'Acme sells widgets to workshops in 40 countries.',
    email: 'hello@example.com',
    websites: ['https://example.com']
  }
});

Response (200), the read:

{
  "success": true,
  "businessProfile": {
    "about": "Widgets, shipped the same day",
    "address": "1 Main St, Springfield",
    "description": "Acme sells widgets to workshops in 40 countries.",
    "email": "hello@example.com",
    "profilePictureUrl": "https://...",
    "websites": ["https://example.com"],
    "vertical": "RETAIL"
  }
}

Response (200), the update:

{
  "success": true,
  "message": "Business profile updated successfully"
}

The profile picture, display name and WhatsApp username have their own endpoints under Business profile; on a coexistence number the picture is locked and managed in the WhatsApp Business app.

If it fails

A 409 from Step 1 means the phone number is already a channel on this account:

{
  "error": "Duplicate channel. The platformIdentifier is already bound to a channel on this accountId."
}

Look the contact up with List contacts and update it instead, or use the bulk import, which skips duplicates rather than rejecting them. A 400 with code missing_required_field means accountId, platform and platformIdentifier were not sent together. Every error uses the envelope in error handling.

Related

  • Broadcasts: target these contacts by phone, id or tag.
  • Contacts API: list, get, delete, channels and custom fields.
  • Business profile API: photo, display name and username.
  • WhatsApp inbox: the conversations these contacts appear in.
Was this page helpful?

Templates

Create WhatsApp message templates, read Meta's review verdict, and import pre-approved templates from Meta's library.

Phone Numbers

Which phone number gets WhatsApp, how to read its live status from Meta, the liveness check, and registering a number that has a two-step PIN.

On this page

Step 1: Create a contactStep 2: Import contacts in bulkStep 3: Update a contactBusiness profileIf it failsRelated