List the people found at a prospect's site
curl --request GET \
--url https://api.snowseo.com/v3/outreach/prospects/{id}/people \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.snowseo.com/v3/outreach/prospects/{id}/people"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.snowseo.com/v3/outreach/prospects/{id}/people', 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.snowseo.com/v3/outreach/prospects/{id}/people",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/outreach/prospects/{id}/people"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.snowseo.com/v3/outreach/prospects/{id}/people")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/outreach/prospects/{id}/people")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"people": [
{
"id": "<string>",
"isNew": true,
"createdAt": "<string>",
"updatedAt": "<string>",
"lastActivityAt": "<string>",
"fullName": "<string>",
"title": "<string>",
"seniority": "<string>",
"companyName": "<string>",
"companyDomain": "<string>",
"linkedinUrl": "<string>",
"location": "<string>",
"countryCode": "<string>",
"status": "<string>",
"lastError": "<string>",
"isTarget": true,
"pickedByUser": true,
"email": {
"id": "<string>",
"email": "<string>",
"name": "<string>",
"role": "<string>",
"countryCode": "<string>",
"location": "<string>",
"verifiedStatus": "<string>",
"confidence": 123,
"isPrimary": true
},
"emails": [
{
"id": "<string>",
"email": "<string>",
"name": "<string>",
"role": "<string>",
"countryCode": "<string>",
"location": "<string>",
"verifiedStatus": "<string>",
"confidence": 123,
"isPrimary": true
}
]
}
]
}Contacts
Contacts
Find who to pitch at a prospect’s site, then resolve the email addresses of the people worth writing to.
GET
/
v3
/
outreach
/
prospects
/
{id}
/
people
List the people found at a prospect's site
curl --request GET \
--url https://api.snowseo.com/v3/outreach/prospects/{id}/people \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.snowseo.com/v3/outreach/prospects/{id}/people"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.snowseo.com/v3/outreach/prospects/{id}/people', 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.snowseo.com/v3/outreach/prospects/{id}/people",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/outreach/prospects/{id}/people"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.snowseo.com/v3/outreach/prospects/{id}/people")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/outreach/prospects/{id}/people")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"people": [
{
"id": "<string>",
"isNew": true,
"createdAt": "<string>",
"updatedAt": "<string>",
"lastActivityAt": "<string>",
"fullName": "<string>",
"title": "<string>",
"seniority": "<string>",
"companyName": "<string>",
"companyDomain": "<string>",
"linkedinUrl": "<string>",
"location": "<string>",
"countryCode": "<string>",
"status": "<string>",
"lastError": "<string>",
"isTarget": true,
"pickedByUser": true,
"email": {
"id": "<string>",
"email": "<string>",
"name": "<string>",
"role": "<string>",
"countryCode": "<string>",
"location": "<string>",
"verifiedStatus": "<string>",
"confidence": 123,
"isPrimary": true
},
"emails": [
{
"id": "<string>",
"email": "<string>",
"name": "<string>",
"role": "<string>",
"countryCode": "<string>",
"location": "<string>",
"verifiedStatus": "<string>",
"confidence": 123,
"isPrimary": true
}
]
}
]
}Getting someone to write to is deliberately two steps: first find out who works at a site, then buy an address only for the people you actually want. That split is what stops you paying for forty addresses when one person was the right one.
Related endpoints: Get one person, Remove a person, List every person, Choose who to write to.
Requests are scoped to the brand your API key belongs to; an organization key passes the brand’s
teamId. See Authentication.Find people
Looks up the people worth pitching at one site or a batch of them - editors, writers, whoever can actually add the link. Nothing is bought here: you get names, job titles and seniority so you can decide. Body:prospectIds, or selection to pick prospects by filter instead. Optionally pass terms, 3-25 distinct job titles to match; omit it for the default editorial, SEO, marketing, and owner roles. A 400 is returned when one term contains another (for example founder and founders), since the longer one can never find anyone the shorter does not.
Runs in the background and replies 202. The response has enqueuedCount, enqueuedProspectIds, skipped, and creditsCharged. Poll Outreach Prospects while each enqueued site’s status is finding_people, then read the result with List a prospect’s people.
Costs 5 AI credits per site. A 402 means not enough credits. These sites are skipped, counted in skipped, and cost nothing, so a retry is safe:
- sites whose search is already running
- creator platforms, where the searchable domain belongs to the platform rather than the person
- sites whose
linkPlayis notoutreach, because the link is not earned by writing to someone - prospects that already link to you (
already-linked)
List a prospect’s people
GET /v3/outreach/prospects/{id}/people
Everyone found at one site, newest activity first (lastActivityAt).
| Field | Description |
|---|---|
id | The person ID that other endpoints take, such as peopleIds when resolving addresses |
fullName | Their name |
title | Job title - the thing worth deciding on |
seniority | Free text, or null when unknown. Either the provider’s label or one guessed from the title. Examples: CEO, Founder, Owner / Partner, Vice President, Head, Director, Manager, Senior, Editor, Writer, Entry Level. Do not treat it as a closed set |
companyName | Where they actually work. Often not the site being pitched, since people search returns guest authors and contributors |
companyDomain | That employer’s domain, when known |
linkedinUrl | Their profile, when there is one |
profileImageUrl | Profile photo, when there is one |
location / countryCode | Where they are based, when known |
source | The vendor that supplied the person |
status | pending, enriching, enriched, no_email, failed |
lastError | Why the last lookup failed, or null |
isNew | true for people added in the last 24 hours |
createdAt / updatedAt / lastActivityAt | When the person was added and changed. lastActivityAt also counts changes to their addresses |
email | The address to write to, or null if you have not bought one yet. An object: { id, email, verifiedStatus, confidence, isPrimary } |
emails | Every address resolved for this person, same shape, the preferred one first |
isTarget | true for the person chosen as the site’s target. When nobody has been chosen, the person the automatic pick selects also shows true; pickedByUser tells the two apart |
pickedByUser | true when someone on the team chose this person rather than the automatic pick |
For a link on a blog post, a content editor or head of content answers far more reliably than a founder. Read
title, not seniority.Resolve email addresses
Use Bulk people actions with aselection of person ids. The page renders the request and response schemas from OpenAPI.
Costs 10 AI credits per person actually looked up. Anyone who already has an address, is already enriched, is mid-lookup or is marked no_email is skipped and costs nothing, so a retry is safe. Each call returns eligibility and one result per person; when nobody is eligible nothing is charged. A 402 means not enough credits. Anyone with no findable address is refunded automatically.
There is no product cap on how many people you enrich at once, only a request-size bound well above any real contact list. The cost is per person, so check the count before you send it.
Addresses
- List a prospect’s addresses, including what each
verifiedStatusmeans - Choose a person’s address
Was this page helpful?

