Authentication and API basics
Every customer endpoint, apart from health and version checks, requires a JSON Web Token (JWT). You exchange account credentials for a token, then send it on each request.
Request a token
curl --request POST "https://api.example.com/api/v1/auth/token" \
--header "Content-Type: application/json" \
--data '{
"username": "your-username",
"password": "your-password"
}'
{
"token": "eyJ...",
"expires": "2026-10-01T14:00:00Z",
"eventId": "1234"
}
| Field | Meaning |
|---|---|
token | The JWT. Send it as Authorization: Bearer <token>. |
expires | When the token stops being accepted. Request a new one before this time. |
eventId | The id of the account the token belongs to. |
Token lifetime is set per deployment (typically two hours). Token responses are never encrypted, even when response encryption is on, so you can always authenticate before you can decrypt.
Two-factor sign-in
If the user has two-factor authentication turned on (any user can turn it on for their own sign-in in the Speechlytics web app), the first call does not return a token. It returns 401 with a challenge:
{
"error": "two_factor_required",
"challengeToken": "eyJ...",
"expires": "2026-10-01T12:05:00Z"
}
Complete sign-in within five minutes by sending the challenge and a current code from the user's authenticator app:
curl --request POST "https://api.example.com/api/v1/auth/token/2fa" \
--header "Content-Type: application/json" \
--data '{
"challengeToken": "eyJ...",
"code": "123456",
"useRecoveryCode": false
}'
The response has the same shape as /api/v1/auth/token. To sign in with one of the user's single-use recovery codes, send it as code and set useRecoveryCode to true.
Unattended integrations cannot answer a two-factor prompt, and any user can turn two-factor authentication on for themselves. Use a dedicated API user that does not have it turned on, and protect its credentials in a secret store.
Failed sign-ins and lockout
| Response | Cause |
|---|---|
401 "User not confirmed!" | The user does not exist or has not confirmed their email. |
401 "Bad credentials!" | Wrong password, or the user is locked out. |
401 "Invalid or expired challenge." | The two-factor challenge is older than five minutes or is not valid. |
401 "Invalid verification code." | The authenticator or recovery code was wrong or already used, or the user is locked out. |
429 Too Many Requests | Too many sign-in attempts from your address in a short window. |
Five consecutive failures (password or two-factor code) lock the user for 15 minutes. Sign-ins to the Speechlytics web app and the API share the same counter.
Rate limits
The API applies request-rate limits per client address and per endpoint group:
| Endpoints | Limit (default) |
|---|---|
/api/v1/auth/* | 10 requests per minute per address. |
| Other customer endpoints | A deployment-wide allowance of 10 requests per 10 seconds, shared by all clients, plus 60 requests per minute per address for each endpoint. |
Provider webhooks (/api/v1/webhooks/*) | A separate allowance of 300 requests per minute per address, so a burst of provider events does not consume the API allowance. |
A request over the limit receives 429 Too Many Requests. Back off and retry; do not retry in a tight loop. For bulk ingestion, prefer submitting URLs to uploading base64 bodies, and spread submissions over time. Limits are set per deployment; ask your representative if you need a higher allowance.
Enums
The API reference shows enum values as <number> - <name> (for example 2 - Processed). On the wire, enums are integers in both requests and responses:
{ "language": 0, "hasPriority": false }
The main enums you will meet are:
| Enum | Values |
|---|---|
CallStatus | 0 Queued, 1 InProgress, 2 Processed, 3 Failed, 4 QuotaLimit, 5 NotFound, 6–14 pipeline stages, 15 PolishStarted, 16 PolishEnded, 17 PolishReverted, 18 PolishFailed, 19 PostProcessingDeferred |
Language | 0 Auto, 1 English, 2 Chinese, 3 German, 4 Spanish … 100 Cantonese. See the reference for the full list. |
AudioType | 0 Mono, 1 Stereo |
SummaryType | 0 Sales, 1 CustomerSupport |
Transcript segments report their channel as a string: Left (agent), Right (customer) or Both (mono or combined).
Errors
- Error responses (status
400and above) are never encrypted. - Treat
5xxand503responses as retryable with exponential backoff. - A call that does not exist, or belongs to another account, is reported as not found.
GET /api/v1/calls/{id}/statusreturns200withstatus: 5(NotFound); other call endpoints return404.
Health and version
These endpoints are anonymous and are useful for monitoring:
| Endpoint | Returns |
|---|---|
GET /api/v1/health | Database, queue, processing and search-index health for the deployment. |
GET /api/v1/health/sftp-monitors | For each monitored SFTP drop folder: the host, the number of files and the number of files waiting longer than expected. |
GET /version | The deployed API version. |