Skip to main content

Query Contacts

This endpoint retrieves a paginated list of contacts associated with the authenticated user’s company. It provides powerful filtering capabilities to segment your contact database by tags, categories, source names, and recent call activity. This is ideal for targeted campaign creation, lead qualification workflows, and comprehensive contact management.

Endpoint Details

  • URL: /contacts/query
  • Method: GET
  • Authentication: Required (API KEY or JWT Token)
  • Source: src/api/public_apis_v1/contact/company_contacts/company_contacts_controller.rs
  • Pagination: Supports page-based pagination with customizable page size

Key Features

  • Advanced Filtering: Filter contacts by multiple criteria simultaneously
  • Pagination Support: Efficiently retrieve large contact lists with page-based navigation
  • Search Capability: Full-text search across contact names and phone numbers
  • Call Status Tracking: Filter by last call outcome to identify follow-up opportunities
  • Source Attribution: Track and filter by contact acquisition sources
  • Tag & Category Management: Organize contacts using custom tags and categories

Request Headers

HeaderValueDescription
AuthorizationBearer <api_key>Your API KEY or JWT Token
Content-Typeapplication/jsonRequest content type

Query Parameters

ParameterTypeRequiredDescriptionExample
source_nameStringNoFilter contacts by their acquisition source"Website Form", "CSV Import", "Manual"
searchStringNoSearch term matching firstname, lastname, or phone number"John", "+1234567890"
last_call_statusesStringNoComma-separated list of call statuses to filter by"completed,busy,no-answer"
pageIntegerNoPage number for pagination (0-indexed)0, 1, 2 (default: 0)
per_pageIntegerNoNumber of contacts per page10, 50, 100 (default: 20)
tagsStringNoComma-separated list of tags to filter by"hot_lead,vip"
categoriesStringNoComma-separated list of categories to filter by"sales_qualified,marketing_qualified"

Filter Behavior

  • Multiple Filters: When multiple filters are applied, they work as AND conditions (contacts must match all criteria)
  • Multiple Values: Within a single filter parameter (e.g., tags), multiple values work as OR conditions (contacts can match any value)
  • Case Sensitivity: Search and filter parameters are case-insensitive
  • Partial Matching: The search parameter performs partial matching on names and phone numbers

Example Requests

Basic Request - Get First Page

curl -X GET "https://api.callab.ai/v1/contacts/query?page=0&per_page=20" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Filter by Source

curl -X GET "https://api.callab.ai/v1/contacts/query?source_name=Website%20Form&page=0" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Search for Specific Contact

curl -X GET "https://api.callab.ai/v1/contacts/query?search=John&page=0" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Filter by Call Status

curl -X GET "https://api.callab.ai/v1/contacts/query?last_call_statuses=completed,busy&page=0" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Advanced Filtering

curl -X GET "https://api.callab.ai/v1/contacts/query?tags=hot_lead,vip&categories=sales_qualified&last_call_statuses=no-answer&page=0&per_page=50" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

JavaScript/TypeScript Example

const queryContacts = async (filters = {}) => {
  const baseUrl = 'https://api.callab.ai/v1/contacts/query';
  const apiKey = 'YOUR_API_KEY';

  // Build query string from filters
  const params = new URLSearchParams({
    page: filters.page || 0,
    per_page: filters.perPage || 20,
    ...(filters.sourceName && { source_name: filters.sourceName }),
    ...(filters.search && { search: filters.search }),
    ...(filters.lastCallStatuses && { last_call_statuses: filters.lastCallStatuses }),
    ...(filters.tags && { tags: filters.tags }),
    ...(filters.categories && { categories: filters.categories })
  });

  try {
    const response = await fetch(`${baseUrl}?${params}`, {
      method: 'GET',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json'
      }
    });

    if (!response.ok) {
      throw new Error(`HTTP error! Status: ${response.status}`);
    }

    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Error querying contacts:', error);
    throw error;
  }
};

// Usage examples:
// Get all contacts
const allContacts = await queryContacts();

// Search for "John"
const searchResults = await queryContacts({ search: 'John' });

// Get hot leads with no answer status
const followUpContacts = await queryContacts({
  tags: 'hot_lead',
  lastCallStatuses: 'no-answer',
  page: 0,
  perPage: 50
});

Python Example

import requests
from typing import Optional, Dict, Any

def query_contacts(
    api_key: str,
    page: int = 0,
    per_page: int = 20,
    source_name: Optional[str] = None,
    search: Optional[str] = None,
    last_call_statuses: Optional[str] = None,
    tags: Optional[str] = None,
    categories: Optional[str] = None
) -> Dict[str, Any]:
    """
    Query contacts with various filters.

    Args:
        api_key: Your API authentication key
        page: Page number (0-indexed)
        per_page: Number of results per page
        source_name: Filter by contact source
        search: Search term for names/phone numbers
        last_call_statuses: Comma-separated call statuses
        tags: Comma-separated tags
        categories: Comma-separated categories

    Returns:
        API response with contacts data
    """
    url = "https://api.callab.ai/v1/contacts/query"
    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json"
    }

    params = {"page": page, "per_page": per_page}
    if source_name:
        params["source_name"] = source_name
    if search:
        params["search"] = search
    if last_call_statuses:
        params["last_call_statuses"] = last_call_statuses
    if tags:
        params["tags"] = tags
    if categories:
        params["categories"] = categories

    response = requests.get(url, headers=headers, params=params)

    if response.status_code == 200:
        return response.json()
    else:
        raise Exception(f"Error: {response.status_code} - {response.text}")

