API overview
The DialCru public API is a JSON, server-to-server HTTP API. You authenticate with an API key that belongs to one organization, and every request acts as that organization.
- Authentication — how to send a key
- Scopes — what a key is allowed to do
- Pagination — cursors, and syncing with
updated_since - Rate limits — how hard you may ask
- Idempotency — retrying a write safely
- Errors — the error envelope and every code
- Endpoints: root, contacts import, calls, suppressions, lead results, QA reviews, QA rubrics, webhook endpoints, usage
Base URL
https://<your-app-domain>/api/public/v1Same origin as the dashboard. The path is defined by API.PREFIX in src/lib/const/api.const.ts.
The public segment is meaningful: /api also hosts provider callback routes (Twilio, transcription) that are not part of this contract and are not callable with an API key.
Versioning
The version lives in the path, and is bumped only for a breaking change. When that happens the old version keeps serving until every integration has moved, so v1 will not disappear underneath you.
Every response carries the serving version back:
x-api-version: v1Additive changes — a new optional request field, a new response field, a new endpoint, a new scope — happen within v1 without notice. Ignore response fields you do not recognise, and do not assume the set of keys in a response object is closed.
Requests
content-type: application/jsonon any request with a body. A charset parameter is fine —application/json; charset=utf-8is compared correctly. Anything else is a415.- Send
x-request-idwith a value of your own: 1–200 printable ASCII characters, no spaces. It is echoed back on the response, and it is what lets a support conversation name one specific request. If you send none, or one outside those bounds, we mint one instead — and it is still returned, so always read the id off the response. - Send
idempotency-keyon any write you might retry. See Idempotency. - There is no CORS and no
OPTIONShandler. This API is server-to-server only, because a key usable from a browser is a key published in client-side source.
Responses
Every response is JSON with content-type: application/json; charset=utf-8, and carries x-api-version and x-request-id.
A successful single-resource response wraps the payload in data:
json
{
"data": {
"version": "v1",
"organization_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
}
}A successful list response puts the rows in data and adds pagination:
json
{
"data": [],
"pagination": {
"limit": 50,
"has_more": false,
"next_cursor": null
}
}Lists page with a cursor, not an offset: pass next_cursor back as cursor while has_more is true. The default page is 50 rows and the maximum is 100 (API.LIST). See Pagination.
Each resource's fields are listed on its endpoint page, and are the only fields it carries: a response is built from a published schema, so a field appears only when it has been documented.
An error replaces data with error:
json
{
"error": {
"code": "FORBIDDEN",
"message": "This API key is missing the campaign:write scope."
}
}The envelopes are built by json_ok, json_page and json_err in src/lib/utils/api/response.util.ts. See Errors for the full code list.
A first request
bash
curl -sS https://<your-app-domain>/api/public/v1 \
-H "authorization: Bearer $CALL_CENTER_API_KEY" \
-H "x-request-id: $(uuidgen)"That endpoint requires no scopes and tells you which organization your key speaks for and what it may do — start there, before any resource route. See the root endpoint.