Skip to content
Start free

Developers · API

v1

API 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

ItemDetail
Formatls_partner_ + 64 hexadecimal characters
IssuedBy LiveSpeech when your partner account is set up
ShownOnce, at issue — the server does not keep the plain text
CountOne 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.

ScopeRequests that need it
tenantsCreate, list, read and terminate lines
configRead and update agent settings
callsList call results
webhooksRegister 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

StatusMeaningWhat to do
401The key is missing, malformed or no longer validCheck the header and the key value; if it persists, email support@livespeech.ai
403The key is valid but lacks the scope, or the line belongs to another accountAsk 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

ItemValue
Counted perSending server IP + request path
Limit30 requests per 5 minutes
When exceeded429 + {"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
ItemDetail
Format1–128 printable ASCII characters, no whitespace
Kept forAt least 24 hours — it may be deleted after that
Same key + same bodyThe stored first response is replayed
Same key + different body409 IDEMPOTENCY_KEY_MISMATCH
First request still running409 IDEMPOTENCY_IN_PROGRESS — try again shortly with the same key
Malformed400 (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

ItemDetail
BodyJSON (Content-Type: application/json)
ResponseJSON
TimesISO 8601 UTC (2026-09-09T04:15:22.140Z)
CharactersUTF-8

Endpoints

Base URL: https://console-api.livespeech.ai

Account

Endpoints about the partner account itself (identity and scopes).

Identify the partner (whoami)

get/v1/whoami

Authenticates 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

200

The authenticated partner identity.

The partner's own identity.
FieldTypeRequiredDescription
partnerIdstringrequired
Unique partner identifier.
namestringrequired
Partner display name.
scopesstring[]required
Scopes granted to this partner.

Values: tenants · config · calls · webhooks

keyPrefixstringrequired
Display prefix of the key used to authenticate (not the full key).
401

Authentication failed. The error string is one of two:

  • Missing or invalid Authorization header — the Authorization header is missing or not in Bearer {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"
}
403

The key is valid but the partner account is not active (suspended).

Lines

Line provisioning (tenants scope). Works only on delegated lines.

List lines

get/v1/tenants

Parameters

NameTypeRequiredDescription
limitinteger · queryoptional

1–200 · default 50

cursorstring · queryoptional
nextCursor from the previous response (an opaque token).

Responses

200

A page of the lines delegated to this partner.

FieldTypeRequiredDescription
tenantsobject[]required
tenants[].tenantIdstringrequired
tenants[].namestringrequired
tenants[].regionstring | nullrequired

Values: kr · ca

tenants[].statusstringrequired

Values: active · terminated

tenants[].externalIdstring | nullrequired
tenants[].createdAtstring | nullrequired

date-time

nextCursorstring | nullrequired
400

Malformed request.

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope · line not delegated.

Create a line

post/v1/tenants

Creates 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

NameTypeRequiredDescription
Idempotency-Keystring · headeroptional
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

FieldTypeRequiredDescription
namestringrequired
Display name of the line (the business).

≤ 200 chars

regionstringrequired
Service (telephony) region.

Values: kr · ca

externalIdstringrequired
Your identifier for the line (the duplicate-creation guard). 1–128 printable ASCII characters, no whitespace.

≤ 128 chars

agentobjectoptional
Agent settings. PUT is a partial patch that updates only the fields sent.
agent.personastringoptional
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.greetingstringoptional

≤ 1000 chars

agent.tonestring[]optional

≤ 20 items · each ≤ 60 chars

agent.businessHoursobject | nulloptional
{mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}.
agent.transferobject | nulloptional
{type: take_message|standard_response|transfer_human, message}.
agent.summaryRecipientsobject[]optional

≤ 20 items

agent.summaryRecipients[].emailstringrequired
agent.summaryRecipients[].keywordsstring[]optional

≤ 20 items · each ≤ 60 chars

Responses

201

The created line. No number field.

The create response. No number field (the number is connected separately).
FieldTypeRequiredDescription
tenantIdstringrequired
namestringrequired
regionstring | nullrequired

Values: kr · ca

statusstringrequired

Values: active · terminated

externalIdstring | nullrequired
createdAtstring | nullrequired

date-time

400

Malformed request.

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

402

Line quota exceeded (code: TENANT_QUOTA_EXCEEDED).

403

Partner inactive · missing scope · line not delegated.

409

code: 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

get/v1/tenants/{customerId}

Includes the number (null before one is connected), integration status and a plan summary.

Parameters

NameTypeRequiredDescription
customerIdstring · pathrequired
Line identifier. 403 if the line is not delegated to this partner (existence is not revealed).

Responses

200

Line detail.

FieldTypeRequiredDescription
tenantIdstringrequired
namestringrequired
regionstring | nullrequired

Values: kr · ca

statusstringrequired

Values: active · terminated

externalIdstring | nullrequired
createdAtstring | nullrequired

date-time

numberstring | nullrequired
The number currently being served (null if none).
integrationsobjectrequired
Store integration status per provider.
integrations.cafe24objectoptional
integrations.cafe24.connectedbooleanoptional
integrations.nextengineobjectoptional
integrations.nextengine.connectedbooleanoptional
planobject | nullrequired
plan.tierstring | nulloptional
plan.statusstring | nulloptional
401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope · line not delegated.

Terminate a line

delete/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

NameTypeRequiredDescription
customerIdstring · pathrequired
Line identifier. 403 if the line is not delegated to this partner (existence is not revealed).

Request body(optional)

FieldTypeRequiredDescription
reasonstringoptional

≤ 500 chars

purgebooleanoptional

default false

Responses

200

Termination complete.

FieldTypeRequiredDescription
statusstringrequired

Values: terminated

numberReclaimedbooleanrequired
terminatedAtstringrequired

date-time

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope · line not delegated.

409

A 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.

502

Number release failed — termination held (code: CARRIER_RELEASE_FAILED).

Agent settings

Agent settings for a line (config scope).

Read agent settings

get/v1/tenants/{customerId}/agent

Parameters

NameTypeRequiredDescription
customerIdstring · pathrequired
Line identifier. 403 if the line is not delegated to this partner (existence is not revealed).

Responses

200

The current agent settings.

Agent settings. PUT is a partial patch that updates only the fields sent.
FieldTypeRequiredDescription
personastringoptional
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

greetingstringoptional

≤ 1000 chars

tonestring[]optional

≤ 20 items · each ≤ 60 chars

businessHoursobject | nulloptional
{mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}.
transferobject | nulloptional
{type: take_message|standard_response|transfer_human, message}.
summaryRecipientsobject[]optional

≤ 20 items

summaryRecipients[].emailstringrequired
summaryRecipients[].keywordsstring[]optional

≤ 20 items · each ≤ 60 chars

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope · line not delegated.

Update agent settings (partial)

put/v1/tenants/{customerId}/agent

A partial patch that updates only the fields sent. It can take up to 5 minutes for a change to reach live calls.

Parameters

NameTypeRequiredDescription
customerIdstring · pathrequired
Line identifier. 403 if the line is not delegated to this partner (existence is not revealed).

Request body

Agent settings. PUT is a partial patch that updates only the fields sent.
FieldTypeRequiredDescription
personastringoptional
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

greetingstringoptional

≤ 1000 chars

tonestring[]optional

≤ 20 items · each ≤ 60 chars

businessHoursobject | nulloptional
{mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}.
transferobject | nulloptional
{type: take_message|standard_response|transfer_human, message}.
summaryRecipientsobject[]optional

≤ 20 items

summaryRecipients[].emailstringrequired
summaryRecipients[].keywordsstring[]optional

≤ 20 items · each ≤ 60 chars

Responses

200

The full settings after the update.

Agent settings. PUT is a partial patch that updates only the fields sent.
FieldTypeRequiredDescription
personastringoptional
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

greetingstringoptional

≤ 1000 chars

tonestring[]optional

≤ 20 items · each ≤ 60 chars

businessHoursobject | nulloptional
{mode: "24/7"|"custom", timezone(IANA), schedule{mon..sun:{enabled,open,close}}}.
transferobject | nulloptional
{type: take_message|standard_response|transfer_human, message}.
summaryRecipientsobject[]optional

≤ 20 items

summaryRecipients[].emailstringrequired
summaryRecipients[].keywordsstring[]optional

≤ 20 items · each ≤ 60 chars

400

Malformed request.

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope · line not delegated.

409

The 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

get/v1/tenants/{customerId}/calls

Call 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

NameTypeRequiredDescription
customerIdstring · pathrequired
Line identifier. 403 if the line is not delegated to this partner (existence is not revealed).
limitinteger · queryoptional
Page size (1–200).

1–200 · default 50

cursorstring · queryoptional
nextCursor from the previous response. A tampered or damaged value answers 400 (INVALID_CURSOR).
sinceinteger · queryoptional
Epoch milliseconds. Returns only calls whose summary was stored at or after this time — the same basis as startedAt.

≥ 0

Responses

200

A page of call summaries.

FieldTypeRequiredDescription
callsobject[]required
calls[].callIdstringrequired
Call (session) identifier. The same key as the webhook's callId.
calls[].startedAtstring | nullrequired
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[].titlestring | nulloptional
One-line title.
calls[].summarystring | nullrequired
The call summary.
calls[].durationSecsinteger | nulloptional
Call length in seconds.
calls[].callTypestring | nulloptional

Values: phone · web

calls[].callerNumberstring | nulloptional
Caller's number — masked (only the last four digits shown).
calls[].transferredbooleanoptional
calls[].transferTostring | nulloptional
calls[].resolutionstring | nulloptional

Values: Resolved · Booked · Escalated

calls[].sentimentstring | nulloptional

Values: positive · neutral · negative

calls[].topicsstring[]optional
nextCursorstring | nullrequired
Cursor for the next page. null on the last page.
400

Malformed request.

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope · line not delegated.

Webhooks

Push delivery of call completions (webhooks scope). One endpoint per partner.

Read the current webhook configuration

get/v1/webhooks

Returns the current configuration. Only the last four characters of the signing secret are included.

Responses

200

The current webhook configuration.

FieldTypeRequiredDescription
urlstringrequired
eventsstring[]required

Values: call.completed

signingSecretHintstringrequired
The last four characters of the signing secret (for identification — cannot sign).
createdAtstring | nulloptional

date-time

updatedAtstring | nulloptional

date-time

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope.

404

No webhook registered (code: WEBHOOK_NOT_CONFIGURED).

Register or replace the webhook endpoint

put/v1/webhooks

Registers (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

FieldTypeRequiredDescription
urlstringrequired
The https delivery URL. No credentials; no private or loopback hosts.

≤ 2048 chars

eventsstring[]optional
Events to subscribe to. Omit to subscribe to every supported event.

Values: call.completed

≥ 1 items

Responses

200

The registered configuration plus the full signing secret (this response only).

FieldTypeRequiredDescription
urlstringrequired
eventsstring[]required

Values: call.completed

signingSecretstringrequired
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.
createdAtstringoptional

date-time

updatedAtstringoptional

date-time

400

Malformed request.

401

Authentication failed (missing key · format/hash mismatch · revoked — reason not disclosed).

403

Partner inactive · missing scope.

422

URL format or host violation (WEBHOOK_URL_INVALID) · unsupported event (UNKNOWN_EVENT).

Call completed event delivery

postcall.completed → to your registered webhook URL

When 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):

  1. Parse the header: t={unix seconds},v1={hex HMAC}.
  2. Drop the whsec_ prefix from the secret and hex-decode it to get the raw key.
  3. Sign {t}.{raw request body bytes} with HMAC-SHA256 and compare with v1 in constant time.
  4. Reject as a replay if t is more than 5 minutes away from the current time.

Parameters

NameTypeRequiredDescription
X-LiveSpeech-Eventstring · headerrequired
Event type.

Values: call.completed

X-LiveSpeech-Deliverystring · headerrequired
Delivery identifier (= callId). The same value on retries.
X-LiveSpeech-Signaturestring · headerrequired
t={unix seconds},v1={hex HMAC-SHA256} — see the verification steps above.

Request body

The 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.
FieldTypeRequiredDescription
eventstringrequired

Values: call.completed

tenantIdstringrequired
The line the call belongs to — your routing key.
callIdstringrequired
Call (session) identifier. The same as callId in GET /calls. The de-duplication key.
occurredAtstringrequired
When the call ended (summary finalized).

date-time

summarystringrequired
The call summary.
resolutionstring | nullrequired

Values: Resolved · Booked · Escalated

recordingAvailablebooleanrequired
Whether a recording is expected to exist (true for phone calls). Recordings are not provided through the API.

Responses

2XX

Received (the body is ignored). 5xx · 408 · 429 · no response are retried; any other 4xx is not.