HeyRik DocsGet startedConnect your backend to HeyRik
Get started

Connect your backend to HeyRik

Everything your server needs: the base URL and auth, the results webhook for every finished call, the live-leads webhook that feeds a campaign from your own system, and how lead fields reach the agent.

8 minute read Practical examples included

Your server talks to HeyRik in two directions. It calls the API to create agents and campaigns and to push leads, and HeyRik calls your server with the result of every finished call. This page is the contract for both — copy the examples and you are integrated.

Two webhooks, two directions

The results webhook is a URL you own that HeyRik POSTs to after each call. The live-leads webhook is a URL HeyRik owns that your system POSTs leads to. They are independent — use either or both.

01

Base URL, authentication, envelopes

The same three rules apply to every request.

Base URL

https://server.heyrik.com/api/v1 — every path in the API reference is relative to this.

Authentication

Authorization: Bearer <key> or X-API-Key: <key>. Keys are created in the dashboard under API keys and only ever see their own account.

Envelopes

Success is { "data": … }. Errors are { "error": "<machine_code>", "hint"?: "…" } with a matching HTTP status. Lists may add total, page, limit.

Rate limits

API-key traffic is throttled per key (429 rate_limited — back off and retry). The live-leads webhook allows 600 posts per minute per source IP.

A minimal client (Node.js)
const api = async (path, init = {}) => {
  const r = await fetch("https://server.heyrik.com/api/v1" + path, {
    ...init,
    headers: {
      Authorization: `Bearer ${process.env.HEYRIK_API_KEY}`,
      "Content-Type": "application/json",
      ...init.headers,
    },
  });
  const body = await r.json();
  if (!r.ok) throw new Error(`${r.status} ${body.error}: ${body.hint ?? ""}`);
  return body.data;
};
02

Results webhook — every finished call, delivered to you

Set webhook_url on a campaign. HeyRik POSTs JSON to it when a lead's call finishes and once more when the whole campaign completes.

Set the URL (create or PATCH a campaign)
curl -X PATCH https://server.heyrik.com/api/v1/campaigns/cmp_4a19 \
  -H "Authorization: Bearer $HEYRIK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "webhook_url": "https://api.acme.com/heyrik/results" }'
What arrives after each call — event: contact_completed
{
  "event": "contact_completed",
  "campaign_id": "cmp_4a19",
  "campaign_name": "July outreach",
  "contact_id": "cct_9b1e",
  "phone": "+919876543210",
  "status": "completed",
  "outcome": "completed",
  "attempts": 1,
  "category": "hot",
  "variables": { "name": "Ravi", "order_id": "AC-8842" },
  "call_id": "call_8eab93e5",
  "call": {
    "summary": "Ravi confirmed the order and asked for a callback on Monday.",
    "outcome": "completed",
    "duration_ms": 214000,
    "recording_url": "https://example.com/rec.mp3",
    "extracted_variables": { "callback_requested": "yes", "interest_level": "high" }
  },
  "ts": "2026-08-24T13:41:07.512Z"
}
When the run finishes — event: campaign_completed
{
  "event": "campaign_completed",
  "campaign_id": "cmp_4a19",
  "campaign_name": "July outreach",
  "counts": { "pending": 0, "calling": 0, "completed": 231, "failed": 19, "retry": 0, "total": 250 },
  "ts": "2026-08-24T18:02:44.001Z"
}

Respond 2xx quickly

HeyRik waits up to 12 seconds and does not retry a failed delivery. Acknowledge first, then do your work in a queue.

Make it idempotent

Key your storage on contact_id + call_id. A lead with retries produces one event per attempt that ended; status is the final one for that attempt.

Read the fields you asked for

call.extracted_variables carries the agent's output variables and any campaign extraction_schema fields; category is the classify bucket, if you set one.

Keep the URL private

The webhook has no signature yet — use an unguessable path or a query token you validate, and only accept HTTPS.

A handler that stays fast (Express)
app.post("/heyrik/results", express.json(), async (req, res) => {
  const ev = req.body;
  res.sendStatus(200);                       // ack first — HeyRik times out at 12 s

  if (ev.event === "contact_completed") {
    await queue.add("heyrik-result", {
      key: `${ev.contact_id}:${ev.call_id}`,   // idempotency
      phone: ev.phone,
      outcome: ev.outcome,
      fields: ev.call?.extracted_variables ?? {},
      recording: ev.call?.recording_url ?? null,
    });
  } else if (ev.event === "campaign_completed") {
    await notifyOps(`Campaign ${ev.campaign_name} done: ${JSON.stringify(ev.counts)}`);
  }
});
03

