Developers · API
v1API reference
The base URL is https://console-api.livespeech.ai, and every request sends the API key as a Bearer token. The first part of this page is the rules shared by every request; the second part is the endpoint-by-endpoint specification.
Authorization: Bearer ls_partner_0123abcd...
A missing or malformed key answers 401 with a WWW-Authenticate: Bearer header.
Keys
| Item | Detail |
|---|---|
| Format | ls_partner_ + 64 hexadecimal characters |
| Issued | By LiveSpeech when your partner account is set up |
| Shown | Once, at issue — the server does not keep the plain text |
| Count | One account key covers all lines (no per-line keys) |
Keep the key in a server environment variable or secret store and send requests from your server. In a browser or mobile app it would let anyone control every line you have.
Scopes
A key carries a set of scopes that says what it can do. Check the ones you have with GET /v1/whoami.
| Scope | Requests that need it |
|---|---|
tenants | Create, list, read and terminate lines |
config | Read and update agent settings |
calls | List call results |
webhooks | Register and read the webhook |
Without the scope you get 403 and a message naming the scope you need. Ask support@livespeech.ai for scopes you are missing.
{ "error": "Insufficient scope: calls required" }
Telling refusals apart
| Status | Meaning | What to do |
|---|---|---|
401 | The key is missing, malformed or no longer valid | Check the header and the key value; if it persists, email support@livespeech.ai |
403 | The key is valid but lacks the scope, or the line belongs to another account | Ask for the scope, or check the line identifier |
For security, 401 does not say which reason applies. Reading another account's line answers the same 403 without revealing whether the line exists.
Rate limit
| Item | Value |
|---|---|
| Counted per | Sending server IP + request path |
| Limit | 30 requests per 5 minutes |
| When exceeded | 429 + {"error":"Too many requests. Please try again later."} |
Different paths are counted separately — line A's call list and line B's call list have separate limits. On 429, wait a moment and send again; if it keeps happening, widen the interval. For a bulk sync, tell support@livespeech.ai in advance.
Retrying safely with an idempotency key
Creating a line (POST /v1/tenants) accepts an Idempotency-Key header. If the connection drops before you get the response, sending the same key again returns the first response without creating a second line.
Idempotency-Key: create-mall-00123-1
| Item | Detail |
|---|---|
| Format | 1–128 printable ASCII characters, no whitespace |
| Kept for | At least 24 hours — it may be deleted after that |
| Same key + same body | The stored first response is replayed |
| Same key + different body | 409 IDEMPOTENCY_KEY_MISMATCH |
| First request still running | 409 IDEMPOTENCY_IN_PROGRESS — try again shortly with the same key |
| Malformed | 400 (the key is not consumed) |
If the first request failed, the key is released — sending it again runs the request anew. Reuse a key only when retrying that same request, and always use a new key for a new creation (for example create-{customerId}-{signupId}). If a key past its retention is still around, you get the earlier response or a 409 back.
Request format
| Item | Detail |
|---|---|
| Body | JSON (Content-Type: application/json) |
| Response | JSON |
| Times | ISO 8601 UTC (2026-09-09T04:15:22.140Z) |
| Characters | UTF-8 |
Endpoints
Base URL: https://console-api.livespeech.ai
Account
Endpoints about the partner account itself (identity and scopes).
Identify the partner (whoami)
/v1/whoamiAuthenticates with the Bearer partner key and returns the identity of the partner the key belongs to. It needs no line scope (the delegation gate is not involved), so use it to verify the authentication plumbing.
Responses
200The authenticated partner identity.
| Field | Type | Required | Description |
|---|---|---|---|
partnerId | string | required | Unique partner identifier. |
name | string | required | Partner display name. |
scopes | string[] | required | Scopes granted to this partner. Values: |
keyPrefix | string | required | Display prefix of the key used to authenticate (not the full key). |
401Authentication failed. The error string is one of two:
Missing or invalid Authorization header— the Authorization header is missing or not inBearer {token}form.Invalid API key— key format/hash mismatch · revoked · inactive (the specific reason is not disclosed).
Example · Authorization header missing / malformed
{
"error": "Missing or invalid Authorization header"
}Example · Key format/hash mismatch · revoked · inactive
{
"error": "Invalid API key"
}403The key is valid but the partner account is not active (suspended).
Lines
Line provisioning (tenants scope). Works only on delegated lines.
List lines
/v1/tenantsParameters
| Name | Type | Required | Description |
|---|---|---|---|
limit | integer · query | optional | 1–200 · default 50 |
cursor | string · query | optional | nextCursor from the previous response (an opaque token). |
Responses
200A page of the lines delegated to this partner.
| Field | Type | Required | Description |
|---|---|---|---|
tenants | object[] | required | |
tenants[].tenantId | string | required | |
tenants[].name | string | required | |
tenants[].region | string | null | required | Values: |
tenants[].status | string | required | Values: |
tenants[].externalId | string | null | required | |
tenants[].createdAt | string | null | required | date-time |
nextCursor | string | null | required |
400Malformed request.
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope · line not delegated.
Create a line
/v1/tenantsCreates a line. The response carries no phone number (the number is connected separately). With an Idempotency-Key header, a repeat request with the same key replays the stored first response (no duplicate creation). externalId is your identifier for the line (a mall id, say); creating again with the same value is refused with 409.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key | string · header | optional | Idempotency key for safe retries (1–128 printable ASCII characters, no whitespace). A repeat with the same key and the same body replays the stored first response. The same key with a different body is refused with 409 ( IDEMPOTENCY_KEY_MISMATCH) — so a request never looks successful while its body was ignored.
≤ 128 chars |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | required | Display name of the line (the business). ≤ 200 chars |
region | string | required | Service (telephony) region. Values: |
externalId | string | required | Your identifier for the line (the duplicate-creation guard). 1–128 printable ASCII characters, no whitespace. ≤ 128 chars |
agent | object | optional | Agent settings. PUT is a partial patch that updates only the fields sent.
|
agent.persona | string | optional | The agent's persona prompt. The length limit applies to the text you send. On save, a sentence announcing the call context is added in front, so GET and PUT responses are longer than what you sent by that much. Sending that value back does not duplicate the sentence.
≤ 8000 chars |
agent.greeting | string | optional | ≤ 1000 chars |
agent.tone | string[] | optional | ≤ 20 items · each ≤ 60 chars |
agent.businessHours | object | null | optional | {mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}. |
agent.transfer | object | null | optional | {type: take_message|standard_response|transfer_human, message}. |
agent.summaryRecipients | object[] | optional | ≤ 20 items |
agent.summaryRecipients[].email | string | required | |
agent.summaryRecipients[].keywords | string[] | optional | ≤ 20 items · each ≤ 60 chars |
Responses
201The created line. No number field.
| Field | Type | Required | Description |
|---|---|---|---|
tenantId | string | required | |
name | string | required | |
region | string | null | required | Values: |
status | string | required | Values: |
externalId | string | null | required | |
createdAt | string | null | required | date-time |
400Malformed request.
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
402Line quota exceeded (code: TENANT_QUOTA_EXCEEDED).
403Partner inactive · missing scope · line not delegated.
409code: EXTERNAL_ID_EXISTS — a line with this externalId already exists.
code: IDEMPOTENCY_IN_PROGRESS — a request with the same Idempotency-Key is still running.
code: IDEMPOTENCY_KEY_MISMATCH — the same Idempotency-Key was reused with a different body.
Read a line
/v1/tenants/{customerId}Includes the number (null before one is connected), integration status and a plan summary.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
customerId | string · path | required | Line identifier. 403 if the line is not delegated to this partner (existence is not revealed). |
Responses
200Line detail.
| Field | Type | Required | Description |
|---|---|---|---|
tenantId | string | required | |
name | string | required | |
region | string | null | required | Values: |
status | string | required | Values: |
externalId | string | null | required | |
createdAt | string | null | required | date-time |
number | string | null | required | The number currently being served (null if none). |
integrations | object | required | Store integration status per provider. |
integrations.cafe24 | object | optional | |
integrations.cafe24.connected | boolean | optional | |
integrations.nextengine | object | optional | |
integrations.nextengine.connected | boolean | optional | |
plan | object | null | required | |
plan.tier | string | null | optional | |
plan.status | string | null | optional |
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope · line not delegated.
Terminate a line
/v1/tenants/{customerId}Terminates the line. A line that still holds an active number must have it released first; until then termination is held with 502 (CARRIER_RELEASE_FAILED) and the line stays active. Email support@livespeech.ai with the tenantId to release the number.
purge: true also removes what the line stored, such as the persona and summary recipients.
Once termination completes, the externalId mapping and the delegation link are released: the same externalId can be used to sign up (create) again, the terminated line no longer counts against the quota, and it disappears from list and read (later access answers 403).
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
customerId | string · path | required | Line identifier. 403 if the line is not delegated to this partner (existence is not revealed). |
Request body(optional)
| Field | Type | Required | Description |
|---|---|---|---|
reason | string | optional | ≤ 500 chars |
purge | boolean | optional | default false |
Responses
200Termination complete.
| Field | Type | Required | Description |
|---|---|---|---|
status | string | required | Values: |
numberReclaimed | boolean | required | |
terminatedAt | string | required | date-time |
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope · line not delegated.
409A line that was already terminated but whose delegation was not yet released (code: ALREADY_TERMINATED). This retry runs the release again. A line whose termination and release are fully complete has no delegation, so it answers 403.
502Number release failed — termination held (code: CARRIER_RELEASE_FAILED).
Agent settings
Agent settings for a line (config scope).
Read agent settings
/v1/tenants/{customerId}/agentParameters
| Name | Type | Required | Description |
|---|---|---|---|
customerId | string · path | required | Line identifier. 403 if the line is not delegated to this partner (existence is not revealed). |
Responses
200The current agent settings.
| Field | Type | Required | Description |
|---|---|---|---|
persona | string | optional | The agent's persona prompt. The length limit applies to the text you send. On save, a sentence announcing the call context is added in front, so GET and PUT responses are longer than what you sent by that much. Sending that value back does not duplicate the sentence.
≤ 8000 chars |
greeting | string | optional | ≤ 1000 chars |
tone | string[] | optional | ≤ 20 items · each ≤ 60 chars |
businessHours | object | null | optional | {mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}. |
transfer | object | null | optional | {type: take_message|standard_response|transfer_human, message}. |
summaryRecipients | object[] | optional | ≤ 20 items |
summaryRecipients[].email | string | required | |
summaryRecipients[].keywords | string[] | optional | ≤ 20 items · each ≤ 60 chars |
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope · line not delegated.
Update agent settings (partial)
/v1/tenants/{customerId}/agentA partial patch that updates only the fields sent. It can take up to 5 minutes for a change to reach live calls.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
customerId | string · path | required | Line identifier. 403 if the line is not delegated to this partner (existence is not revealed). |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
persona | string | optional | The agent's persona prompt. The length limit applies to the text you send. On save, a sentence announcing the call context is added in front, so GET and PUT responses are longer than what you sent by that much. Sending that value back does not duplicate the sentence.
≤ 8000 chars |
greeting | string | optional | ≤ 1000 chars |
tone | string[] | optional | ≤ 20 items · each ≤ 60 chars |
businessHours | object | null | optional | {mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}. |
transfer | object | null | optional | {type: take_message|standard_response|transfer_human, message}. |
summaryRecipients | object[] | optional | ≤ 20 items |
summaryRecipients[].email | string | required | |
summaryRecipients[].keywords | string[] | optional | ≤ 20 items · each ≤ 60 chars |
Responses
200The full settings after the update.
| Field | Type | Required | Description |
|---|---|---|---|
persona | string | optional | The agent's persona prompt. The length limit applies to the text you send. On save, a sentence announcing the call context is added in front, so GET and PUT responses are longer than what you sent by that much. Sending that value back does not duplicate the sentence.
≤ 8000 chars |
greeting | string | optional | ≤ 1000 chars |
tone | string[] | optional | ≤ 20 items · each ≤ 60 chars |
businessHours | object | null | optional | {mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}. |
transfer | object | null | optional | {type: take_message|standard_response|transfer_human, message}. |
summaryRecipients | object[] | optional | ≤ 20 items |
summaryRecipients[].email | string | required | |
summaryRecipients[].keywords | string[] | optional | ≤ 20 items · each ≤ 60 chars |
400Malformed request.
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope · line not delegated.
409The line is terminated (code: TENANT_TERMINATED).
Call results
Call results for a line (calls scope). Summaries only — no transcripts or recording URLs.
List a line's call results
/v1/tenants/{customerId}/callsCall summaries for a delegated line, newest first. Returns summary fields only — no full transcript or recording URL, and the caller's number (callerNumber) is masked to its last four digits. Calls the operator deleted in the console do not appear.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
customerId | string · path | required | Line identifier. 403 if the line is not delegated to this partner (existence is not revealed). |
limit | integer · query | optional | Page size (1–200). 1–200 · default 50 |
cursor | string · query | optional | nextCursor from the previous response. A tampered or damaged value answers 400 (INVALID_CURSOR). |
since | integer · query | optional | Epoch milliseconds. Returns only calls whose summary was stored at or after this time — the same basis as startedAt.≥ 0 |
Responses
200A page of call summaries.
| Field | Type | Required | Description |
|---|---|---|---|
calls | object[] | required | |
calls[].callId | string | required | Call (session) identifier. The same key as the webhook's callId. |
calls[].startedAt | string | null | required | The time the summary was stored (ISO 8601). Not when the call started: it is set after the call ends and the summary is ready. Use durationSecs for the call length.date-time |
calls[].title | string | null | optional | One-line title. |
calls[].summary | string | null | required | The call summary. |
calls[].durationSecs | integer | null | optional | Call length in seconds. |
calls[].callType | string | null | optional | Values: |
calls[].callerNumber | string | null | optional | Caller's number — masked (only the last four digits shown). |
calls[].transferred | boolean | optional | |
calls[].transferTo | string | null | optional | |
calls[].resolution | string | null | optional | Values: |
calls[].sentiment | string | null | optional | Values: |
calls[].topics | string[] | optional | |
nextCursor | string | null | required | Cursor for the next page. null on the last page. |
400Malformed request.
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope · line not delegated.
Webhooks
Push delivery of call completions (webhooks scope). One endpoint per partner.
Read the current webhook configuration
/v1/webhooksReturns the current configuration. Only the last four characters of the signing secret are included.
Responses
200The current webhook configuration.
| Field | Type | Required | Description |
|---|---|---|---|
url | string | required | |
events | string[] | required | Values: |
signingSecretHint | string | required | The last four characters of the signing secret (for identification — cannot sign). |
createdAt | string | null | optional | date-time |
updatedAt | string | null | optional | date-time |
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope.
404No webhook registered (code: WEBHOOK_NOT_CONFIGURED).
Register or replace the webhook endpoint
/v1/webhooksRegisters (or replaces) the one webhook endpoint per partner. The URL must be https; URLs with credentials and private or loopback hosts are refused (422 WEBHOOK_URL_INVALID). Omitting events subscribes to every supported event; if an unsupported event is included, the whole request is refused with 422 UNKNOWN_EVENT.
The signing secret is returned in full only in this response (signingSecret) — it was issued when the partner account was created, and the registration response is its official hand-over. Later GETs return only a four-character hint.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | required | The https delivery URL. No credentials; no private or loopback hosts. ≤ 2048 chars |
events | string[] | optional | Events to subscribe to. Omit to subscribe to every supported event. Values: ≥ 1 items |
Responses
200The registered configuration plus the full signing secret (this response only).
| Field | Type | Required | Description |
|---|---|---|---|
url | string | required | |
events | string[] | required | Values: |
signingSecret | string | required | The full HMAC signing secret ( whsec_ + hex). Returned only in the PUT response — store it somewhere safe. To verify, drop whsec_ and hex-decode the rest to get the key.
|
createdAt | string | optional | date-time |
updatedAt | string | optional | date-time |
400Malformed request.
401Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).
403Partner inactive · missing scope.
422URL format or host violation (WEBHOOK_URL_INVALID) · unsupported event (UNKNOWN_EVENT).
Call completed event delivery
call.completed → to your registered webhook URLWhen a line's call (session) ends and its summary is final, a call.completed event is POSTed to the registered webhook URL. The payload carries tenantId so the partner can route it to the right store. Phone numbers, transcripts and recording URLs are not included.
Delivery guarantee: at least once. The same callId can arrive twice on rare occasions, so the receiver must de-duplicate by callId.
Success and retries: a 2xx response counts as success (the body is ignored; respond within 10 seconds; redirects are not followed and count as failure). 5xx · 408 · 429 · no response (timeout, connection failure, redirect) are retried with exponential backoff (starting at 1 minute, doubling, up to 1 hour apart), for 8 attempts in total including the first. Any other 4xx is taken as the receiver refusing the request: no retry, and that delivery ends.
Signature verification (X-LiveSpeech-Signature):
- Parse the header:
t={unix seconds},v1={hex HMAC}. - Drop the
whsec_prefix from the secret and hex-decode it to get the raw key. - Sign
{t}.{raw request body bytes}with HMAC-SHA256 and compare withv1in constant time. - Reject as a replay if
tis more than 5 minutes away from the current time.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
X-LiveSpeech-Event | string · header | required | Event type. Values: |
X-LiveSpeech-Delivery | string · header | required | Delivery identifier (= callId). The same value on retries. |
X-LiveSpeech-Signature | string · header | required | t={unix seconds},v1={hex HMAC-SHA256} — see the verification steps above. |
Request body
call.completed webhook payload. Phone numbers, transcripts and recording URLs are not included. summary, however, is free text summarizing the conversation and may contain personal data mentioned during the call (names, order numbers, addresses) — store and process the payload as personal data.
| Field | Type | Required | Description |
|---|---|---|---|
event | string | required | Values: |
tenantId | string | required | The line the call belongs to — your routing key. |
callId | string | required | Call (session) identifier. The same as callId in GET /calls. The de-duplication key. |
occurredAt | string | required | When the call ended (summary finalized). date-time |
summary | string | required | The call summary. |
resolution | string | null | required | Values: |
recordingAvailable | boolean | required | Whether a recording is expected to exist (true for phone calls). Recordings are not provided through the API. |
Responses
2XXReceived (the body is ignored). 5xx · 408 · 429 · no response are retried; any other 4xx is not.