Get Contact by Email
curl --request GET \
--url https://app.cometly.com/public-api/v1/contacts/by-email/{email} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.cometly.com/public-api/v1/contacts/by-email/{email}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.cometly.com/public-api/v1/contacts/by-email/{email}', 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://app.cometly.com/public-api/v1/contacts/by-email/{email}",
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://app.cometly.com/public-api/v1/contacts/by-email/{email}"
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://app.cometly.com/public-api/v1/contacts/by-email/{email}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.cometly.com/public-api/v1/contacts/by-email/{email}")
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{
"message": "<string>",
"contact_ids": [
123
]
}Contacts
Get Contact by Email
Retrieve a single contact by its email address
GET
/
public-api
/
v1
/
contacts
/
by-email
/
{email}
Get Contact by Email
curl --request GET \
--url https://app.cometly.com/public-api/v1/contacts/by-email/{email} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.cometly.com/public-api/v1/contacts/by-email/{email}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.cometly.com/public-api/v1/contacts/by-email/{email}', 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://app.cometly.com/public-api/v1/contacts/by-email/{email}",
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://app.cometly.com/public-api/v1/contacts/by-email/{email}"
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://app.cometly.com/public-api/v1/contacts/by-email/{email}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.cometly.com/public-api/v1/contacts/by-email/{email}")
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{
"message": "<string>",
"contact_ids": [
123
]
}Overview
This endpoint looks up exactly one contact by email address, when you already expect a single match. The success response is byte-identical to Get Contact — same fields (id, emails, phones, names, locations, custom_fields) and the same optional extras, all of which behave identically here. See Get Contact for the full field-by-field response breakdown; it isn’t repeated on this page.
You can address the contact either of two ways:
- By path:
GET /contacts/by-email/{email} - By query string:
GET /contacts/by-email?email={email}
@ or a percent-encoded %40 in the {email} segment.
Resolution matches the email filter on List Contacts: matching is exact (not partial or fuzzy) and case-insensitive, with surrounding whitespace trimmed. It matches both the contact’s primary address and any of its alternate addresses, including addresses captured on profiles that were later merged into the contact.
Because this endpoint addresses a single contact, more than one match is an error rather than an arbitrary pick — see the 409 response below.
Use this endpoint when you expect exactly one contact for the address. Use List Contacts with its
email filter instead when you want to see every contact that shares an address, need to batch up to 100 addresses in one call, or want to avoid the possibility of a 409 entirely.Path Parameters
string
The email address of the contact to retrieve, when using the path form
GET /contacts/by-email/{email}. Required when not using the query form. Accepts a raw @ or a percent-encoded %40.Query Parameters
string
The email address of the contact to retrieve, when using the query form
GET /contacts/by-email?email=. Required when not using the path form.boolean
default:"0"
When set to
1, includes the last 5 comet tokens associated with this contact, ordered by most recent first. Accepts 1 or 0.boolean
default:"0"
When set to
1, includes the contact’s full event journey — all conversions and touchpoints sorted by most recent first. Accepts 1 or 0.boolean
default:"1"
When set to
1 (default), direct touchpoints are excluded from the events list. Set to 0 to include them. Only applies when include_events=1. Accepts 1 or 0.boolean
default:"0"
When set to
1, custom field keys in the custom_fields object will use the user-defined labels (e.g. "Customer Age") instead of the raw column names (e.g. "profile_field_1"). Fields without a configured label will keep their raw column name. Accepts 1 or 0.boolean
default:"0"
When set to
1, includes up to the last 1000 raw browsing session hits (page views) for this contact, ordered by most recent first. Accepts 1 or 0.Response
Success Response
Returns the contact object directly (not wrapped in adata property) — the same shape returned by Get Contact, including all of its optional fields (comet_tokens, events, browsing_session_hits) under the same query parameters.
Error Response
string
Error description explaining what went wrong.
integer[]
Only present on a
409 response. The sorted list of canonical contact ids that matched the given email.Example Requests
Look Up by Path
curl "https://app.cometly.com/public-api/v1/contacts/by-email/jane%40acme.com" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json"
const email = 'jane@acme.com';
const response = await fetch(`https://app.cometly.com/public-api/v1/contacts/by-email/${encodeURIComponent(email)}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
const data = await response.json();
<?php
$email = 'jane@acme.com';
$url = 'https://app.cometly.com/public-api/v1/contacts/by-email/' . rawurlencode($email);
$headers = [
'Authorization: Bearer YOUR_API_KEY',
'Accept: application/json',
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);
?>
import requests
from urllib.parse import quote
email = 'jane@acme.com'
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
url = f'https://app.cometly.com/public-api/v1/contacts/by-email/{quote(email, safe="")}'
response = requests.get(url, headers=headers)
data = response.json()
Look Up by Query String
curl -G "https://app.cometly.com/public-api/v1/contacts/by-email" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d "email=jane@acme.com"
const email = 'jane@acme.com';
const params = new URLSearchParams({ email });
const response = await fetch(`https://app.cometly.com/public-api/v1/contacts/by-email?${params}`, {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
const data = await response.json();
<?php
$email = 'jane@acme.com';
$url = 'https://app.cometly.com/public-api/v1/contacts/by-email?' . http_build_query(['email' => $email]);
$headers = [
'Authorization: Bearer YOUR_API_KEY',
'Accept: application/json',
'Content-Type: application/json'
];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);
?>
import requests
email = 'jane@acme.com'
url = 'https://app.cometly.com/public-api/v1/contacts/by-email'
headers = {
'Authorization': 'Bearer YOUR_API_KEY',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
response = requests.get(url, headers=headers, params={'email': email})
data = response.json()
Status Codes
| Status Code | Description |
|---|---|
| 200 | Exactly one contact matched and was retrieved |
| 401 | Missing or invalid API key |
| 403 | API key doesn’t have permission or subscription is inactive |
| 404 | No contact matches the given email |
| 409 | More than one contact matches the given email — see contact_ids in the response |
| 422 | Invalid parameters (missing or malformed email) |
| 429 | Too many requests - rate limit exceeded. See Rate Limiting |
Notes
- Rate Limit: This endpoint has a limit of 30 requests per minute per Space — the same bucket as Get Contact, not the 15/minute limit on List Contacts. See Rate Limiting for details.
- Resolution: Matching is exact and case-insensitive, with surrounding whitespace trimmed. It matches both the contact’s primary address and any of its alternate addresses, including addresses captured on profiles that were later merged into the contact — the identical algorithm used by the
emailfilter on List Contacts. - Multiple matches are a
409, not a pick: several distinct contacts can legitimately share an address. When that happens, nothing is guessed — the response is{"message": "Multiple contacts match this email. Fetch them with GET /contacts?email= and then request one by its contact id.", "contact_ids": [...]}. Either call List Contacts with itsemailfilter to see all of the matches, or request one of the returnedcontact_idsdirectly via Get Contact. - No match is a
404: unlike the list-basedemailfilter (which returns a normal200with an empty array), this endpoint returns404with{"message": "Contact not found"}when nothing matches, because it addresses a single resource. - Same payload as Get Contact: the response body, including all optional fields and query parameters, is identical to Get Contact. Nothing here can drift from that endpoint’s documented shape.