Enrich contact data using ZoomInfo in Jitterbit Studio
Introduction
ZoomInfo provides B2B contact and company data through a REST API. This guide shows how to use the HTTP v2 connector to authenticate with ZoomInfo, build a reusable resource router that maps named endpoint types to API paths, and use that router to search for contacts, enrich existing contact records, and retrieve company data.
The key pattern in this guide is a Case-based resource router: a single script maps a resource name such as contact or company to the corresponding ZoomInfo API path, and one central HTTP v2 POST operation handles all API calls. This makes the integration reusable: adding a new ZoomInfo endpoint requires only a one-line addition to the router script, with no additional connection or activity setup.
This guide assumes a ZoomInfo account with API access credentials (username and password).
Note
A native ZoomInfo connector is also available as an alternative to the HTTP v2 approach shown in this guide. It provides Enrich, Search, and Lookup activities that cover common contact and company operations without building API calls by hand.
Design pattern
Authentication runs once at the start of the workflow to obtain a JWT. All subsequent ZoomInfo calls follow the same sequence:
Set $core.zoom.resource"] --> B["Script
Resource router
→ sets $core.zoom.object"] B --> C["Build request
transformation"] C --> D["HTTP v2 POST
Posts to [$core.zoom.object]"] D --> E["Process response
transformation"]
| Step | Purpose |
|---|---|
| Set resource | Caller sets core.zoom.resource to a named endpoint type (for example, contact). |
| Resource router | Router script maps the name to the API path and stores it in core.zoom.object. |
| Build request | Transformation builds the JSON request body for the specific endpoint. |
| HTTP v2 POST | One central POST activity sends the request to [$core.zoom.object]. |
| Process response | Transformation parses the response into variables or records for downstream use. |
The router and POST activity are shared across all ZoomInfo API calls.
The table shows the conceptual flow. In the implementation, the resource router and POST activity are steps within one shared operation (the central POST operation in Part 3), while the build request and process response are separate, reusable operations that you create per resource type and invoke with RunOperation (see Part 4).
Part 1: Configure project variables and the HTTP v2 connection
Step 1: Create project variables
Store credentials and the runtime JWT in project variables so that sensitive values are not hardcoded in scripts or activity configuration.
Open the project actions menu and select Project Variables. Then add:
| Name | Default value | Description |
|---|---|---|
zoom.username |
(your ZoomInfo username) | ZoomInfo account username or email address |
zoom.password |
(your ZoomInfo password) | ZoomInfo account password |
zoom.jwt |
(empty) | JWT populated at runtime by the authenticate operation |
Mark zoom.password and zoom.jwt as hidden. For guidance on storing credentials securely, see Manage endpoint credentials.
Step 2: Configure the HTTP v2 connection
-
In Studio, open your project and click the Project endpoints and connectors tab in the design component palette.
-
Click the HTTP v2 connector to open the connection configuration screen.
-
Connection Name: Enter
ZoomInfo API. -
Base URL: Enter
https://api.zoominfo.com. -
Authorization: Select Bearer Token and enter
[$zoom.jwt]as the token value. Thezoom.jwtproject variable is empty when the project first runs. The authenticate operation in Part 2 populates it before any other ZoomInfo call is made. The/authenticateendpoint itself does not validate theAuthorizationheader, so an empty token on the initial call does not cause an error. -
Click Test to verify the connection, then click Save Changes.
Part 2: Authenticate and store the JWT
ZoomInfo uses a JWT-based authentication model. Before any API call, an operation posts credentials to the /authenticate endpoint and stores the returned JWT in zoom.jwt.
Step 1: Create the authenticate operation
-
Create a new operation and name it
core.ZoomInfo - Get Auth Token. -
Add a Transformation step. In the transformation, define a JSON target schema with two fields:
usernameandpassword. Map[$zoom.username]and[$zoom.password]to the respective fields. -
From the ZoomInfo API connection, drag a POST activity after the transformation as the target.
-
Double-click the POST activity to open its configuration.
-
Name: Enter
ZoomInfo - Authenticate. -
Path: Enter
/authenticate. -
In the Request tab, add a Content-Type header with value
application/json. -
Click Finished.
Step 2: Extract and store the JWT
Add a Script step after the POST activity. The script reads the JWT from $jitterbit.response, which holds the raw response body from the preceding HTTP activity, and stores it in the project variable:
$zoom.jwt = TrimChars(GetJSONString($jitterbit.response, "/jwt"), "\"");
If(length(trim($zoom.jwt)) == 0,
RaiseError("ZoomInfo authentication failed. Response: " + $jitterbit.response)
);
WriteToOperationLog("ZoomInfo JWT obtained successfully.");
GetJSONString extracts a field value by JSON path. TrimChars removes the surrounding quotation marks that GetJSONString includes in string values.
Step 3: Call the authenticate operation at the start of each workflow
In any workflow that uses ZoomInfo, call the authenticate operation as the first step:
$core.zoom.resource = "authenticate";
RunOperation("<TAG>operation:core.ZoomInfo - Get Auth Token</TAG>");
If the same workflow runs multiple ZoomInfo calls, authenticate once at the start rather than before each individual call.
Part 3: Build the resource router
The resource router maps a named resource type to the corresponding ZoomInfo API path. One central POST operation reuses this path for every endpoint.
Step 1: Create the router script
Create a Script component named core. Load Zoom API Resource. This script reads core.zoom.resource, set by the caller, and writes the API path to core.zoom.object:
$core.zoom.resource = ToLower($core.zoom.resource);
If(length($core.zoom.resource) == 0,
RaiseError("$core.zoom.resource is empty. Set a resource type before running this script.")
);
Case(
$core.zoom.resource == "contact",
$core.zoom.object = "/search/contact";
,
$core.zoom.resource == "enrich_contact",
$core.zoom.object = "/enrich/contact";
,
$core.zoom.resource == "company",
$core.zoom.object = "/search/company";
,
$core.zoom.resource == "scoop",
$core.zoom.object = "/search/scoop";
,
true,
RaiseError("Unknown ZoomInfo resource: [" + $core.zoom.resource + "]")
);
WriteToOperationLog("ZoomInfo resource: " + $core.zoom.resource
+ " → path: " + $core.zoom.object);
The Case statement routes the four supported resource types. Add a new branch for any additional ZoomInfo endpoint without changing the POST operation or connection.
Step 2: Create the central POST operation
-
Create a new operation and name it
core. ZoomInfo POST API CALL. -
Add the
core. Load Zoom API Resourcescript as the first step socore.zoom.objectis set before the activity runs. -
From the ZoomInfo API connection, drag a POST activity after the script.
-
Name: Enter
ZoomInfo - POST. -
Path: Enter
[$core.zoom.object]. Studio resolves the variable at runtime using the value set by the router script. -
In the Request tab, add a Content-Type header with value
application/json. -
Click Finished.
The supported resource types and their corresponding paths are:
core.zoom.resource value |
API path | Purpose |
|---|---|---|
contact |
/search/contact |
Search for contacts at a company, optionally filtered by job title |
enrich_contact |
/enrich/contact |
Retrieve full contact details (email, direct phone, updated title) |
company |
/search/company |
Look up a company record by name or website domain |
scoop |
/search/scoop |
Retrieve recent news and leadership changes for a company |
Part 4: Search for contacts
With authentication and the router in place, each ZoomInfo call follows the same sequence: set core.zoom.resource, build the request body in a transformation, and run the central POST operation.
Create the build request and process response operations
The build request and process response operations referenced in the steps below are not the central POST operation: you create one pair for each resource type (contact, enrich_contact, company, scoop). Each is a small, single-purpose operation built around one transformation:
- Build request operation: Contains a transformation that maps the input variables (for example,
zoom.companyNameorzoom.query_jobTitle) to the JSON request body that the target ZoomInfo endpoint expects. Run it before the central POST operation so the request body is prepared before the POST activity sends it. - Process response operation: Reads the ZoomInfo response and extracts the returned fields into variables or records for downstream use. Parse the response either with a transformation that maps the response schema to a target, or with a script step that calls
GetJSONStringon$jitterbit.response(the same approach used to extract the JWT in Part 2).
The three operations run in sequence: build request, then the central POST operation, then process response. For each endpoint's request and response schema, see the ZoomInfo API documentation.
Contact search by company name
To retrieve contacts associated with a company, set the resource type and company name, build the request body, and run the POST operation:
// Authenticate (skip if already done earlier in the workflow)
RunOperation("<TAG>operation:core.ZoomInfo - Get Auth Token</TAG>");
// Set the resource type and search parameters
$core.zoom.resource = "contact";
$zoom.companyName = $salesforce.accountName;
// Build and submit the search
RunOperation("<TAG>operation:Zoominfo - Build Request - Contact Info</TAG>");
RunOperation("<TAG>operation:core. ZoomInfo POST API CALL</TAG>");
RunOperation("<TAG>operation:Zoominfo - Process Request - Contact Info</TAG>");
The build request operation (Zoominfo - Build Request - Contact Info) maps zoom.companyName and any optional job title filter to the ZoomInfo Search API request format. The process response operation extracts the returned contact records into variables for downstream use.
For the ZoomInfo Search API request and response schema, see the ZoomInfo API documentation.
Filter contacts by job title
To narrow results to specific roles, set zoom.query_jobTitle before the build request step:
$zoom.query_jobTitle = "Chief Executive Officer";
$core.zoom.resource = "contact";
RunOperation("<TAG>operation:Zoominfo - Build Request - Contact Info</TAG>");
RunOperation("<TAG>operation:core. ZoomInfo POST API CALL</TAG>");
RunOperation("<TAG>operation:Zoominfo - Process Request - Contact Info</TAG>");
To search across multiple job titles, pass a comma-separated list in zoom.query_jobTitle and iterate over the values in the build request operation, making one search call per title and accumulating results.
Part 5: Enrich contact data
Contact enrichment retrieves detailed data (direct email addresses, phone numbers, and current job titles) for contacts already identified through a search or sourced from an existing Salesforce record. Use enrichment when a basic contact search returns limited contact information.
Set core.zoom.resource to enrich_contact and run the central POST operation:
$core.zoom.resource = "enrich_contact";
RunOperation("<TAG>operation:Zoominfo - Build Enrich Request</TAG>");
RunOperation("<TAG>operation:core. ZoomInfo POST API CALL</TAG>");
RunOperation("<TAG>operation:Zoominfo - Process Enrich Response</TAG>");
The enrich request body typically identifies the contact by name and company, or by a ZoomInfo contact ID returned from a prior search. After enrichment, use the returned data to update the corresponding Salesforce contact record. For merging enriched fields into Salesforce, see Query Salesforce records using SOQL.
Part 6: Retrieve company and scoop data
The same router handles company-level lookups. Company search returns a ZoomInfo company ID that can be used in subsequent /search/scoop calls to retrieve recent news and leadership change data.
// Search for the company record
$zoom.companyName = $salesforce.accountName;
RunOperation("<TAG>operation:core.ZoomInfo Build Request - Get Company</TAG>");
$core.zoom.resource = "company";
RunOperation("<TAG>operation:core. ZoomInfo POST API CALL</TAG>");
RunOperation("<TAG>operation:core.ZoomInfo - Read Response - Get Company Id</TAG>");
// Retrieve scoop data using the company ID from the previous step
RunOperation("<TAG>operation:Build Request - Get Scoop for a Company</TAG>");
$core.zoom.resource = "scoop";
RunOperation("<TAG>operation:core. ZoomInfo POST API CALL</TAG>");
RunOperation("<TAG>operation:Read Response - Scoop for a Company</TAG>");
Scoop data includes announcements of leadership changes such as new executive hires or role changes. This is useful for account intelligence workflows that alert sales or account teams when key contacts at a company change.
Verify the integration
-
Run
core.ZoomInfo - Get Auth Tokenin isolation. Add aWriteToOperationLogcall after the JWT extraction script to confirmzoom.jwtis non-empty. Check the operation logs for the log entry. -
Run a contact search for a company name you know exists in ZoomInfo. Confirm in the logs that:
core.zoom.objectis set to/search/contactby the router script.- The POST activity returns a 200 status.
- The process response operation produces contact records.
-
If the
/authenticatecall returns a non-200 status, confirm thatzoom.usernameandzoom.passwordproject variables are set correctly. ZoomInfo credentials are case-sensitive. -
If subsequent API calls return 401 Unauthorized, the JWT extraction may have failed silently. Confirm the
RaiseErrorguard in the authenticate script is active and thatzoom.jwtis non-empty before the next operation chain runs. -
If the router raises an "Unknown ZoomInfo resource" error, verify that
core.zoom.resourceis set to one of the supported values (contact,enrich_contact,company,scoop) and that no leading or trailing whitespace is present in the value.