Skip to main content

Getting Started

This page walks you from a fresh API key to a working end‑to‑end integration that authenticates, finds a call by date range, fetches its transcription and downloads the audio. Every step uses plain curl so you can paste it straight into a terminal.

For a per‑endpoint reference (request shapes, filters, response schemas) see the Endpoint Reference.


Prerequisites

Before you can call the API you need three things from your Focus account:

ItemWhere it comes fromNotes
API keyAdmin → Account → Integrations → Native Focus REST APIA Super User must enable the API and generate the key. Treat it like a password.
clientIdSame admin page (numeric account id)Identifies your tenant.
Integration usernameAuto‑generated and shown next to the API keyFocus provisions a dedicated service user when you enable the API; you don't choose its name. The token inherits this user's roles and rights.
Base URLDetermined by your tenant's region — see Base URLsThe API is regionally deployed.
Service user permissions

Only grant the rights your integration actually needs. The capability matrix lists the right required for each endpoint. A typical "metadata + audio download" integration needs Recording.View, Recording.Play and Recording.Transcription.View.


Base URLs and environments

The API is deployed regionally. Your base URL follows the pattern:

https://<region>.focus.subphonic.ai/api

Where <region> is one of:

Region codeRegion
ukUnited Kingdom
euEuropean Union
usUnited States
caCanada

For example, a UK tenant uses https://uk.focus.subphonic.ai/api. Throughout these docs we refer to your base URL as {{baseUrl}}. Routes shown in the reference are exact paths to append, e.g. {{baseUrl}}/client/recording.search.


Authentication

All authenticated calls take a short‑lived bearer JWT in the Authorization header. You exchange your API key for that JWT (and a refresh token) via POST /authWithApiKey.

Request

  • Method: POST
  • URL: {{baseUrl}}/authWithApiKey
  • Headers: Content-Type: application/json
  • Body:
{
"clientId": 1234567,
"apiKey": "YOUR-API-KEY-XYZ",
"username": "YOUR-INTEGRATION-USERNAME"
}

All three values are shown together in the admin portal when you enable the API. The username is auto‑generated by Focus — use it exactly as displayed.

Example

curl -X POST "$BASE_URL/authWithApiKey" \
-H "Content-Type: application/json" \
-d '{
"clientId": 1234567,
"apiKey": "YOUR-API-KEY-XYZ",
"username": "YOUR-INTEGRATION-USERNAME"
}'

Response

{
"token": "eyJhbGciOi...",
"refreshToken": "eyJhbGciOi..."
}

Use token as the bearer for subsequent calls:

curl -H "Authorization: Bearer $TOKEN" "$BASE_URL/admin/retentionGroup"

Token lifetime & refresh

Bearer tokens are short‑lived (minutes, not hours). When a call returns 401 Unauthorized your token has expired — request a new one by calling POST /authWithApiKey again with the same credentials. There is no need to cache or rotate the API key itself.


End‑to‑end walkthrough: search → transcript → download

The diagram below shows the typical flow for an integration that finds calls and pulls their content. Every numbered step maps to a curl example below.

Step 1 — Authenticate

See Authentication above. Capture the token value into an environment variable:

TOKEN=$(curl -s -X POST "$BASE_URL/authWithApiKey" \
-H "Content-Type: application/json" \
-d '{"clientId":1234567,"apiKey":"YOUR-API-KEY-XYZ","username":"YOUR-INTEGRATION-USERNAME"}' \
| jq -r .token)

Step 2 — Search for recordings

Find every recording in a 24‑hour window, newest first, 100 per page:

curl -X POST "$BASE_URL/client/recording.search" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"dateTimeRange": {
"from": "2026-05-12T00:00:00Z",
"to": "2026-05-13T00:00:00Z"
},
"startTimeDirection": "DESC",
"page": 1,
"pageSize": 100
}'

Each item in the recordings array carries both an interactionId (numeric, used for transcripts and detail) and a thirdPartyId (string, used for audio download). Page through results using the page and pageSize fields and the total count in the response.

See recording.search for the full filter list (free text, person ids, endpoints, communication type, direction, tags, duration, etc.).

Step 3 — Fetch the transcription

curl -X POST "$BASE_URL/client/recording.transcription.get" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "interactionIds": [9876543] }'

The response contains the transcript segments with timestamps and speaker information. If the recording has no transcript (e.g. transcription is disabled, or the call hasn't been processed yet) the array is empty.

Step 4 — Download the audio

Audio download is keyed on thirdPartyId (taken from the search result), and lets you pick the format:

curl -X POST "$BASE_URL/client/recording.playBackByThirdPartyId" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ "thirdPartyId": "abc-123-call-id", "format": "mp3" }' \
--output recording.mp3

Supported formats: mp3, mp3-mono, wav, wav-mono, raw, mp4. The response is a binary stream; pipe it to a file as shown.

Forced comments

If your account has the forced comments feature enabled, every audio download must be accompanied by a justification. Pass it as "comment": "QA review for ticket #1234" in the request body, otherwise the call returns 400 ValidationError.


Pagination

All search endpoints accept page (1‑based) and pageSize and return a total count alongside the result array. Pick a pageSize that keeps response payloads under a few MB — 100500 is a sensible default for recording search; 1000 is fine for lighter resources like users.

{
"page": 1,
"pageSize": 100,
"total": 4321,
"recordings": [ /* ... */ ]
}

For long‑running synchronisation jobs, prefer narrowing by dateTimeRange over deep paging — it is more efficient and resilient to data being added concurrently.


Errors

The API uses standard HTTP status codes. JSON error bodies always include a human‑readable message and, where applicable, a well‑known error prefix you can pattern‑match against.

StatusMeaningTypical cause
400Validation errorBody failed schema validation; required field missing; forced‑comment not supplied.
401UnauthenticatedMissing, malformed or expired bearer token — re‑authenticate.
403ForbiddenThe service user lacks the required right for this endpoint.
404Not foundThe requested recordingId / thirdPartyId doesn't exist or isn't visible to your user.
429Too many requestsRate limit exceeded — back off and retry.
5xxServer errorTransient — retry with exponential backoff.

Always inspect the response body for diagnostic detail; do not rely on status code alone.


Rate limits

The API applies per‑tenant rate limits to protect overall service health. Exact limits depend on your contract and region — please check with your Focus account manager for the values that apply to you. Build your client to:

  • Treat 429 Too Many Requests as a signal to back off (start with 1s, double on each retry, cap at ~30s).
  • Honour any Retry-After header if present.
  • Avoid bursts: throttle bulk synchronisation jobs to a steady request rate rather than firing in parallel.

Next steps

Docs AssistantAsk anything about our products