Contacts


Contacts & Groups Management

Organize your recipients with contacts and groups to efficiently manage and target your messaging campaigns.


Overview

Contacts: Individual recipients with contact information (name, email, phone, company, tags)

Groups: Logical collections of contacts for targeted messaging (e.g., "VIP Customers", "Newsletter Subscribers")

Use Cases:

  • Send targeted campaigns to specific groups
  • Organize contacts by category, location, or custom criteria
  • Track and manage your audience database
  • Enable personalized bulk messaging

Contacts

Create Contact

Add a new contact to your organization.

Endpoint: POST https://api.notifyhub.com/contacts

Authentication: Required

Request:

{
  "name": "John Doe",
  "email": "john.doe@acme.com",
  "phone": "712345678",
  "countryCode": "+254",
  "organization": "Acme Corp",
  "tags": ["vip", "customer"],
  "groups": ["60d5f8e4c3f1a2b3c4d5e6f7"]
}

Field Descriptions:

| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | Yes | Contact's full name | | email | string | No | Email address (required for email channel) | | phone | string | No | Phone number without country code (required for SMS/WhatsApp) | | countryCode | string | No | Phone country code (e.g., "+254") | | organization | string | No | Contact's company/organization name | | tags | array | No | Custom tags for filtering/categorization | | groups | array | No | Array of group IDs this contact belongs to |

Note: At least one of email or phone is required for sending messages.

Response (201 Created):

{
  "_id": "6978abcd1234567890abcdef",
  "name": "John Doe",
  "email": "john.doe@acme.com",
  "phone": "712345678",
  "countryCode": "+254",
  "organization": "Acme Corp",
  "tags": ["vip", "customer"],
  "groups": ["60d5f8e4c3f1a2b3c4d5e6f7"],
  "NotifyhubOrganization": "695cc3b0212740bd1dba40d2",
  "createdAt": "2026-01-26T10:15:00.000Z",
  "updatedAt": "2026-01-26T10:15:00.000Z"
}

Example:

curl -X POST https://api.notifyhub.com/contacts \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "john.doe@acme.com",
    "phone": "712345678",
    "countryCode": "+254",
    "organization": "Acme Corp",
    "tags": ["vip"],
    "groups": ["60d5f8e4c3f1a2b3c4d5e6f7"]
  }'

List All Contacts

Retrieve all contacts in your organization.

Endpoint: GET https://api.notifyhub.com/contacts

Authentication: Required

Response (200 OK):

[
  {
    "_id": "6978abcd1234567890abcdef",
    "name": "John Doe",
    "email": "john.doe@acme.com",
    "phone": "712345678",
    "countryCode": "+254",
    "organization": "Acme Corp",
    "tags": ["vip"],
    "groups": ["60d5f8e4c3f1a2b3c4d5e6f7"],
    "createdAt": "2026-01-26T10:15:00.000Z",
    "updatedAt": "2026-01-26T10:15:00.000Z"
  },
  {
    "_id": "6978efgh1234567890ghijkl",
    "name": "Jane Smith",
    "email": "jane@example.com",
    "phone": "723456789",
    "countryCode": "+254",
    "organization": "Example Inc",
    "tags": ["customer"],
    "groups": [],
    "createdAt": "2026-01-25T14:30:00.000Z",
    "updatedAt": "2026-01-25T14:30:00.000Z"
  }
]

Example:

curl -X GET https://api.notifyhub.com/contacts \
  -H "Authorization: Bearer YOUR_TOKEN"
const response = await fetch('https://api.notifyhub.com/contacts', {
  headers: { 'Authorization': `Bearer ${token}` }
});
const contacts = await response.json();

Get Contact by ID

Retrieve a specific contact.

Endpoint: GET https://api.notifyhub.com/contacts/:id

Authentication: Required

Path Parameters:

  • id (required): Contact ID

Response (200 OK):

