API Reference
The Hadef AI public API lets you run the research pipeline, retrieve pitches, and record the sends you make yourself. Hadef sends nothing. All endpoints are under /v1/ and require an API key, which is available on every plan. One credit is spent per completed run; every other call is free.
https://hadef.io · All endpoints accept and return JSON.Authentication
Create API keys from Settings → API keys. Pass the key as a Bearer token:
Authorization: Bearer hdk_your_api_key_here
Keys are user-scoped. A revoked key is rejected immediately. The full key is shown once at creation, so store it securely.
Rate limits
Requests are rate limited per API key. A request over the limit returns 429 Too Many Requests with a Retry-After header giving the number of seconds to wait. The JSON body carries "code": "rate_limited" and a hint that states the limit in force.
Error format
All errors return JSON with an error field:
{"error": "Invalid or missing API key", "hint": "Authorization: Bearer hdk_..."}
Pipeline
Kick off a research pipeline run for a prospect. Returns immediately with a prospect_id to poll.
Request body
| Field | Type | Description |
|---|---|---|
linkedin_url required | string | Full LinkedIn profile URL |
prospect_name | string | Full name (optional, improves research accuracy) |
curl -X POST https://hadef.io/v1/pipeline/run \
-H "Authorization: Bearer hdk_..." \
-H "Content-Type: application/json" \
-d '{"linkedin_url":"https://linkedin.com/in/example","prospect_name":"Jane Smith"}'
Response
{"prospect_id": "uuid", "status": "queued", "job_id": "uuid", "linkedin_url": "..."}
Poll a run until status is no longer researching. A run ends as pitched (a pitch was written and passed QA), researched (a pitch was written and did not pass QA), disqualified (not enough public material, no pitch) or new (no verdict, no pitch; you can run it again). The pitch field is the latest pitch for the prospect, and pitch.status is qa_passed, qa_failed, or sent once you have recorded a send. Wait on status, not on the presence of pitch: when you research a guest again, the pitch from the earlier run is still returned while the new run is in progress.
curl https://hadef.io/v1/pipeline/uuid \ -H "Authorization: Bearer hdk_..."
Response
{
"prospect_id": "uuid",
"status": "pitched",
"updated_at": "2026-04-26T09:00:00Z",
"pitch": {
"pitch_id": "uuid",
"status": "qa_passed",
"linkedin_message": "...",
"email_subject": "...",
"email_body": "..."
}
}
Pitch
Record that you sent a pitch yourself, and on which channel. It only records the send: Hadef delivers nothing, and the call is free.
| Field | Type | Description |
|---|---|---|
pitch_id required | string | UUID from pipeline response |
channel | string | linkedin (default) or email |
curl -X POST https://hadef.io/v1/pitch/mark-sent \
-H "Authorization: Bearer hdk_..." \
-H "Content-Type: application/json" \
-d '{"pitch_id":"uuid","channel":"linkedin"}'
Response
{"sent_at": "2026-04-26T09:01:00Z", "channel": "linkedin", "already_marked": false, "delivered_by_hadef": false}
Prospects
List your prospects. Paginated, newest first.
| Query param | Default | Description |
|---|---|---|
limit | 20 | Max 100 |
offset | 0 | Pagination offset |
curl "https://hadef.io/v1/prospects?limit=10&offset=0" \ -H "Authorization: Bearer hdk_..."
Credits
Check remaining credits and plan tier.
curl https://hadef.io/v1/credits \ -H "Authorization: Bearer hdk_..."
Response
{"remaining": 47, "plan": "professional"}
Zapier integration
Use the Webhooks by Zapier action to call Hadef from any Zap:
- Add a Webhooks by Zapier step, choose POST
- URL:
https://hadef.io/v1/pipeline/run - Headers:
Authorization: Bearer hdk_your_key - Data:
{"linkedin_url": "{{LinkedIn URL field}}"} - Add a second step to poll
/v1/pipeline/{{prospect_id}}untilstatusis no longerresearching, then readpitchif it ended aspitchedorresearched
curl examples
Full pipeline in bash
KEY="hdk_your_key_here"
# Start pipeline
PROSPECT=$(curl -s -X POST https://hadef.io/v1/pipeline/run \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"linkedin_url":"https://linkedin.com/in/example"}')
ID=$(echo $PROSPECT | python3 -c "import sys,json; print(json.load(sys.stdin)['prospect_id'])")
echo "Pipeline started: $ID"
# Poll until done
while true; do
STATUS=$(curl -s https://hadef.io/v1/pipeline/$ID \
-H "Authorization: Bearer $KEY")
S=$(echo $STATUS | python3 -c "import sys,json; print(json.load(sys.stdin)['status'])")
echo "Status: $S"
[ "$S" != "researching" ] && break
sleep 30
done
# pitched or researched: this run wrote a pitch. Anything else: it did not.
case "$S" in pitched|researched) ;; *) echo "Run ended without a pitch: $S"; exit 1;; esac
# Print pitch
echo $STATUS | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['pitch']['linkedin_message'])"
Hadef API v1 · Manage keys