Hollerly API
Add leads, read replies and move deals from your own code, Zapier, Make, or Claude. The API, webhooks into Zapier and Make, and the MCP server are on the Agency plan. Plain webhooks are on Pro and up.
Base URL: https://hollerlyai.com/api/v1. Every request and response is JSON.
Authentication
Create a key in Settings, Integrations, API keys. It starts with hl_live_ and is shown once. Send it as a Bearer token. A key acts for the whole workspace, so keep it server side and revoke it if it leaks.
curl https://hollerlyai.com/api/v1/me \
-H "Authorization: Bearer $HOLLERLY_KEY"{ "workspace_id": "6f1c…", "plan": "agency", "email": "you@agency.com" }Errors
Errors come back as { "error": "message" } with a status code: 400 bad input, 401 missing or revoked key, 403 plan doesn't include the API, 404 not found in this workspace, 409 not allowed right now (for example resuming before samples are approved), 500 our fault.
Endpoints
GET/api/v1/me
The workspace the key belongs to.
curl https://hollerlyai.com/api/v1/me -H "Authorization: Bearer $HOLLERLY_KEY"GET/api/v1/campaigns
Every campaign with its counts.
curl https://hollerlyai.com/api/v1/campaigns -H "Authorization: Bearer $HOLLERLY_KEY"{
"campaigns": [
{
"id": "0b7e…", "name": "Founders in Austin", "status": "active",
"samples_approved": 5, "client_id": null, "created_at": "2026-09-14T10:02:11Z",
"stats": { "leads": 240, "invited": 180, "accepted": 71, "replied": 19,
"emailed": 40, "with_email": 96, "meetings": 6, "opened": 22 }
}
]
}GET/api/v1/campaigns/{id}/leads?status=&limit=
Newest leads first. limit defaults to 50, max 200. status is optional: new, in_sequence, waiting_accept, replied, done, failed or skipped.
curl "https://hollerlyai.com/api/v1/campaigns/$CAMPAIGN_ID/leads?status=replied&limit=50" -H "Authorization: Bearer $HOLLERLY_KEY"POST/api/v1/campaigns/{id}/leads
Up to 500 leads per call. Each needs a linkedin_url or an email; optional fields are full_name, first_name, company, headline and location. Email-only leads only get the campaign's email steps.
Skipped: rows without a usable URL or email, duplicates, people on your do-not-contact list (email, domain, LinkedIn or company), and anyone already in any campaign of the workspace.
curl -X POST https://hollerlyai.com/api/v1/campaigns/$CAMPAIGN_ID/leads -H "Authorization: Bearer $HOLLERLY_KEY" \
-H "Content-Type: application/json" \
-d '{
"leads": [
{ "linkedin_url": "https://www.linkedin.com/in/jordan-lee/", "full_name": "Jordan Lee", "company": "Northwind" },
{ "email": "sam@acme.com", "first_name": "Sam", "company": "Acme" }
]
}'{ "added": 2, "skipped": 0 }GET/api/v1/leads/{id}
One lead with status, pipeline stage, reply tag, tags, deal value and timestamps.
curl https://hollerlyai.com/api/v1/leads/$LEAD_ID -H "Authorization: Bearer $HOLLERLY_KEY"PATCH/api/v1/leads/{id}
Any of stage (replied, interested, meeting, proposal, won, lost, or null), tags (up to 20 strings, replaces the list) and deal_value (number or null). A stage change fires the lead.stage_changed event.
curl -X PATCH https://hollerlyai.com/api/v1/leads/$LEAD_ID -H "Authorization: Bearer $HOLLERLY_KEY" \
-H "Content-Type: application/json" \
-d '{ "stage": "proposal", "tags": ["warm", "q4"], "deal_value": 4800 }'GET/api/v1/replies?since=
Inbound LinkedIn messages and emails, newest first, up to 100. since is ISO 8601 and defaults to 7 days ago.
curl "https://hollerlyai.com/api/v1/replies?since=2026-10-01T00:00:00Z" -H "Authorization: Bearer $HOLLERLY_KEY"{
"replies": [
{
"id": "c1d…", "lead_id": "8a2…", "channel": "linkedin", "subject": null,
"body": "Sounds good, send me a time next week.", "at": "2026-10-01T15:20:04Z",
"lead": { "full_name": "Jordan Lee", "company": "Northwind", "stage": "interested", "reply_tag": "interested", … }
}
]
}POST/api/v1/campaigns/{id}/pause
Stops sending for the campaign until it is resumed.
curl -X POST https://hollerlyai.com/api/v1/campaigns/$CAMPAIGN_ID/pause -H "Authorization: Bearer $HOLLERLY_KEY"POST/api/v1/campaigns/{id}/resume
Starts it again. Returns 409 until 5 sample messages are approved in the app.
curl -X POST https://hollerlyai.com/api/v1/campaigns/$CAMPAIGN_ID/resume -H "Authorization: Bearer $HOLLERLY_KEY"POST/api/v1/hooks
Subscribe a URL to one event (REST hooks). source is zapier, make or api. Events: lead.replied, lead.tagged, meeting.booked, lead.accepted, lead.stage_changed, lead.unsubscribed, message.sent.
curl -X POST https://hollerlyai.com/api/v1/hooks -H "Authorization: Bearer $HOLLERLY_KEY" \
-H "Content-Type: application/json" \
-d '{ "target_url": "https://hooks.zapier.com/hooks/standard/123/abc/", "event": "lead.replied", "source": "zapier" }'{ "id": "5e0c…" }DELETE/api/v1/hooks/{id}
Unsubscribe. Returning HTTP 410 from your endpoint also turns the hook off.
curl -X DELETE https://hollerlyai.com/api/v1/hooks/$HOOK_ID -H "Authorization: Bearer $HOLLERLY_KEY"GET/api/v1/samples/{event}
An array with one sample payload for the event, for Zapier's perform list and Make's sample data.
curl https://hollerlyai.com/api/v1/samples/lead.replied -H "Authorization: Bearer $HOLLERLY_KEY"Webhooks
Add endpoints in Settings, Integrations, Webhooks. Hollerly sends a POST with this body. Respond with any 2xx within 8 seconds.
{
"event": "lead.replied",
"created_at": "2026-10-02T09:14:00.000Z",
"workspace_id": "6f1c…",
"lead": {
"id": "8a2…", "full_name": "Jordan Lee", "first_name": "Jordan",
"headline": "Head of Growth at Northwind", "company": "Northwind",
"email": "jordan@northwind.com", "profile_url": "https://www.linkedin.com/in/jordan-lee/",
"public_id": "jordan-lee", "campaign_id": "0b7e…", "status": "replied",
"stage": "replied", "reply_tag": null, "tags": [], "score": 8, "meeting_at": null
},
"data": { "channel": "linkedin", "text": "Sounds good, send me a time next week." }
}Every request has an X-Hollerly-Signature: sha256=<hex> header: the HMAC-SHA256 of the raw request body, keyed with the webhook's secret. Verify it against the raw bytes before parsing.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyHollerly(rawBody, header, secret) {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(header ?? "");
return a.length === b.length && timingSafeEqual(a, b);
}
// Express: keep the raw body
app.post("/hooks/hollerly", express.raw({ type: "application/json" }), (req, res) => {
if (!verifyHollerly(req.body, req.get("x-hollerly-signature"), process.env.HOLLERLY_WEBHOOK_SECRET)) {
return res.status(401).end();
}
const event = JSON.parse(req.body.toString("utf8"));
// event.event, event.lead, event.data
res.sendStatus(204);
});Zapier and Make
Both connect with an API key and REST hooks, so triggers fire instantly instead of polling.
- Create an API key named after the tool in Settings, Integrations.
- Authentication: API key, sent as the header Authorization: Bearer {{api_key}}. Test with GET /api/v1/me.
- Subscribe: POST /api/v1/hooks with { "target_url": "{{bundle.targetUrl}}", "event": "lead.replied", "source": "zapier" }. Store the returned id.
- Unsubscribe: DELETE /api/v1/hooks/{{bundle.subscribeData.id}}.
- Perform list (samples): GET /api/v1/samples/lead.replied.
- Actions: use POST /api/v1/campaigns/{id}/leads to add leads from a form, CRM or sheet, and PATCH /api/v1/leads/{id} to move deals.
In Make, use the HTTP module with the same header, or a custom webhook: create the webhook in Make, then register its URL with POST /api/v1/hooks and "source": "make".
MCP for Claude
Hollerly runs an MCP server at https://hollerlyai.com/api/mcp (Streamable HTTP, stateless). Connect Claude or any MCP client and ask things like "who replied this week?" or "add these 20 people to my Austin campaign". It uses the same API key.
Claude Code
claude mcp add --transport http hollerly https://hollerlyai.com/api/mcp --header "Authorization: Bearer hl_live_..."Other clients that read a JSON config:
{
"mcpServers": {
"hollerly": {
"type": "http",
"url": "https://hollerlyai.com/api/mcp",
"headers": { "Authorization": "Bearer hl_live_..." }
}
}
}| Tool | What it does |
|---|---|
| list_campaigns | Campaigns with their counts |
| get_campaign_stats | Counts plus accept and reply rates for one campaign |
| add_leads | Add up to 500 leads to a campaign, same rules as the REST endpoint |
| list_replies | Recent inbound replies, optional since |
| get_lead | One lead |
| set_lead_stage | Move a lead in the pipeline |
| pause_campaign | Pause sending |
| resume_campaign | Resume sending |
Raw JSON-RPC, if you want to test by hand:
curl -X POST https://hollerlyai.com/api/mcp -H "Authorization: Bearer $HOLLERLY_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": { "name": "list_replies", "arguments": { "since": "2026-10-01T00:00:00Z" } } }'