{
  "_id": "6978abcd1234567890abcdef",
  "name": "John Doe",
  "email": "john.doe@acme.com",
  "phone": "712345678",
  "countryCode": "+254",
  "organization": "Acme Corp",
  "tags": ["vip", "customer"],
  "groups": ["60d5f8e4c3f1a2b3c4d5e6f7"],
  "createdAt": "2026-01-26T10:15:00.000Z",
  "updatedAt": "2026-01-26T10:15:00.000Z"
}

Example:

curl -X GET https://api.notifyhub.com/contacts/6978abcd1234567890abcdef \
  -H "Authorization: Bearer YOUR_TOKEN"

Update Contact

Update contact information.

Endpoint: PUT https://api.notifyhub.com/contacts/:id

Authentication: Required

Path Parameters:

  • id (required): Contact ID

Request (partial update - send only fields to change):

{
  "name": "John Updated Doe",
  "email": "john.updated@acme.com",
  "phone": "723456789",
  "tags": ["vip", "premium"],
  "groups": ["60d5f8e4c3f1a2b3c4d5e6f7", "60d5f8e4c3f1a2b3c4d5e6f8"]
}

Response (200 OK):

{
  "_id": "6978abcd1234567890abcdef",
  "name": "John Updated Doe",
  "email": "john.updated@acme.com",
  "phone": "723456789",
  "countryCode": "+254",
  "organization": "Acme Corp",
  "tags": ["vip", "premium"],
  "groups": ["60d5f8e4c3f1a2b3c4d5e6f7", "60d5f8e4c3f1a2b3c4d5e6f8"],
  "createdAt": "2026-01-26T10:15:00.000Z",
  "updatedAt": "2026-01-27T09:30:00.000Z"
}

Example:

curl -X PUT https://api.notifyhub.com/contacts/6978abcd1234567890abcdef \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Updated Doe",
    "tags": ["vip", "premium"]
  }'

Delete Contact

Permanently delete a contact.

Endpoint: DELETE https://api.notifyhub.com/contacts/:id

Authentication: Required

Path Parameters:

  • id (required): Contact ID

Response (200 OK):

{
  "message": "Contact deleted successfully"
}

Example:

curl -X DELETE https://api.notifyhub.com/contacts/6978abcd1234567890abcdef \
  -H "Authorization: Bearer YOUR_TOKEN"

Note: Deleting a contact does not remove them from groups or delete associated message logs.


Groups

Create Group

Create a new contact group.

Endpoint: POST https://api.notifyhub.com/groups

Authentication: Required

Request:

{
  "name": "VIP Customers",
  "description": "High-value clients requiring priority support",
  "color": "bg-blue-500/10 text-blue-500 border-blue-500/20"
}

Field Descriptions:

| Field | Type | Required | Description | |-------|------|----------|-------------| | name | string | Yes | Group name (must be unique within organization) | | description | string | No | Group description/purpose | | color | string | Yes | UI color theme (Tailwind CSS classes) |

Response (201 Created):

{
  "_id": "6978abcd1234567890abcdef",
  "name": "VIP Customers",
  "description": "High-value clients requiring priority support",
  "color": "bg-blue-500/10 text-blue-500 border-blue-500/20",
  "organization": "695cc3b0212740bd1dba40d2",
  "createdAt": "2026-01-26T10:15:00.000Z",
  "updatedAt": "2026-01-26T10:15:00.000Z"
}

Example:

curl -X POST https://api.notifyhub.com/groups \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "VIP Customers",
    "description": "High-value clients",
    "color": "bg-blue-500/10 text-blue-500 border-blue-500/20"
  }'

Color Options (recommended Tailwind classes):

