> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cometly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# List Contacts

> Retrieve a paginated list of contacts filtered by creation date

## Overview

This endpoint allows you to retrieve a paginated list of contacts from Cometly within a specific date range. Each contact includes primary data from the profile (email, name, phone, location). For complete contact information including all associated emails, phones, names, and locations from merged profiles, use the individual contact endpoint GET /contacts/{id}. Results are cursor-paginated for efficient data retrieval and ordered by ID (newest first).

## Query Parameters

### Required Parameters

<ParamField query="start_date" type="string" required>
  Start date and time for filtering contacts by creation date in `YYYY-MM-DD HH:MM:SS` format. The date is interpreted in your space's timezone.

  Example: `2024-01-15 00:00:00`
</ParamField>

<ParamField query="end_date" type="string" required>
  End date and time for filtering contacts by creation date in `YYYY-MM-DD HH:MM:SS` format. Must be after `start_date`. The date is interpreted in your space's timezone.

  Example: `2024-01-15 23:59:59`
</ParamField>

### Optional Parameters

<ParamField query="per_page" type="integer" default="200">
  Number of contacts to return per page. Minimum: 1, Maximum: 5000
</ParamField>

<ParamField query="cursor" type="string">
  Pagination cursor from a previous response. Use this to fetch the next page of results.
</ParamField>

<ParamField query="include_comet_tokens" type="boolean" default="0">
  When set to `1`, includes the last 5 comet tokens for each contact, ordered by most recent first. Accepts `1` or `0`.
</ParamField>

<ParamField query="include_all_emails" type="boolean" default="0">
  When set to `1`, includes all email addresses associated with the contact (including emails from merged profiles). Accepts `1` or `0`.
</ParamField>

<ParamField query="include_custom_fields" type="boolean" default="0">
  When set to `1`, includes all 30 custom field columns for each contact. Fields 1-15 are text, 16-25 are numeric, 26-30 are date. Accepts `1` or `0`.
</ParamField>

<ParamField query="use_custom_field_labels" type="boolean" default="0">
  When set to `1`, custom field keys in the response will use the user-defined labels (e.g. `"Customer Age"`) instead of the raw column names (e.g. `"profile_field_1"`). Only applies when `include_custom_fields=1`. Fields without a configured label will keep their raw column name. Accepts `1` or `0`.
</ParamField>

## Response

### Success Response

The response follows Laravel's cursor pagination structure:

<ResponseField name="data" type="array">
  Array of contact objects. Each contact includes:

  * `id` (integer): The unique identifier of the contact
  * `email` (string|null): Primary email address
  * `name` (string|null): Primary name
  * `phone` (string|null): Primary phone number
  * `location` (string|null): Primary location
  * `comet_tokens` (array): Array of comet tokens (only included when `include_comet_tokens=1`)
  * `emails` (array): Array of all email addresses associated with the contact, including emails from merged profiles (only included when `include_all_emails=1`)
  * `profile_field_1` through `profile_field_30`: Custom field values (only included when `include_custom_fields=1`). Fields 1-15 are text (string|null), 16-25 are numeric (number|null), 26-30 are date (string|null)
</ResponseField>

<ResponseField name="path" type="string">
  The base URL path for the endpoint
</ResponseField>

<ResponseField name="per_page" type="integer">
  Number of items per page
</ResponseField>

<ResponseField name="next_cursor" type="string | null">
  Cursor for the next page of results. `null` if there are no more pages.
</ResponseField>

<ResponseField name="next_page_url" type="string | null">
  Full URL for the next page of results. `null` if there are no more pages.
</ResponseField>

<ResponseField name="prev_cursor" type="string | null">
  Cursor for the previous page of results. `null` if on the first page.
</ResponseField>

<ResponseField name="prev_page_url" type="string | null">
  Full URL for the previous page of results. `null` if on the first page.
</ResponseField>

### Error Response

<ResponseField name="message" type="string">
  Error description explaining what went wrong
