Developers
CallTracker REST API
The CallTracker API gives your own systems read access to one workspace: calls with their marketing attribution, placements and tracking numbers. It is read-only; to receive calls as they happen, use signed webhooks. The machine-readable spec is at /api/v1/openapi.json (OpenAPI 3.1).
Authentication
- Create a key in Settings β API access. Only members who can manage integrations can create or revoke keys.
- Choose the permissions the key needs: calls:read, placements:read, numbers:read.
- The full key (ct_live_β¦) is shown once. CallTracker stores only a SHA-256 hash of it.
- Send it on every request as 'Authorization: Bearer ct_live_β¦'. A key only sees data in the workspace it was created in.
- Revoking a key takes effect immediately. A workspace can have up to 10 active keys.
Endpoints
Base URL: https://calltracker.dev/api/v1
| Endpoint | Scope | Description |
|---|---|---|
| GET /calls | calls:read | List calls, newest first. Filters: from, to (ISO 8601), placementId, status. |
| GET /calls/{id} | calls:read | One call with its attribution and Google Ads upload status. |
| GET /placements | placements:read | List placements. Filter: active=true|false. |
| GET /numbers | numbers:read | Every tracking number: single placement numbers and dynamic number insertion pool numbers. |
Example
curl "https://calltracker.dev/api/v1/calls?from=2026-10-01T00:00:00Z&limit=50" \
-H "Authorization: Bearer $CALLTRACKER_API_KEY"{
"data": [
{
"id": "clx2k9d0f0001",
"placementId": "clx2k8z1a0000",
"callerNumber": "+4791234567",
"status": "completed",
"durationSeconds": 184,
"connectedSeconds": 179,
"aiHandled": false,
"tags": ["new-customer"],
"hasRecording": true,
"transcriptionStatus": "completed",
"startedAt": "2026-10-01T09:14:03.000Z",
"attribution": {
"trafficSource": "GOOGLE_ADS",
"utmSource": "google",
"utmMedium": "cpc",
"utmCampaign": "plumbing-oslo",
"utmTerm": "emergency plumber",
"utmContent": null,
"gclid": "Cj0KCQjw...",
"gbraid": null,
"wbraid": null,
"fbclid": null,
"msclkid": null,
"referrerUrl": "https://www.google.com/",
"landingPage": "https://example.com/emergency"
},
"googleAdsUploadStatus": "uploaded"
}
],
"nextCursor": "MjAyNi0xMC0wMVQwOToxNDowMy4wMDBafGNseDJrOWQwZjAwMDE"
}Values above are illustrative.
Pagination
- List endpoints return up to limit items (default 50, maximum 100), newest first.
- When more results exist, the response has a nextCursor. Pass it back as ?cursor=β¦ with the same filters to get the next page; it is null on the last page.
- Cursors are stable while new calls arrive, so paging does not skip or repeat calls.
Rate limits
- Each key can make 120 requests per minute.
- Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix seconds).
- Over the limit you get HTTP 429 with a Retry-After header in seconds.
Errors
Errors use one JSON shape with a stable code:
{ "error": { "code": "insufficient_scope", "message": "This API key needs the 'placements:read' scope." } }- 400 invalid_request: an unknown or malformed query parameter.
- 401 unauthorized: the key is missing, malformed or revoked.
- 403 insufficient_scope: the key lacks the permission for this endpoint.
- 404 not_found: no such record in this workspace.
- 429 rate_limited: wait for Retry-After seconds.
What the API does not do
- It cannot create, change or delete data.
- Recording audio and transcripts are not served by the API; hasRecording and transcriptionStatus tell you whether they exist in the dashboard.
- There is no OAuth app flow for third-party apps; keys belong to one workspace.
Pull call data into your stack
The REST API and webhooks are included in CallTracker Pro at no extra cost.