const colors = [
  'bg-blue-500/10 text-blue-500 border-blue-500/20',
  'bg-green-500/10 text-green-500 border-green-500/20',
  'bg-purple-500/10 text-purple-500 border-purple-500/20',
  'bg-red-500/10 text-red-500 border-red-500/20',
  'bg-orange-500/10 text-orange-500 border-orange-500/20',
  'bg-pink-500/10 text-pink-500 border-pink-500/20',
  'bg-indigo-500/10 text-indigo-500 border-indigo-500/20',
  'bg-teal-500/10 text-teal-500 border-teal-500/20'
];

List All Groups

Retrieve all groups in your organization.

Endpoint: GET https://api.notifyhub.com/groups

Authentication: Required

Response (200 OK):

[
  {
    "_id": "6978abcd1234567890abcdef",
    "name": "VIP Customers",
    "description": "High-value clients",
    "color": "bg-blue-500/10 text-blue-500 border-blue-500/20",
    "organization": "695cc3b0212740bd1dba40d2",
    "createdAt": "2026-01-26T10:15:00.000Z",
    "updatedAt": "2026-01-26T10:15:00.000Z"
  },
  {
    "_id": "6978efgh1234567890ghijkl",
    "name": "Newsletter Subscribers",
    "description": "Monthly newsletter recipients",
    "color": "bg-green-500/10 text-green-500 border-green-500/20",
    "organization": "695cc3b0212740bd1dba40d2",
    "createdAt": "2026-01-25T14:30:00.000Z",
    "updatedAt": "2026-01-25T14:30:00.000Z"
  }
]

Example:

curl -X GET https://api.notifyhub.com/groups \
  -H "Authorization: Bearer YOUR_TOKEN"

Delete Group

Permanently delete a group.

Endpoint: DELETE https://api.notifyhub.com/groups/:id

Authentication: Required

Path Parameters:

  • id (required): Group ID

Response (200 OK):

{
  "message": "Group deleted successfully"
}

Example:

curl -X DELETE https://api.notifyhub.com/groups/6978abcd1234567890abcdef \
  -H "Authorization: Bearer YOUR_TOKEN"

Note: Deleting a group does not delete the contacts in that group. Contacts will simply no longer be associated with the deleted group.


Managing Group Membership

Contacts can belong to multiple groups. Membership is managed through the contacts endpoints.

Add Contact to Group

Update the contact's groups array to include the group ID.

curl -X PUT https://api.notifyhub.com/contacts/CONTACT_ID \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "groups": ["GROUP_ID_1", "GROUP_ID_2"]
  }'

Remove Contact from Group

Update the contact's groups array to exclude the group ID.

curl -X PUT https://api.notifyhub.com/contacts/CONTACT_ID \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "groups": ["GROUP_ID_1"]
  }'

Get Contacts in a Group

Filter contacts by group using your application logic:

