Generic webhook integration
The universal path: any platform that can send an HTTP POST can push calls in, and any platform that can receive one can get reports out. This is the same contract every other integration is built on, framed as a setup guide.
Before you start
Create an API key with calls:write scope under Company → API keys.
The key authenticates the inbound endpoint via the X-Api-Key header. See
Authentication.
Step 1 — Send calls in (inbound)
POST a JSON body with your call details and the X-Api-Key header. The endpoint maps
flexible field names, so most platforms' native payloads work with little or no transformation. For
each value, the first matching key wins:
| Call attribute | Accepted JSON keys |
|---|---|
| External id | external_call_id, call_id, id |
| Rep name | rep_name, agent_name, user_name |
| Rep email | rep_email, agent_email |
| Customer name | customer_name, contact_name |
| Customer phone | customer_phone, phone, from |
| Customer email | customer_email, email |
| Recording URL | recording_url, recording, audio_url |
| Duration (sec) | duration_seconds, duration |
| Started at | call_started_at, started_at |
| CRM contact id | crm_contact_id, contact_id |
| CRM deal id | crm_deal_id, deal_id |
curl -X POST https://api.callanalyticsapi.com/webhooks/inbound/generic \
-H "X-Api-Key: cc_3a91f8e2_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"id": "evt-7781",
"contact_name": "Acme Corp",
"phone": "+15125550199",
"recording": "https://storage.example.com/rec/7781.mp3",
"duration": 1560,
"agent_name": "Jordan Lee"
}'
| Response | Meaning |
|---|---|
201 {"call_id":…,"status":"received"} | New call created. |
200 {"call_id":…,"status":"duplicate"} | External id seen before — existing call returned. Dedupe is keyed on the external id, so retries are safe. |
401 | Missing/invalid X-Api-Key. |
422 {"error":"empty_payload"} | Empty JSON body. |
The recording_url must be publicly fetchable — we download the audio from it. Use a
signed/public URL if your storage requires auth. The whole raw payload is stored with the call, so
unmapped fields are retained.
Step 2 — Receive reports out (outbound)
Add an endpoint under Company → Webhooks, subscribe it to events, and we POST a signed JSON body to your URL when they fire. Save the signing secret shown once at creation.
Events you can subscribe to
Most integrations only need call.report_completed — its payload includes the full
report.
Verifying the signature
Each delivery carries X-Cadence-Signature: t=<ts>,v1=<hmac>, an
HMAC-SHA256 over ts + "." + raw_body using your endpoint secret. Recompute and compare
in constant time, and reject timestamps outside a 300-second window. Full PHP and Node verification
snippets are on the Webhooks page.
Inspecting deliveries
Call GET /v1/webhooks/events to list recent outbound deliveries with their status,
response code, and attempt count — useful for debugging your receiver.
This generic contract underpins the GoHighLevel and Zapier guides. If a platform isn't listed, this is the path to use.