# Usage examples:
# Get first page of all contacts
contacts = query_contacts(api_key="YOUR_API_KEY")

# Search for specific contact
results = query_contacts(
    api_key="YOUR_API_KEY",
    search="John",
    page=0
)

# Get contacts needing follow-up
followup_list = query_contacts(
    api_key="YOUR_API_KEY",
    tags="hot_lead,vip",
    last_call_statuses="no-answer,busy",
    per_page=50
)

Response

Success Response

Status Code: 200 OK
{
  "status": "ok",
  "message": "ok",
  "data": {
    "total_count": 150,
    "data": [
      {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "company_id": "047efb70-8d78-4c6a-a9bf-0466739cf96a",
        "firstname": "John",
        "lastname": "Doe",
        "phone_number": "+1234567890",
        "metadata": {
          "email": "[email protected]",
          "company_name": "Acme Corp",
          "job_title": "Marketing Director",
          "custom_field": "custom_value"
        },
        "number_country_code": "+1",
        "last_call_status": "completed",
        "last_call_at": "2024-01-15T14:30:00Z",
        "last_call_duration": 180,
        "last_call_feedback": "Customer was very interested",
        "source_name": "Website Form",
        "tag_name": "hot_lead",
        "category_name": "sales_qualified",
        "notes": "Follow up next week",
        "created_at": "2024-01-10T09:00:00Z",
        "updated_at": "2024-01-15T14:32:00Z",
        "campaign_id": "650e8400-e29b-41d4-a716-446655440001",
        "status": "active",
        "workspace_id": "default"
      }
    ]
  }
}

Error Response

Status Code: 200 OK (with error status)
{
  "status": "error",
  "message": "error",
  "data": ""
}

Response Fields

Pagination Object

FieldTypeDescription
total_countIntegerTotal number of contacts matching the filter criteria
dataArrayArray of contact objects for the current page

Contact Object Fields

FieldTypeDescription
idUUIDUnique identifier for the contact
company_idUUIDCompany that owns this contact
firstnameStringContact’s first name
lastnameStringContact’s last name
phone_numberStringContact’s phone number in E.164 format
metadataObjectCustom metadata fields (email, company, job title, etc.)
number_country_codeStringCountry code of the phone number
last_call_statusStringStatus of most recent call (completed, busy, no-answer, etc.)
last_call_atDateTime or nullTimestamp of the last call
last_call_durationInteger or nullDuration of last call in seconds
last_call_feedbackString or nullFeedback from the most recent call
source_nameStringSource where contact was acquired
tag_nameStringTag label for categorization
category_nameStringCategory classification
notesString or nullAdditional notes about the contact
created_atDateTimeTimestamp when contact was created
updated_atDateTimeTimestamp when contact was last updated
campaign_idUUID or nullAssociated campaign identifier
statusStringContact status (active, inactive)
workspace_idStringWorkspace identifier

Use Cases

1. Lead Segmentation

Query contacts by tags and categories to create targeted segments for specific campaigns:
# Get all VIP sales-qualified leads
/contacts/query?tags=vip&categories=sales_qualified

2. Follow-Up Lists

Identify contacts who need follow-up based on their last call status:
# Get contacts with no-answer or busy status
/contacts/query?last_call_statuses=no-answer,busy

3. Source Analysis

Analyze contact acquisition by filtering by source:
# Get all contacts from website forms
/contacts/query?source_name=Website%20Form
Search for specific contacts by name or phone number:
# Search for "John"
/contacts/query?search=John

5. Campaign Preparation

Build targeted lists for new campaigns by combining multiple filters:
# Get hot leads from website that haven't been called
/contacts/query?tags=hot_lead&source_name=Website%20Form&last_call_statuses=never_called

6. CRM Export

Paginate through all contacts for data export or synchronization:
# Get page 1 with 100 contacts
/contacts/query?page=0&per_page=100
# Get page 2
/contacts/query?page=1&per_page=100

Pagination Best Practices

Calculating Total Pages

const totalPages = Math.ceil(response.data.total_count / perPage);

Iterating Through All Pages

async function getAllContacts(apiKey) {
  let allContacts = [];
  let page = 0;
  const perPage = 100;

  while (true) {
    const response = await queryContacts({ page, perPage });
    allContacts = allContacts.concat(response.data.data);

    if (response.data.data.length < perPage) {
      break; // Last page
    }
    page++;
  }

  return allContacts;
}

Common Call Statuses

StatusDescriptionFollow-Up Action
completedCall was successfully completedReview feedback, schedule follow-up if needed
busyContact’s line was busyRetry during different time
no-answerContact didn’t answerRetry at different time of day
failedCall failed to connectCheck phone number validity
voicemailCall went to voicemailLeave message and mark for follow-up
never_calledContact has never been calledPrime candidate for new campaigns

Notes

  • Performance: For large datasets, use reasonable per_page values (20-100) to balance response time and number of requests
  • Pagination Index: Page numbering starts at 0 (first page is page=0)
  • Filter Combinations: Multiple filters are applied as AND conditions - contacts must match all specified criteria
  • Empty Results: An empty data array with total_count=0 indicates no contacts match the filters
  • Rate Limiting: Consider implementing rate limiting when paginating through large datasets
  • Timestamps: All timestamps are in UTC format
  • Metadata Flexibility: The metadata field can contain any custom JSON structure
  • Search Performance: The search parameter performs case-insensitive partial matching across multiple fields