// 1. Get all contacts
const contacts = await fetch('https://api.notifyhub.com/contacts', {
  headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json());
 
// 2. Filter by group ID
const groupId = '6978abcd1234567890abcdef';
const groupContacts = contacts.filter(contact => 
  contact.groups.includes(groupId)
);

Bulk Operations

Bulk Create Contacts

Create multiple contacts in a loop (future: dedicated bulk endpoint).

async function bulkCreateContacts(contacts, token) {
  const results = [];
  
  for (const contact of contacts) {
    try {
      const response = await fetch('https://api.notifyhub.com/contacts', {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(contact)
      });
      
      const result = await response.json();
      results.push({ success: true, contact: result });
    } catch (error) {
      results.push({ success: false, error: error.message });
    }
  }
  
  return results;
}
 
// Usage
const contactsToCreate = [
  { name: 'John Doe', email: 'john@example.com', phone: '712345678', countryCode: '+254' },
  { name: 'Jane Smith', email: 'jane@example.com', phone: '723456789', countryCode: '+254' }
];
 
const results = await bulkCreateContacts(contactsToCreate, token);

Import from CSV

const csv = require('csv-parser');
const fs = require('fs');
 
async function importContactsFromCSV(filePath, token) {
  const contacts = [];
  
  // Read CSV
  await new Promise((resolve) => {
    fs.createReadStream(filePath)
      .pipe(csv())
      .on('data', (row) => {
        contacts.push({
          name: row.name,
          email: row.email,
          phone: row.phone,
          countryCode: row.countryCode || '+254',
          organization: row.company,
          tags: row.tags ? row.tags.split(',') : []
        });
      })
      .on('end', resolve);
  });
  
  // Create contacts
  return await bulkCreateContacts(contacts, token);
}
 
// Usage
await importContactsFromCSV('contacts.csv', token);

CSV Format:

name,email,phone,countryCode,company,tags
John Doe,john@example.com,712345678,+254,Acme Corp,vip,customer
Jane Smith,jane@example.com,723456789,+254,Example Inc,customer

Best Practices

1. Data Quality

// Validate before creating
function validateContact(contact) {
  const errors = [];
  
  if (!contact.name) {
    errors.push('Name is required');
  }
  
  if (!contact.email && !contact.phone) {
    errors.push('At least email or phone is required');
  }
  
  if (contact.email && !isValidEmail(contact.email)) {
    errors.push('Invalid email format');
  }
  
  if (contact.phone && !isValidPhone(contact.phone)) {
    errors.push('Invalid phone format');
  }
  
  return errors.length === 0 ? null : errors;
}
 
function isValidEmail(email) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
 
function isValidPhone(phone) {
  return /^\d{9,15}$/.test(phone);
}

2. Tag Strategy

Use consistent, lowercase tags for easier filtering:

const tagCategories = {
  status: ['active', 'inactive', 'pending'],
  tier: ['vip', 'premium', 'standard'],
  source: ['website', 'referral', 'event'],
  engagement: ['high', 'medium', 'low']
};
 
// Good
{ tags: ['vip', 'active', 'website'] }
 
// Avoid
{ tags: ['VIP Customer', 'Very Active', 'From Website'] }

3. Group Organization

Create logical, non-overlapping groups:

// Good structure
const groups = [
  { name: 'VIP Customers', description: 'Top 10% by revenue' },
  { name: 'Newsletter Subscribers', description: 'Opted in for monthly updates' },
  { name: 'Trial Users', description: 'Active free trial users' },
  { name: 'Support Tickets', description: 'Open support cases' }
];
 
// Avoid overlapping or vague groups
// Bad: 'Important Customers', 'Other Customers', 'Miscellaneous'

4. Deduplication

Check for duplicates before creating:

async function createContactSafely(contact, token) {
  // 1. Get existing contacts
  const existing = await fetch('https://api.notifyhub.com/contacts', {
    headers: { 'Authorization': `Bearer ${token}` }
  }).then(r => r.json());
  
  // 2. Check for duplicates
  const duplicate = existing.find(c => 
    c.email === contact.email || 
    (c.phone === contact.phone && c.countryCode === contact.countryCode)
  );
  
  if (duplicate) {
    console.log('Contact already exists:', duplicate._id);
    return duplicate;
  }
  
  // 3. Create new contact
  return await fetch('https://api.notifyhub.com/contacts', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(contact)
  }).then(r => r.json());
}

Error Handling

Common Errors

400 Bad Request - Missing Required Fields:

{
  "statusCode": 400,
  "message": "name is required",
  "error": "Bad Request"
}

400 Bad Request - Duplicate Group Name:

{
  "statusCode": 400,
  "message": "Group name already exists in this organization",
  "error": "Bad Request"
}

404 Not Found:

{
  "statusCode": 404,
  "message": "Contact not found",
  "error": "Not Found"
}

Error Handling Example

async function safeCreateContact(contact, token) {
  try {
    const response = await fetch('https://api.notifyhub.com/contacts', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(contact)
    });
    
    if (!response.ok) {
      const error = await response.json();
      throw new Error(error.message);
    }
    
    return await response.json();
  } catch (error) {
    console.error('Failed to create contact:', error.message);
    return null;
  }
}

Next Steps: