curl --request POST \
--url https://api.pipecorn.com/v2/contacts/single_enrich \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '
{
"firstname": "Mathieu",
"lastname": "Brun-Picard",
"domain": "pipecorn.com",
"company_name": "Pipecorn",
"linkedin_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"enrichment_type": [
"email",
"phone",
"personal_email"
],
"custom": {
"hubspot_id": "4447901"
}
}
'import requests
url = "https://api.pipecorn.com/v2/contacts/single_enrich"
payload = {
"firstname": "Mathieu",
"lastname": "Brun-Picard",
"domain": "pipecorn.com",
"company_name": "Pipecorn",
"linkedin_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"enrichment_type": ["email", "phone", "personal_email"],
"custom": { "hubspot_id": "4447901" }
}
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
firstname: 'Mathieu',
lastname: 'Brun-Picard',
domain: 'pipecorn.com',
company_name: 'Pipecorn',
linkedin_url: 'https://www.linkedin.com/in/mathieu-brun-picard/',
enrichment_type: ['email', 'phone', 'personal_email'],
custom: {hubspot_id: '4447901'}
})
};
fetch('https://api.pipecorn.com/v2/contacts/single_enrich', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pipecorn.com/v2/contacts/single_enrich",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'firstname' => 'Mathieu',
'lastname' => 'Brun-Picard',
'domain' => 'pipecorn.com',
'company_name' => 'Pipecorn',
'linkedin_url' => 'https://www.linkedin.com/in/mathieu-brun-picard/',
'enrichment_type' => [
'email',
'phone',
'personal_email'
],
'custom' => [
'hubspot_id' => '4447901'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.pipecorn.com/v2/contacts/single_enrich"
payload := strings.NewReader("{\n \"firstname\": \"Mathieu\",\n \"lastname\": \"Brun-Picard\",\n \"domain\": \"pipecorn.com\",\n \"company_name\": \"Pipecorn\",\n \"linkedin_url\": \"https://www.linkedin.com/in/mathieu-brun-picard/\",\n \"enrichment_type\": [\n \"email\",\n \"phone\",\n \"personal_email\"\n ],\n \"custom\": {\n \"hubspot_id\": \"4447901\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.pipecorn.com/v2/contacts/single_enrich")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"firstname\": \"Mathieu\",\n \"lastname\": \"Brun-Picard\",\n \"domain\": \"pipecorn.com\",\n \"company_name\": \"Pipecorn\",\n \"linkedin_url\": \"https://www.linkedin.com/in/mathieu-brun-picard/\",\n \"enrichment_type\": [\n \"email\",\n \"phone\",\n \"personal_email\"\n ],\n \"custom\": {\n \"hubspot_id\": \"4447901\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pipecorn.com/v2/contacts/single_enrich")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"firstname\": \"Mathieu\",\n \"lastname\": \"Brun-Picard\",\n \"domain\": \"pipecorn.com\",\n \"company_name\": \"Pipecorn\",\n \"linkedin_url\": \"https://www.linkedin.com/in/mathieu-brun-picard/\",\n \"enrichment_type\": [\n \"email\",\n \"phone\",\n \"personal_email\"\n ],\n \"custom\": {\n \"hubspot_id\": \"4447901\"\n }\n}"
response = http.request(request)
puts response.read_body{
"enrichment_id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "Mathieu",
"last_name": "Brun-Picard",
"linkedin_profile_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"status": "success",
"email": "mathieu@prontohq.com",
"email_status": "valid",
"phones": [
"+33612345678",
"+33145678901"
],
"phone_details": [
{
"number": "+33612345678",
"type": "mobile"
},
{
"number": "+33145678901",
"type": "fixed_line"
}
],
"phone_status": "valid",
"custom": {
"hubspot_id": "4447901"
}
}Synchronous Single Contact Enrichment
Enrich a single contact with email, phone, and/or personal email data and get results instantly
curl --request POST \
--url https://api.pipecorn.com/v2/contacts/single_enrich \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: <api-key>' \
--data '
{
"firstname": "Mathieu",
"lastname": "Brun-Picard",
"domain": "pipecorn.com",
"company_name": "Pipecorn",
"linkedin_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"enrichment_type": [
"email",
"phone",
"personal_email"
],
"custom": {
"hubspot_id": "4447901"
}
}
'import requests
url = "https://api.pipecorn.com/v2/contacts/single_enrich"
payload = {
"firstname": "Mathieu",
"lastname": "Brun-Picard",
"domain": "pipecorn.com",
"company_name": "Pipecorn",
"linkedin_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"enrichment_type": ["email", "phone", "personal_email"],
"custom": { "hubspot_id": "4447901" }
}
headers = {
"X-API-KEY": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-KEY': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
firstname: 'Mathieu',
lastname: 'Brun-Picard',
domain: 'pipecorn.com',
company_name: 'Pipecorn',
linkedin_url: 'https://www.linkedin.com/in/mathieu-brun-picard/',
enrichment_type: ['email', 'phone', 'personal_email'],
custom: {hubspot_id: '4447901'}
})
};
fetch('https://api.pipecorn.com/v2/contacts/single_enrich', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.pipecorn.com/v2/contacts/single_enrich",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'firstname' => 'Mathieu',
'lastname' => 'Brun-Picard',
'domain' => 'pipecorn.com',
'company_name' => 'Pipecorn',
'linkedin_url' => 'https://www.linkedin.com/in/mathieu-brun-picard/',
'enrichment_type' => [
'email',
'phone',
'personal_email'
],
'custom' => [
'hubspot_id' => '4447901'
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-KEY: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.pipecorn.com/v2/contacts/single_enrich"
payload := strings.NewReader("{\n \"firstname\": \"Mathieu\",\n \"lastname\": \"Brun-Picard\",\n \"domain\": \"pipecorn.com\",\n \"company_name\": \"Pipecorn\",\n \"linkedin_url\": \"https://www.linkedin.com/in/mathieu-brun-picard/\",\n \"enrichment_type\": [\n \"email\",\n \"phone\",\n \"personal_email\"\n ],\n \"custom\": {\n \"hubspot_id\": \"4447901\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-KEY", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.pipecorn.com/v2/contacts/single_enrich")
.header("X-API-KEY", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"firstname\": \"Mathieu\",\n \"lastname\": \"Brun-Picard\",\n \"domain\": \"pipecorn.com\",\n \"company_name\": \"Pipecorn\",\n \"linkedin_url\": \"https://www.linkedin.com/in/mathieu-brun-picard/\",\n \"enrichment_type\": [\n \"email\",\n \"phone\",\n \"personal_email\"\n ],\n \"custom\": {\n \"hubspot_id\": \"4447901\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pipecorn.com/v2/contacts/single_enrich")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-KEY"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"firstname\": \"Mathieu\",\n \"lastname\": \"Brun-Picard\",\n \"domain\": \"pipecorn.com\",\n \"company_name\": \"Pipecorn\",\n \"linkedin_url\": \"https://www.linkedin.com/in/mathieu-brun-picard/\",\n \"enrichment_type\": [\n \"email\",\n \"phone\",\n \"personal_email\"\n ],\n \"custom\": {\n \"hubspot_id\": \"4447901\"\n }\n}"
response = http.request(request)
puts response.read_body{
"enrichment_id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "Mathieu",
"last_name": "Brun-Picard",
"linkedin_profile_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"status": "success",
"email": "mathieu@prontohq.com",
"email_status": "valid",
"phones": [
"+33612345678",
"+33145678901"
],
"phone_details": [
{
"number": "+33612345678",
"type": "mobile"
},
{
"number": "+33145678901",
"type": "fixed_line"
}
],
"phone_status": "valid",
"custom": {
"hubspot_id": "4447901"
}
}Overview
This endpoint performs real-time waterfall enrichment across multiple data providers to find the most accurate email, phone number, and/or personal email for a contact. Results are returned immediately in the API response, making it ideal for interactive applications, Chrome extensions, and real-time workflows.Rate Limits
- 50 requests per second per user
Enrichment Types
You can specify which data points you want to enrich by passing theenrichment_type array parameter:
["email"]- Find and validate professional email addresses only["phone"]- Find phone numbers only["personal_email"]- Find personal email addresses only (requires user consent — see below)- Any combination, e.g.
["email", "phone"],["email", "personal_email"], or["email", "phone", "personal_email"]
personal_email requires the authenticated user to have consented
to personal email enrichment in their account settings. If consent is missing,
the API responds with 422 Unprocessable Entity and the message
"You can't use the personal email enrichment feature without consenting with our terms of use".
This consent gate is required for GDPR compliance.Requests including phone or personal_email must include linkedin_url.Phone Type Filter
Whenenrichment_type includes "phone", pass phone_type to choose which
numbers come back:
phone_type | Returned numbers |
|---|---|
["all"] (default) | Every number found, whatever its line type |
["mobile"] | Only mobile numbers — type of mobile or fixed_or_mobile |
["mobile"], the waterfall keeps querying providers until one returns a
mobile number — a provider that only has a landline doesn’t stop the search.
Landlines, VoIP, toll-free and other non-mobile numbers are
dropped from both phones and phone_details. If only non-mobile numbers were
found, phones is empty and phone_status is not_found. phone_type
combines with phone_country_codes (both filters apply). Any other value is rejected with
422 Unprocessable Entity.
{
"linkedin_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"enrichment_type": ["phone"],
"phone_type": ["mobile"]
}
Waterfall Enrichment
When you request multiple enrichment types, our system uses a sophisticated waterfall approach:- Attempts to find the professional email from the most reliable providers first
- Searches for personal email through dedicated personal-email providers (Pipecorn, LeadMagic, Airscale)
- Searches for phone numbers using provider prioritization
- Returns results as soon as all requested data points are found or all providers are exhausted
Response Format
Success Response
When enrichment succeeds, you’ll receive a 200 response with the enriched data: Email Only:{
"enrichment_id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "Mathieu",
"last_name": "Brun-Picard",
"linkedin_profile_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"status": "success",
"email": "mathieu@prontohq.com",
"email_status": "valid"
}
{
"enrichment_id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "Mathieu",
"last_name": "Brun-Picard",
"linkedin_profile_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"status": "success",
"phones": [
"+33612345678"
],
"phone_details": [
{ "number": "+33612345678", "type": "mobile" }
],
"phone_status": "valid"
}
{
"enrichment_id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "Mathieu",
"last_name": "Brun-Picard",
"linkedin_profile_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"status": "success",
"email": "mathieu@prontohq.com",
"email_status": "valid",
"phones": [
"+33612345678",
"+33145678901"
],
"phone_details": [
{ "number": "+33612345678", "type": "mobile" },
{ "number": "+33145678901", "type": "fixed_line" }
],
"phone_status": "valid"
}
{
"enrichment_id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "Mathieu",
"last_name": "Brun-Picard",
"linkedin_profile_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"status": "success",
"personal_email": "mathieu.bp@gmail.com",
"personal_email_status": "valid"
}
Error Response
When no data is found, the response includes a message and empty data fields:{
"enrichment_id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "Mathieu",
"last_name": "Brun-Picard",
"linkedin_profile_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"status": "error",
"message": "No email or phone found for this profile",
"email": null,
"email_status": "N/A",
"phones": [],
"phone_details": [],
"phone_status": "not_found"
}
Required Fields
enrichment_type is always required — an array containing any combination of
"email", "phone", and/or "personal_email". The other required fields
depend on which types you request:
enrichment_type value | Additional required fields |
|---|---|
"email" | firstname, lastname, and one of linkedin_url, domain, or company_name |
"phone" | linkedin_url |
"personal_email" | linkedin_url |
firstname/lastname are only needed when you request "email"; phone and
personal email run off the linkedin_url alone.
When you request a combination, the requirements add up — but a single
linkedin_url satisfies the identifier requirement for all three types. For
example, ["email", "phone"] needs firstname, lastname, and a
linkedin_url (the linkedin_url covers both the email and phone steps).
Recommended Fields
Beyond the required fields, supplying more context improves accuracy:linkedin_url- LinkedIn profile URL (highly recommended for accuracy; on its own it satisfies every enrichment type)domain/company_name- Company context that improves professional email matching when you don’t have alinkedin_url.
Custom Fields
You can include custom fields that will be returned in the response:{
"firstname": "Mathieu",
"lastname": "Brun-Picard",
"linkedin_url": "https://www.linkedin.com/in/mathieu-brun-picard/",
"enrichment_type": ["email"],
"custom": {
"crm_id": "12345",
"campaign": "outbound_q1",
"segment": "enterprise"
}
}
custom field of the response, making it easy to correlate results with your internal systems.
Email Status Values
Theemail_status field indicates the validation state of the email:
deliverable- Email is deliverablecatch-all- Email hasa catch-all status but was validated by our debouncing waterfallN/A- Email enrichment was not requested or no email was found
Personal Email Status Values
Thepersonal_email_status field indicates the validation state of the personal email:
valid- Personal email was found and validatedinvalid- Personal email enrichment ran but the result is not deliverableN/A- Personal email enrichment was not requested or no personal email was found
Phone Status Values
Thephone_status field indicates whether valid phone numbers were found:
valid- At least one valid phone number foundnot_found- No phone numbers found or phone enrichment not requested
Phone Type Values
phones keeps returning the plain list of E.164 numbers for existing
integrations; phone_details holds the same numbers in the same order, each
with its line type in type:
type | Meaning |
|---|---|
mobile | Mobile number |
fixed_or_mobile | Can’t be told apart from the number alone — mobile and landline share the same ranges (e.g. US, Canada). Treated as mobile by the phone_type filter |
fixed_line | Landline (office switchboard, desk phone) |
voip | VoIP number |
toll_free | Toll-free number |
premium_rate | Premium-rate number |
shared_cost | Shared-cost number |
personal_number | Personal (follow-me) number |
pager | Pager |
uan | Universal access number (company-wide number) |
voicemail | Voicemail access number |
unknown | The number could not be classified |
Pricing
Each enrichment request consumes credits based on the enrichment type requested and the providers used. A phone enrichment is only charged when a mobile number (mobile or fixed_or_mobile) is found. Check your account credits using the Account Credits endpoint.
Credits are checked before the waterfall runs. If your balance cannot cover the
enrichment the request is rejected with 402 Payment Required and
code: "insufficient_credits" (the response carries a top_up_url); if it
would exceed your workspace weekly credit limit, with 403 Forbidden and
code: "workspace_limit_exceeded". No provider is called and nothing is spent
in either case. See Credit and limit errors.Authorizations
Body
Contact information for synchronous enrichment
Types of enrichment to perform. Can be any combination of ["email"], ["phone"], and/or ["personal_email"]. Note: "personal_email" requires the user to have consented to personal email enrichment in their account settings. Requests including "personal_email" or "phone" require linkedin_url.
1 - 3 elementsphone, email, personal_email First name of the contact
Last name of the contact
Company name of the contact
Company domain
LinkedIn profile URL of the contact
Optional webhook URL to also receive enrichment results
Optional. Restrict phone enrichment to phone numbers from these countries. When omitted, the user's account-level default phone country codes are applied.
ISO 3166-1 alpha-2 country code (e.g. "US", "FR", "GB")
Optional. Filters the phone numbers returned by phone enrichment. ["all"] (default) returns every number found; ["mobile"] returns only mobile numbers (type of mobile or fixed_or_mobile) and drops landlines, VoIP, toll-free and other non-mobile numbers. With ["mobile"] the waterfall keeps querying providers until one returns a mobile number. Any other value is rejected with 422. Ignored unless enrichment_type includes phone.
1all, mobile Custom fields to include with the enrichment response
Response
Enrichment completed successfully
The ID of the enrichment request
The contact's first name
The contact's last name
The contact's LinkedIn profile URL
The status of the enrichment request
success, error The enriched email address (present if enrichment_type includes email)
The validation status of the email (present if enrichment_type includes email)
valid, invalid, N/A The enriched personal email address (present if enrichment_type includes personal_email)
The validation status of the personal email (present if enrichment_type includes personal_email)
valid, invalid, N/A Array of phone numbers found, after the phone_type filter is applied (present if enrichment_type includes phone)
Phone number in E.164 format
Phone numbers found, each with its line type. Same numbers and order as phones, after the phone_type filter is applied (empty array when none found).
Show child attributes
Show child attributes
The status of phone enrichment (present if enrichment_type includes phone)
valid, not_found Error message if enrichment failed
Custom fields passed in the request
Was this page helpful?