---
updatedAt: 2026-07-27T09:25:40.000Z
agentTools:
  projectIndex: https://docs.gtm.ai/llms.txt
---

# Find contacts using filters

ZoomInfo's GTM Data API helps you identify the right prospects through targeted search and enrichment. In this tutorial, you'll learn how to "**find Marketing Directors at Software companies headquartered in California".**

<Callout icon="far fa-circle-info" theme="default">
  **Credits Usage:&#x20;**&#x4C;ookup and Search requests do not consume credits. Credits are only charged when you enrich a contact, and only the first time that contact is enriched.
</Callout>

This workflow uses four Data API v1 endpoints in the recommended sequence to build a targeted contact list.

* **Lookup**: Resolves valid values for `industries`, `states`, `management-levels`, and `job-functions`.
* **Search Contacts**: Finds Marketing Directors at Software companies in California and returns matching `personId`s with a match score.
* **Enrich Contacts**: Retrieves verified contact details, including business email and phone, for the selected `contactId`.

```mermaid
flowchart LR
    A["Lookup
    Resolve valid filter values"]
    -->
    B["Search Contacts
    Find matching contacts"]
    -->
    C["Enrich Contacts
    Retrieve verified details"]
```

***

# cURL Request

## Step 1: Resolve filter with Lookup

**Endpoint:** `GET /data/v1/lookup/{fieldName}`

`fieldName` is a path parameter. For this scenario you need four fields: `industries`, `states`, `management-levels`, and `job-functions`.

Example:  Resolve the management level

```curl
curl --request GET \
     --url 'https://api.zoominfo.com/gtm/data/v1/lookup/management-levels' \
     --header 'accept: application/vnd.api+json' \
     --header 'authorization: Bearer <access_token>'
```

```json JSON Response
{
"data": [
    { "type": "ManagementLevel", "id": "Director", "attributes": { "name": "Director" } },
    { "type": "ManagementLevel", "id": "VP Level Exec", "attributes": { "name": "VP Level Exec" } },
    { "type": "ManagementLevel", "id": "C Level Exec", "attributes": { "name": "C Level Exec" } }
  ]
}
```

## Step 2: Search Contacts Using Lookup Results

**Endpoint:** `POST /data/v1/contacts/search`

This is the key thing to know about this endpoint: **you don't need to search companies first.** `Search Contacts` accepts company-level filters (`industryCodes`, `state`, `metroRegion`, `employeeCount`, `revenue`, `companyName`, etc.) in the exact same request as person-level filters (`managementLevel`, `jobFunction`, `jobTitle`). ZoomInfo matches both sides internally in one call — you just pass every filter you have.

This call is free and returns only match hints (`hasEmail`, `hasDirectPhone`, etc.) — no actual email addresses or phone numbers yet.

```curl
curl --request POST \
     --url 'https://api.zoominfo.com/gtm/data/v1/contacts/search?page%5Bnumber%5D=1&page%5Bsize%5D=25&sort=-contactAccuracyScore' \
     --header 'accept: application/vnd.api+json' \
     --header 'content-type: application/vnd.api+json' \
     --header 'authorization: Bearer <access_token>' \
     --data '
{
  "data": {
    "type": "ContactSearch",
    "attributes": {
      "industryCodes": "Computer Software",
      "state": "California",
      "locationSearchType": "HQ",
      "managementLevel": "Director",
      "jobFunction": "Marketing",
      "primaryIndustriesOnly": true,
      "contactAccuracyScoreMin": "80",
      "requiredFields": "email,phone"
    }
  }
}'
```

```json JSON Response
{
  "data": [
    {
      "type": "Contact",
      "id": "4191419698",
      "attributes": {
        "firstName": "Jordan",
        "lastName": "Reyes",
        "jobTitle": "Director of Marketing",
        "contactAccuracyScore": 95,
        "hasEmail": true,
        "hasDirectPhone": false,
        "hasMobilePhone": true,
        "company": {
          "id": 346572700,
          "name": "Acme Software Inc"
        }
      }
    }
  ],
  "meta": {
    "page": { "number": 1, "total": 1 },
    "totalResults": 14
  }
}
```

Collect `id` (`contactId`) for every contact you want full detail on, that's the input to Step 3.&#x20;

## Step 3: Enrich the contacts returned by the search

**Endpoint:** `POST /data/v1/contacts/enrich`

This is the only step in the workflow that charges credits — one per record, unless the record is already under management in your org's 12-month window. Enrich up to 25 records per call.

```curl
curl --request POST \
     --url 'https://api.zoominfo.com/gtm/data/v1/contacts/enrich' \
     --header 'accept: application/vnd.api+json' \
     --header 'content-type: application/vnd.api+json' \
     --header 'authorization: Bearer <access_token>' \
     --data '
{
  "data": [
    { "type": "ContactEnrich", "attributes": { "personId": "4191419698" } },
    { "type": "ContactEnrich", "attributes": { "personId": "4191419712" } }
  ],
  "outputFields": [
    "firstName", "lastName", "jobTitle", "managementLevel",
    "email", "phone", "mobilePhone", "companyName", "contactAccuracyScore"
  ],
  "requiredFields": ["email"]
}'
```

```json JSON Response
{
  "data": [
    {
      "type": "Contact",
      "id": "4191419698",
      "attributes": {
        "firstName": "Jordan",
        "lastName": "Reyes",
        "jobTitle": "Director of Marketing",
        "managementLevel": ["Director"],
        "email": "jordan.reyes@acmesoftware.example",
        "phone": "+1-650-555-0142",
        "mobilePhone": "+1-650-555-0198",
        "company": { "id": 346572700, "name": "Acme Software Inc" },
        "contactAccuracyScore": 95
      },
      "meta": {
        "input": { "personId": 4191419698 },
        "matchStatus": "FULL_MATCH"
      }
    },
    {
      "id": "4191419712",
      "type": "Contact",
      "attributes": {},
      "meta": {
        "input": { "personId": 4191419712 },
        "matchStatus": "NO_MATCH"
      }
    }
  ]
}
```

***

# Error Handling

| Status | Code        | Message                                     | What it means here                                                                                                                       |
| ------ | ----------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | `PFAPI0006` | *Input parameter '\[parameter]' is invalid* | Usually means a value like `industryCodes` or `managementLevel` didn't come from Lookup. Re-run Step 1 and use the exact returned value. |
| 400    | `PFAPI0004` | *Missing required inputs...*                | Search or Enrich body didn't include enough identifying fields.                                                                          |
| 401    | `ZI0001`    | *Token invalid / expired*                   | Refresh your OAuth token and retry.                                                                                                      |
| 403    | `ZI0003`    | *You do not have access to this endpoint*   | Your package doesn't include this field/endpoint — contact your ZoomInfo Account Manager.                                                |
| 429    | `ZI0004`    | *Rate limit exceeded*                       | Back off exponentially and retry.                                                                                                        |

Full reference: [error handling](/docs/status-codes-and-errors).

# Rate Limits

Default: 25 requests/second. Premium add-on: 30/sec. Premium+: 35/sec. All 429/5xx responses should be retried with exponential backoff. See [rate limits](https://docs.zoominfo.com/docs/rate-limits).