Quickstart: Enrich Emails with Intent
What this does
Send an email address (or a LinkedIn URL), get back the intent topics that person is actively researching, with scores. This is the fastest path to a working Delivr integration: one endpoint, one POST, useful data in the response.
email in -> POST /api/v1/intent/lookup -> topics + scores out
Typical uses: scoring leads in a CRM, an enrichment column in Clay or a spreadsheet workflow, prioritizing outreach by what a prospect is researching this week.
Before you start
You need an organization API key + secret pair. Create one in the dashboard under Settings > API keys; the Authentication guide walks through it. Every request below sends both headers:
X-Api-Key: dlvr_...
X-Api-Secret: ...
1. Look up one person
curl -X POST "https://api.delivr.ai/api/v1/intent/lookup" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Secret: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{"id": "row-42", "email": "[email protected]"}'Response (200 OK)
{
"response": {
"id": "row-42",
"matched": true,
"matched_on": "email",
"topics": [
{
"topic_id": "4eyes_103456",
"topic_name": "CRM Software",
"score": "high",
"perc_score": 87
}
]
},
"as_of": "2026-06-19"
}How to read it:
idis your own opaque row identifier, echoed back. Use it to join results to your source data.matched: falsewith an emptytopicsarray means the person is not in the current intent data. That is a normal outcome, never an error.scoreis the intent tier (highormedium);perc_scoreis a 0-99 percentile strength within the topic.as_ofis the date of the intent dataset serving your request. Data refreshes daily.- You can send
linkedin_urlinstead ofemail. A LinkedIn URL identifies the person rather than one address, so it resolves across every address we hold for them and can match where a single email would not.
2. Look up a list (up to 10,000 per call)
POST /api/v1/intent/batch takes up to 10,000 items per request, mixing email and linkedin_url freely. Results come back in input order, one per item.
curl -X POST "https://api.delivr.ai/api/v1/intent/batch" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Secret: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"items": [
{"id": "r1", "email": "[email protected]"},
{"id": "r2", "linkedin_url": "https://www.linkedin.com/in/jane-doe-87745243"},
{"id": "r3", "email": "[email protected]"}
]
}'The response carries matched_count plus a results array shaped like the single lookup. Unmatched items simply come back matched: false.
3. Preview cost before you run (dry_run)
Every intent endpoint accepts "dry_run": true. The API resolves your request, tells you exactly how many records a live run would bill, and charges nothing:
curl -X POST "https://api.delivr.ai/api/v1/intent/batch" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "X-Api-Secret: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{"items": [...], "dry_run": true}'{
"dry_run": true,
"meter": "intent_signal_scored",
"records_to_charge": 2
}You are billed per matched record only; unmatched lookups cost nothing. Details in Rate Limits and Metering.
Complete example: enrich a CSV (Python)
import csv
import requests
API = "https://api.delivr.ai/api/v1/intent/batch"
HEADERS = {
"X-Api-Key": "YOUR_API_KEY",
"X-Api-Secret": "YOUR_API_SECRET",
}
BATCH_SIZE = 10_000 # server-side maximum per call
def batches(rows, size):
for i in range(0, len(rows), size):
yield rows[i : i + size]
with open("leads.csv") as f:
rows = [{"id": str(i), "email": r["email"]} for i, r in enumerate(csv.DictReader(f))]
enriched = {}
for chunk in batches(rows, BATCH_SIZE):
resp = requests.post(API, headers=HEADERS, json={"items": chunk}, timeout=60)
resp.raise_for_status()
for result in resp.json()["response"]["results"]:
if result["matched"]:
top = result["topics"][0] if result["topics"] else None
enriched[result["id"]] = {
"top_topic": top["topic_name"] if top else "",
"score": top["score"] if top else "",
"topic_count": len(result["topics"]),
}
print(f"matched {len(enriched)} of {len(rows)}")Complete example: enrich one row (JavaScript)
const resp = await fetch('https://api.delivr.ai/api/v1/intent/lookup', {
method: 'POST',
headers: {
'X-Api-Key': process.env.DELIVR_API_KEY,
'X-Api-Secret': process.env.DELIVR_API_SECRET,
'Content-Type': 'application/json',
},
body: JSON.stringify({ id: 'lead-1', email: '[email protected]' }),
});
if (!resp.ok) throw new Error(`Delivr API ${resp.status}`);
const { response } = await resp.json();
if (response.matched) {
const researching = response.topics.map((t) => t.topic_name).join(', ');
console.log(`Researching: ${researching}`);
}Errors you might see
| Status | Meaning | Fix |
|---|---|---|
400 | Malformed request (missing email/linkedin_url, batch over 10,000 items) | Check the request body against the examples above |
401 | Missing or invalid key/secret pair | Re-copy both halves from the dashboard; see Authentication |
429 | Over your request rate limit (default 10 requests/sec per organization) | Back off and retry; see Rate Limits and Metering |
An unmatched identifier is not an error: it returns 200 with matched: false.
Where to go next
- Company-level intent:
POST /api/v1/intent/companyscores a company domain the same way. Same auth, same shape. - Discovery (topic to people/companies): given a topic, list the people or companies showing intent with
POST /api/v1/intent/peopleand/api/v1/intent/companies. Free capped previews exist at/previewvariants so you can see real records before importing. - Which API should I use? if your use case is not a per-row lookup.
- Full API reference for every field on every endpoint.
Updated about 15 hours ago