Live-leads webhook — feed a campaign from your own system

Every campaign has its own ingest URL and token. Your CRM, form, or ad platform posts leads to it as they arrive; HeyRik dials them inside the calling window.

Copy the URL

Open the campaign in the dashboard → Live leads webhook. The URL carries the campaign's own token (cin_…), so no account API key is needed — and a leaked token exposes only that one campaign.

Send the token your way

?token=cin_… in the URL, the X-Campaign-Token header, or token in the JSON body — whichever your tool supports.

Rotate when in doubt

Rotate from the campaign page; the old token stops working immediately.

Post one lead or many
curl -X POST "https://server.heyrik.com/api/campaigns/cmp_4a19/ingest?token=cin_4ead0ca15938393bbb0eac35f6" \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "phone": "+919876543210", "fullName": "Ravi Kumar", "company": "Acme", "priority": 5 },
      { "phone": "+919123456789", "fullName": "Asha Patel", "company": "Nimbus" }
    ]
  }'
Response
{
  "data": { "added": 2, "skipped": 0, "rounded": 0, "total": 252, "reopened": false }
}

A single lead works too

Post { "phone": "+91…", "name": "…" } without the contacts wrapper. Add "fast": true to a lead (or the batch) to dial it before everything else.

It reopens finished campaigns

A campaign is continuous: posting to a completed campaign sets it running again and the new leads are dialled. Only a cancelled campaign refuses leads (409 campaign_closed).

Numbers must be complete

Send phones as strings in E.164 (+919876543210). A value like 9.17993E+11 — Excel's rounded form — has lost digits; it is counted in rounded and skipped, never dialled.

04

How lead fields reach the agent

Every field you send with a lead is available to the agent as a {{variable}}. You do not have to match the agent's names.

An agent declares input variables — say prospect_name,prospect_company, industry_segment. When a campaign dials a lead, HeyRik maps the lead's fields to those variables by meaning: a field called fullName, Decision Maker or Contact person all fill prospect_name. The mapping is worked out once per campaign (an AI reads the field names and a few sample values), stored on the campaign, and applied to every lead — uploaded, posted to the webhook, or added by hand. A field named exactly like the variable is used as-is.

What you send
{
  "phone": "+919876543210",
  "Decision Maker": "Aju Thomas",
  "Company": "CIRIL",
  "Segment": "Real Estate & Construction",
  "Role / Headline": "Corporate Real Estate Professional",
  "Location": "Hyderabad, Telangana, India"
}
What the agent's prompt sees
prospect_name      = Aju Thomas
prospect_company   = CIRIL
industry_segment   = Real Estate & Construction
prospect_role      = Corporate Real Estate Professional
prospect_location  = Hyderabad, Telangana, India
agent_name         = (the variable's default)
05

Campaign lifecycle

What each status means for your integration.

06

Prefer polling? Read results instead

Everything the webhook delivers is also readable, so a batch job can reconcile without receiving anything.

Progress, then the finished leads
# progress + counts
curl https://server.heyrik.com/api/v1/campaigns/cmp_4a19 -H "Authorization: Bearer $HEYRIK_API_KEY"

# every finished lead with outcome, category, extracted fields
curl "https://server.heyrik.com/api/v1/campaigns/cmp_4a19/contacts?status=completed&limit=500" \
  -H "Authorization: Bearer $HEYRIK_API_KEY"

# one lead with its recording + transcript
curl https://server.heyrik.com/api/v1/campaigns/cmp_4a19/contacts/cct_9b1e -H "Authorization: Bearer $HEYRIK_API_KEY"

# or the whole run as a CSV
curl https://server.heyrik.com/api/v1/campaigns/cmp_4a19/export -H "Authorization: Bearer $HEYRIK_API_KEY" -o results.csv
401api_key_required

No key, or a revoked one. Create a new key in the dashboard.

402insufficient_credits

Top up before starting a run; `need` tells you the minimum.

404campaign_not_found

Wrong id, or a campaign owned by another account.

409campaign_closed

The campaign was cancelled — create a new one.

429rate_limited

Back off with jitter and retry.

07

Go-live checklist

Ten minutes of checks that prevent a bad first campaign.