Skip to content

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.

Base URL ​

https://<your-app-domain>/api/public/v1

Same 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: v1

Additive 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/json on any request with a body. A charset parameter is fine — application/json; charset=utf-8 is compared correctly. Anything else is a 415.
  • Send x-request-id with 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-key on any write you might retry. See Idempotency.
  • There is no CORS and no OPTIONS handler. 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.