Your ATS talks to WebCallHub. WebCallHub talks to the phone network. Nobody retypes anything.
Navetech's ATS always makes outbound HTTPS calls to us — nothing opens in the firewall, no VPN, no software installed. We reach the ATS only if Navetech gives us a webhook URL; otherwise the ATS polls.
Three ways in — pick the one that matches your ATS
Tier 1 · No integration day 1
Recruiters use the WebCallHub desk (page 2). Candidate names come from a one-time CSV sync. Nothing to build.
- Number + seats
- History, recordings, outcomes in our portal
- Dashboards (page 3)
Tier 2 · Light ½ day of your dev
Your ATS pushes candidates nightly and shows a Call button on the candidate record. Screen-pop by name on inbound.
- POST /ats/candidates/sync
- POST /ats/click-to-call
- Optional: drop in <wch-dialer>
Tier 3 · Deep 1–2 days
Every call, recording link and outcome lands on the candidate record automatically.
- Signed webhook (below), or
- Poll GET /ats/calls?since_id= if the ATS is behind a firewall
- Write outcomes from your screen: POST /ats/calls/{id}/disposition
What your ATS receives — one JSON shape, three events
POST https://ats.navetech.example/hooks/webcallhub
X-WebCallHub-Event: call.disposition_updated
X-WebCallHub-Timestamp: 1757340000
X-WebCallHub-Signature: sha256=… (HMAC over "timestamp.body")
{
"version": 1,
"event": "call.disposition_updated",
"call_id": "ob-3f9c1a7e2b",
"direction": "outbound",
"origin": "ats_api",
"status": "completed",
"started_at": "2026-09-08T15:41:02",
"ended_at": "2026-09-08T15:45:14",
"duration_seconds": 252,
"candidate": { "id": "NAV-48213", "name": "Priya Raman",
"job_id": "REQ-2026-118", "system": "navetech-ats" },
"agent": { "email": "[email protected]", "extension": "t12a3" },
"outcome": { "code": "interested", "label": "Interested",
"notes": "Wants the Dallas hybrid role", "at": "2026-09-08T15:46:30",
"followup_at": null },
"recording_url": "https://app.webcallhub.com/api/recordings/ob-3f9c1a7e2b?token=…"
}
Dedupe on call_id (+ outcome.at for corrected outcomes). Verify the signature with the 10-line recipe in the docs. Answer 2xx fast; do your ATS write asynchronously.
The seven self-serve steps
| # | Step | Where |
|---|---|---|
| 1 | Create the workspace on the Recruiter plan; add recruiters | Sign up → Team |
| 2 | Buy the US number (caller ID; candidates ring it back) | Dashboard → Buy a number |
| 3 | Mint an API key: ats:read ats:write calls:originate | Dashboard → API keys |
| 4 | Push candidates (id, name, phone, job, recruiter) | POST /ats/candidates/sync |
| 5 | Call button on the candidate record | POST /ats/click-to-call |
| 6 | Webhook URL + signing secret (or poll) | Dashboard → Integrate → Your own CRM |
| 7 | Outcomes, history, reports | /ats/calls · /ats/reports/* |
Base URL https://app.webcallhub.com. Every endpoint is scoped to the workspace on the key — no request can reach another customer's candidates. Docs with a paste-ready verifier: CRM_INTEGRATION.md.
Also a CRM?
SuiteCRM and monday.com connect from the same Integrate page; every recruiter call lands there too as a Call record on the contact.
What we never do
Reach into your ATS, store resumes or notes, or send a transcript nobody consented to. We hold a thin candidate projection — enough to ring a phone and name who is calling.
What stays with you
The number (portable), the recordings (export any time), the candidate relationship. WebCallHub is the phone layer with a record — the ATS remains the system of record.