Developers · API
v1Quickstart
From receiving your key to creating a first line and reading its call results takes about ten minutes. Follow the steps in order.
1. Get a key
LiveSpeech issues your API key when your partner account is set up. It is a string that starts with ls_partner_ and is shown only once — put it in your server's secret store as soon as you receive it. A lost key cannot be shown again; ask support@livespeech.ai for a new one.
The examples below read the key and the base URL from environment variables.
export LS_BASE_URL="https://console-api.livespeech.ai"
export LS_PARTNER_KEY="ls_partner_0123abcd..." # the key you received
2. Check that the key works
GET /v1/whoami returns the key's identity and scopes without touching any line. Use it as the first call to verify your plumbing. Every field is in the API reference.
curl -s "$LS_BASE_URL/v1/whoami" \
-H "Authorization: Bearer $LS_PARTNER_KEY"const BASE_URL = process.env.LS_BASE_URL;
const API_KEY = process.env.LS_PARTNER_KEY;
const res = await fetch(`${BASE_URL}/v1/whoami`, {
headers: { Authorization: `Bearer ${API_KEY}` },
});
console.log(res.status, await res.json());import os, requests
BASE_URL = os.environ["LS_BASE_URL"]
API_KEY = os.environ["LS_PARTNER_KEY"]
res = requests.get(
f"{BASE_URL}/v1/whoami",
headers={"Authorization": f"Bearer {API_KEY}"},
)
print(res.status_code, res.json()){
"partnerId": "ptn_0123abcd4567ef89",
"name": "Example Partner Inc.",
"scopes": ["tenants", "config", "calls", "webhooks"],
"keyPrefix": "ls_partner_0123abcd4567"
}
scopes lists what this key can do. If something you need is missing, email support@livespeech.ai.
3. Create a line
One customer is one line. Put your own identifier for the customer in externalId, and you can match lines to customers later without a mapping table.
RESPONSE=$(curl -s -X POST "$LS_BASE_URL/v1/tenants" \
-H "Authorization: Bearer $LS_PARTNER_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: create-mall-00123-1" \
-d '{
"name": "Example Mall",
"region": "kr",
"externalId": "mall_00123"
}')
echo "$RESPONSE"
# Keep the tenantId from the response for the next steps.
TENANT_ID=$(printf '%s' "$RESPONSE" \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["tenantId"])')const BASE_URL = process.env.LS_BASE_URL;
const API_KEY = process.env.LS_PARTNER_KEY;
const res = await fetch(`${BASE_URL}/v1/tenants`, {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'create-mall-00123-1',
},
body: JSON.stringify({
name: 'Example Mall',
region: 'kr',
externalId: 'mall_00123',
}),
});
const tenant = await res.json();
console.log(res.status, tenant);
// Keep the tenantId from the response for the next steps.
const tenantId = tenant.tenantId;import os, requests
BASE_URL = os.environ["LS_BASE_URL"]
API_KEY = os.environ["LS_PARTNER_KEY"]
res = requests.post(
f"{BASE_URL}/v1/tenants",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
"Idempotency-Key": "create-mall-00123-1",
},
json={"name": "Example Mall", "region": "kr", "externalId": "mall_00123"},
)
tenant = res.json()
print(res.status_code, tenant)
# Keep the tenantId from the response for the next steps.
tenant_id = tenant["tenantId"]{
"tenantId": "8f2c1d40-5b7a-4c31-9e08-1a2b3c4d5e6f",
"name": "Example Mall",
"region": "kr",
"status": "active",
"externalId": "mall_00123",
"createdAt": "2026-09-09T04:15:22.140Z"
}
The tenantId in the response goes into every line path from here on — keep it in a variable as the examples do. Every request and response field is in the API reference.
4. Configure the agent
Decide how the line speaks and what it says. persona is free text describing how to treat callers; greeting is the first thing it says when it picks up.
curl -s -X PUT "$LS_BASE_URL/v1/tenants/$TENANT_ID/agent" \
-H "Authorization: Bearer $LS_PARTNER_KEY" \
-H "Content-Type: application/json" \
-d '{
"persona": "You are the customer service agent for Example Mall. Keep answers short and polite. If you are not sure about something, say you will check and call back.",
"greeting": "Hello, this is Example Mall customer service. How can I help you?",
"summaryRecipients": [{ "email": "cs@example.com", "keywords": ["refund", "exchange"] }]
}'const BASE_URL = process.env.LS_BASE_URL;
const API_KEY = process.env.LS_PARTNER_KEY;
const res = await fetch(
`${BASE_URL}/v1/tenants/${tenantId}/agent`,
{
method: 'PUT',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
persona:
'You are the customer service agent for Example Mall. Keep answers short and polite. If you are not sure about something, say you will check and call back.',
greeting: 'Hello, this is Example Mall customer service. How can I help you?',
summaryRecipients: [{ email: 'cs@example.com', keywords: ['refund', 'exchange'] }],
}),
},
);
console.log(res.status, await res.json());import os, requests
BASE_URL = os.environ["LS_BASE_URL"]
API_KEY = os.environ["LS_PARTNER_KEY"]
res = requests.put(
f"{BASE_URL}/v1/tenants/{tenant_id}/agent",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={
"persona": "You are the customer service agent for Example Mall. Keep answers short and polite. If you are not sure about something, say you will check and call back.",
"greeting": "Hello, this is Example Mall customer service. How can I help you?",
"summaryRecipients": [{"email": "cs@example.com", "keywords": ["refund", "exchange"]}],
},
)
print(res.status_code, res.json()){
"persona": "You are handling a live phone call.\n\nYou are the customer service agent for Example Mall. Keep answers short and polite. If you are not sure about something, say you will check and call back.",
"greeting": "Hello, this is Example Mall customer service. How can I help you?",
"tone": [],
"businessHours": null,
"transfer": null,
"summaryRecipients": [{ "email": "cs@example.com", "keywords": ["refund", "exchange"] }]
}
The response's persona starts with a sentence saying this is a live phone call. It is added automatically — you did not send it — and sending the value back as is does not duplicate it. The remaining settings are in Agent settings; every field is in the API reference.
5. Connect a number
Once the line exists, email support@livespeech.ai with its tenantId and the region to use, and we connect the number. When it is connected, number in the GET /v1/tenants/{customerId} response shows it.
6. Make a test call and read the result
Call the connected number, talk for a moment, and hang up. Once the call ends and its summary is stored, it appears in the list.
curl -s "$LS_BASE_URL/v1/tenants/$TENANT_ID/calls?limit=5" \
-H "Authorization: Bearer $LS_PARTNER_KEY"const BASE_URL = process.env.LS_BASE_URL;
const API_KEY = process.env.LS_PARTNER_KEY;
const res = await fetch(
`${BASE_URL}/v1/tenants/${tenantId}/calls?limit=5`,
{ headers: { Authorization: `Bearer ${API_KEY}` } },
);
console.log(res.status, await res.json());import os, requests
BASE_URL = os.environ["LS_BASE_URL"]
API_KEY = os.environ["LS_PARTNER_KEY"]
res = requests.get(
f"{BASE_URL}/v1/tenants/{tenant_id}/calls",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"limit": 5},
)
print(res.status_code, res.json()){
"calls": [
{
"callId": "6f1e0c2a-4b7d-4c1e-9a52-3f8d2f10ab34",
"startedAt": "2026-09-09T04:31:08.000Z",
"title": "Delivery status inquiry",
"summary": "The caller asked about the delivery status of an order and was told it ships today.",
"durationSecs": 74,
"callType": "phone",
"callerNumber": "*******5678",
"transferred": false,
"transferTo": null,
"resolution": "Resolved",
"sentiment": "positive",
"topics": ["delivery"]
}
],
"nextCursor": null
}
A call appears in the list after its summary is stored. If you query right after hanging up it may not be there yet — try again shortly.
startedAt is the time the summary was stored — not when the call started. Use durationSecs for the call length. Every field is in the API reference.
Next
- Want each call pushed to you without polling → Webhooks
- Running many customers → Multi-store
- How to handle failed responses → Errors & limits