</ResponseField>

## Example Requests

<CodeGroup>
  ```bash cURL theme={null}
  # Basic request
  curl -G "https://app.cometly.com/public-api/v1/contacts" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d "start_date=2024-01-15 00:00:00" \
    -d "end_date=2024-01-15 23:59:59"

  # Include comet tokens
  curl -G "https://app.cometly.com/public-api/v1/contacts" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d "start_date=2024-01-15 00:00:00" \
    -d "end_date=2024-01-15 23:59:59" \
    -d "include_comet_tokens=1"

  # Include all emails
  curl -G "https://app.cometly.com/public-api/v1/contacts" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d "start_date=2024-01-15 00:00:00" \
    -d "end_date=2024-01-15 23:59:59" \
    -d "include_all_emails=1"

  # Pagination request using cursor
  curl -G "https://app.cometly.com/public-api/v1/contacts" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d "start_date=2024-01-15 00:00:00" \
    -d "end_date=2024-01-15 23:59:59" \
    -d "cursor=eyJpZCI6MTIzNDU..."
  ```

  ```javascript JavaScript theme={null}
  // Basic request
  const params = new URLSearchParams({
    start_date: '2024-01-15 00:00:00',
    end_date: '2024-01-15 23:59:59'
  });

  const response = await fetch(`https://app.cometly.com/public-api/v1/contacts?${params}`, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }
  });

  const data = await response.json();

  // Include comet tokens
  const paramsWithTokens = new URLSearchParams({
    start_date: '2024-01-15 00:00:00',
    end_date: '2024-01-15 23:59:59',
    include_comet_tokens: 1
  });

  // Include all emails
  const paramsWithEmails = new URLSearchParams({
    start_date: '2024-01-15 00:00:00',
    end_date: '2024-01-15 23:59:59',
    include_all_emails: 1
  });

  const responseWithEmails = await fetch(`https://app.cometly.com/public-api/v1/contacts?${paramsWithEmails}`, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }
  });

  const dataWithEmails = await responseWithEmails.json();

  const responseWithTokens = await fetch(`https://app.cometly.com/public-api/v1/contacts?${paramsWithTokens}`, {
    method: 'GET',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    }
  });

  const dataWithTokens = await responseWithTokens.json();

  // Pagination using cursor from previous response
  if (data.next_cursor) {
    const nextParams = new URLSearchParams({
      start_date: '2024-01-15 00:00:00',
      end_date: '2024-01-15 23:59:59',
      cursor: data.next_cursor
    });

    const nextPage = await fetch(`https://app.cometly.com/public-api/v1/contacts?${nextParams}`, {
      method: 'GET',
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      }
    });
  }
  ```

  ```php PHP theme={null}
  <?php
  // Basic request
  $baseUrl = 'https://app.cometly.com/public-api/v1/contacts';
  $headers = [
      'Authorization: Bearer YOUR_API_KEY',
      'Accept: application/json',
      'Content-Type: application/json'
  ];

  $params = http_build_query([
      'start_date' => '2024-01-15 00:00:00',
      'end_date' => '2024-01-15 23:59:59'
  ]);

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $baseUrl . '?' . $params);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  $data = json_decode($response, true);
  curl_close($ch);

  // Include comet tokens
  $paramsWithTokens = http_build_query([
      'start_date' => '2024-01-15 00:00:00',
      'end_date' => '2024-01-15 23:59:59',
      'include_comet_tokens' => 1
  ]);

  // Include all emails
  $paramsWithEmails = http_build_query([
      'start_date' => '2024-01-15 00:00:00',
      'end_date' => '2024-01-15 23:59:59',
      'include_all_emails' => 1
  ]);

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $baseUrl . '?' . $paramsWithEmails);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $responseWithEmails = curl_exec($ch);
  $dataWithEmails = json_decode($responseWithEmails, true);
  curl_close($ch);

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $baseUrl . '?' . $paramsWithTokens);
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $responseWithTokens = curl_exec($ch);
  $dataWithTokens = json_decode($responseWithTokens, true);
  curl_close($ch);

  // Pagination using cursor
  if (!empty($data['next_cursor'])) {
      $nextParams = http_build_query([
          'start_date' => '2024-01-15 00:00:00',
          'end_date' => '2024-01-15 23:59:59',
          'cursor' => $data['next_cursor']
      ]);

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, $baseUrl . '?' . $nextParams);
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

      $nextResponse = curl_exec($ch);
      curl_close($ch);
  }
  ?>
  ```

  ```python Python theme={null}
  import requests

  # Basic request
  base_url = 'https://app.cometly.com/public-api/v1/contacts'
  headers = {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
  }

  params = {
      'start_date': '2024-01-15 00:00:00',
      'end_date': '2024-01-15 23:59:59'
  }

  response = requests.get(base_url, headers=headers, params=params)
  data = response.json()

  # Include comet tokens
  params_with_tokens = {
      'start_date': '2024-01-15 00:00:00',
      'end_date': '2024-01-15 23:59:59',
      'include_comet_tokens': 1
  }

  # Include all emails
  params_with_emails = {
      'start_date': '2024-01-15 00:00:00',
      'end_date': '2024-01-15 23:59:59',
      'include_all_emails': 1
  }

  response_with_emails = requests.get(base_url, headers=headers, params=params_with_emails)
  data_with_emails = response_with_emails.json()

  response_with_tokens = requests.get(base_url, headers=headers, params=params_with_tokens)
  data_with_tokens = response_with_tokens.json()

  # Pagination using cursor from previous response
  if data.get('next_cursor'):
      next_params = {
          'start_date': '2024-01-15 00:00:00',
          'end_date': '2024-01-15 23:59:59',
          'cursor': data['next_cursor']
      }

      next_response = requests.get(base_url, headers=headers, params=next_params)
      next_data = next_response.json()
  ```
</CodeGroup>

## Status Codes

| Status Code | Description                                                                               |
| ----------- | ----------------------------------------------------------------------------------------- |
| 200         | Contacts successfully retrieved                                                           |
| 401         | Missing or invalid API key                                                                |
| 403         | API key doesn't have permission or subscription is inactive                               |
| 422         | Invalid parameters provided (check error message for details)                             |
| 429         | Too many requests - rate limit exceeded. See [Rate Limiting](/introduction/rate-limiting) |

## Notes

* **Rate Limit**: This endpoint has a limit of **15 requests per minute** per Space. See [Rate Limiting](/introduction/rate-limiting) for details.
* **Primary Data Only**: This endpoint returns primary contact data (email, name, phone, location) from the profiles table for efficient browsing.
* **Complete Contact Data**: For full contact information including all associated emails, phones, names, and locations from merged profiles, use GET /contacts/{id}.
* **Performance**: This endpoint uses a single efficient query, making it ideal for listing and browsing large numbers of contacts.
* **Ordering**: Results are ordered by ID in descending order (newest first).
* **Pagination**: Cursor pagination is used for efficient traversal of large result sets.
* **Comet Tokens**: Use the `include_comet_tokens=1` query parameter to include the last 5 comet tokens for each contact. This parameter is optional and defaults to `0`.
* **All Emails**: Use the `include_all_emails=1` query parameter to include all email addresses for each contact, including emails from merged profiles. This parameter is optional and defaults to `0`.
* **Custom Fields**: Use the `include_custom_fields=1` query parameter to include all 30 custom fields in the response. Fields 1-15 are text, 16-25 are numeric, 26-30 are date. This parameter is optional and defaults to `0`.
* **Custom Field Labels**: Use `use_custom_field_labels=1` alongside `include_custom_fields=1` to replace raw column names (`profile_field_1`) with user-defined labels (e.g. `Customer Age`). Fields without a configured label will retain their raw column name.
