Summary and recommendation
ZoomInfo exposes two distinct API surfaces that serve different purposes and must not be conflated. The data intelligence API (base URL: https://api.zoominfo.com) covers contact and company search, enrichment, and lookup - it is not a user-management CRUD API.
Platform user provisioning is handled exclusively via SCIM 2.0, which is configured within the IdP and requires an Enterprise plan plus active SSO. Authentication uses a proprietary JWT flow: POST credentials to /authenticate, extract the jwt field, and pass it as Authorization: Bearer <jwt> on all subsequent requests.
Tokens expire in approximately 60 minutes; no refresh token is issued, so proactive re-authentication must be built into any long-running pipeline. The API does not implement OAuth 2.0 - do not attempt authorization code or client credentials flows.
API quick reference
| Has user API | Yes |
| Auth method | JWT (username + password exchanged for a short-lived access token via POST /authenticate) |
| Base URL | Official docs |
| SCIM available | Yes |
| SCIM plan required | Enterprise |
Authentication
Auth method: JWT (username + password exchanged for a short-lived access token via POST /authenticate)
Setup steps
- Obtain API credentials (client username and password) from your ZoomInfo account team.
- POST to https://api.zoominfo.com/authenticate with JSON body {"username": "
", "password": " "}. - Extract the 'jwt' field from the response; this token is valid for 60 minutes.
- Include the token in all subsequent requests as Authorization: Bearer
. - Re-authenticate before token expiry; no refresh token mechanism is documented.
Required scopes
| Scope | Description | Required for |
|---|---|---|
| N/A | ZoomInfo's REST API does not use OAuth 2.0 scopes. Access is governed by the licensed features and data packages associated with the account credentials. | All API operations |
User object / data model
| Field | Type | Description | On create | On update | Notes |
|---|---|---|---|---|---|
| id | string | ZoomInfo internal unique identifier for the contact/person record. | system-generated | immutable | Used as primary key in search and lookup calls. |
| firstName | string | Contact's first name. | optional | writable | |
| lastName | string | Contact's last name. | optional | writable | |
| string | Primary business email address. | optional | writable | Used as a match key in enrichment calls. | |
| phone | string | Direct phone number. | optional | writable | |
| jobTitle | string | Contact's current job title. | optional | writable | |
| companyName | string | Name of the employer company. | optional | writable | |
| companyId | string | ZoomInfo internal company identifier. | system-generated | immutable | |
| linkedInUrl | string | LinkedIn profile URL for the contact. | optional | writable | |
| department | string | Department within the company. | optional | writable | |
| managementLevel | string | Seniority level (e.g., C-Level, VP, Director). | optional | writable | |
| city | string | City of the contact's work location. | optional | writable | |
| state | string | State/region of the contact's work location. | optional | writable | |
| country | string | Country of the contact's work location. | optional | writable | |
| hasEmail | boolean | Indicates whether a verified email is available for the contact. | system-generated | read-only |
Core endpoints
Authenticate / obtain JWT
- Method: POST
- URL:
https://api.zoominfo.com/authenticate - Watch out for: Token expires in ~60 minutes. No refresh token is issued; re-authenticate before expiry.
Request example
POST /authenticate
Content-Type: application/json
{
"username": "api_user@example.com",
"password": "s3cr3t"
}
Response example
{
"jwt": "eyJhbGciOiJIUzI1NiJ9..."
}
Search contacts
- Method: POST
- URL:
https://api.zoominfo.com/search/contact - Watch out for: Each result returned consumes credits from the account allotment. Use outputFields to limit returned fields and reduce credit consumption.
Request example
POST /search/contact
Authorization: Bearer <jwt>
{
"rpp": 25,
"page": 1,
"jobTitle": ["VP of Sales"]
}
Response example
{
"maxResults": 1200,
"totalResults": 1200,
"currentPage": 1,
"data": [{"id":"123","firstName":"Jane"}]
}
Enrich contact
- Method: POST
- URL:
https://api.zoominfo.com/enrich/contact - Watch out for: Match confidence varies; low-confidence matches may return partial or no data. Review matchStatus in response.
Request example
POST /enrich/contact
Authorization: Bearer <jwt>
{
"matchPersonInput": [
{"emailAddress": "jane@acme.com"}
]
}
Response example
{
"data": {"result": [{"input":{},
"data":[{"id":"123","email":"jane@acme.com"}]
}]}
}
Search companies
- Method: POST
- URL:
https://api.zoominfo.com/search/company - Watch out for: Company search also consumes credits per result row returned.
Request example
POST /search/company
Authorization: Bearer <jwt>
{
"rpp": 10,
"page": 1,
"companyName": ["Acme Corp"]
}
Response example
{
"maxResults": 5,
"data": [{"id":"456","name":"Acme Corp"}]
}
Enrich company
- Method: POST
- URL:
https://api.zoominfo.com/enrich/company - Watch out for: Providing both companyName and website improves match accuracy.
Request example
POST /enrich/company
Authorization: Bearer <jwt>
{
"matchCompanyInput": [
{"companyName": "Acme Corp", "website": "acme.com"}
]
}
Response example
{
"data": {"result": [{"data":[{"id":"456",
"name":"Acme Corp"}]}]}
}
Lookup contact by ID
- Method: GET
- URL:
https://api.zoominfo.com/lookup/contact/{id} - Watch out for: Lookup by ID still consumes credits. Cache results where possible.
Request example
GET /lookup/contact/123
Authorization: Bearer <jwt>
Response example
{
"id": "123",
"firstName": "Jane",
"lastName": "Doe",
"email": "jane@acme.com"
}
Usage / credit balance
- Method: GET
- URL:
https://api.zoominfo.com/usage - Watch out for: Exact field names may vary; consult current developer docs as this endpoint schema is not fully published.
Request example
GET /usage
Authorization: Bearer <jwt>
Response example
{
"creditsUsed": 1200,
"creditsAvailable": 3800
}
Rate limits, pagination, and events
- Rate limits: Rate limits are enforced per account and vary by contract tier. ZoomInfo does not publicly document specific numeric limits; limits are defined in individual service agreements.
- Rate-limit headers: No
- Retry-After header: No
- Rate-limit notes: API usage consumes credits from the account's annual allotment. Exceeding limits results in 429 responses. Specific header names for rate-limit state are not publicly documented.
- Pagination method: offset
- Default page size: 25
- Max page size: 100
- Pagination pointer: rpp (results per page) and page
| Plan | Limit | Concurrent |
|---|---|---|
| Professional | Not publicly documented; governed by credit allotment (5K credits/year) | 0 |
| Advanced | Not publicly documented; governed by credit allotment (10K credits/year) | 0 |
| Elite | Not publicly documented; governed by credit allotment (10K credits/year + features) | 0 |
- Webhooks available: No
- Webhook notes: ZoomInfo does not publicly document a webhook or event-streaming system for its data or user-management APIs as of the policy date.
- Alternative event strategy: Poll the search/enrich endpoints on a schedule to detect data changes. ZoomInfo's Intent data and Streaming Intent products offer near-real-time signals but are separate licensed features, not webhook push.
SCIM API status
SCIM available: Yes
SCIM version: 2.0
Plan required: Enterprise
Endpoint: Not publicly documented; configured within the IdP (Okta, Entra ID, OneLogin) using the SCIM base URL provided by ZoomInfo during SSO/SCIM setup.
Supported operations: Create user (provision), Deactivate user (deprovision), Update user attributes, Assign user individually, Assign user via group
Limitations:
- SSO must be configured and active before SCIM provisioning can be enabled.
- SCIM is confirmed for Okta; Entra ID and OneLogin support is referenced but less explicitly documented.
- Google Workspace is not listed as a supported IdP for SCIM.
- The 'Require SSO' toggle enforces SSO login; enabling it before SCIM is fully tested can lock out users.
- SCIM base URL and bearer token are provided by ZoomInfo account team, not self-serve.
- Group-based deprovisioning behavior (e.g., removing from group vs. full deactivation) should be validated in a test environment.
Common scenarios
Three integration patterns cover the majority of ZoomInfo API use cases. For platform user provisioning via SCIM (Okta), configure the SCIM base URL and bearer token - both provided by the ZoomInfo account team, not self-serve - in the IdP's provisioning settings, then assign users or groups.
the IdP POSTs SCIM User objects to ZoomInfo automatically. Validate group-based deprovisioning behavior in a test environment before enabling 'Require SSO,' since enabling that toggle prematurely can lock out admins.
For contact enrichment, POST a matchPersonInput array to /enrich/contact with only the outputFields your pipeline needs; check matchStatus on every result before storing, because credits are consumed per record returned regardless of match confidence.
For bulk search workflows, use rpp (max 100) and page (1-indexed) parameters for offset pagination - no cursor mechanism exists - and implement a re-authentication loop for batches that exceed the 60-minute token window.
Integrating ZoomInfo into an identity graph via an MCP server with 60+ deep IT/identity integrations allows enrichment signals (jobTitle, managementLevel, department, companyId) to be joined against internal identity records for role-inference and access-review workflows.
Provision a new ZoomInfo platform user via SCIM (Okta)
- Ensure SSO is configured in ZoomInfo Admin settings with Okta as the IdP.
- Obtain the SCIM base URL and bearer token from ZoomInfo account team.
- In Okta, navigate to the ZoomInfo application > Provisioning > Integration and enter the SCIM base URL and token.
- Enable 'Create Users', 'Update User Attributes', and 'Deactivate Users' in Okta provisioning settings.
- Assign the user or group to the ZoomInfo Okta application; Okta will POST a SCIM User object to ZoomInfo.
- Verify the user appears in ZoomInfo Admin > Users with the correct role.
Watch out for: Do not enable 'Require SSO' in ZoomInfo until all admin accounts are confirmed to be SSO-enabled, or admins may be locked out.
Enrich a list of contacts via API
- POST to /authenticate with API credentials to obtain a JWT.
- Prepare a matchPersonInput array with known identifiers (email, name + company).
- POST to /enrich/contact with the matchPersonInput payload and desired outputFields.
- Parse the response data[].result[].data[] array for enriched records.
- Check matchStatus on each result; only consume/store records with high-confidence matches.
- Re-authenticate before the 60-minute token expiry if processing large batches.
Watch out for: Each record in the response consumes credits even if the match confidence is low. Filter by matchStatus before storing results.
Deprovision a departed employee via SCIM
- In the IdP (Okta/Entra/OneLogin), remove the user from the ZoomInfo application assignment or deactivate the user in the IdP.
- The IdP sends a SCIM PATCH or DELETE request to ZoomInfo's SCIM endpoint to deactivate the user.
- Verify in ZoomInfo Admin > Users that the user's status is set to inactive/deprovisioned.
- Confirm the user can no longer authenticate via SSO to ZoomInfo.
Watch out for: Removing a user from a group (rather than deactivating the IdP account) may not trigger deprovisioning if group-push is not configured. Validate the exact deprovisioning trigger in a test environment.
Why building this yourself is a trap
The most consequential caveat in ZoomInfo's API is credit consumption: every contact or company record returned by /search/contact, /search/company, /enrich/contact, /enrich/company, or /lookup/contact/{id} draws from the account's annual credit allotment, including re-fetches of previously retrieved records. Omitting the outputFields parameter returns all available fields and maximizes credit burn per call.
Rate limits are contract-specific and not published in developer documentation; the API returns 429 on breach, but no rate-limit headers or Retry-After values are emitted, making adaptive throttling difficult to implement without account-team guidance.
SCIM provisioning carries its own traps: the SCIM base URL and token are not self-serve, SSO must be fully active before SCIM can be enabled, and removing a user from an IdP group rather than deactivating the IdP account may not trigger deprovisioning if group-push is not explicitly configured.
Webhooks are not available; detecting data changes requires scheduled polling of search and enrich endpoints, with Intent data streaming available only as a separately licensed feature.
Automate ZoomInfo workflows without one-off scripts
Stitchflow builds and maintains end-to-end IT automation across your SaaS stack, including apps without APIs. Built for exactly how your company works, with human approvals where they matter.