Skip to content
Start free

Developers · API

v1

Fetch call results

A call appears in the list once it has ended and its summary is stored. Newest first.

GET /v1/tenants/{customerId}/callslimit sets the page size (1–200, default 50); pass the previous response's nextCursor as cursor to read the next page. since returns only calls at or after the time you pass (an integer of epoch milliseconds).

Each entry carries the call identifier (the same value as the webhook's callId), a time, a one-line title, the summary, the call length, the caller's number, whether the call was handed over, the outcome, the caller's sentiment and topics. Every field and its possible values are in the API reference.

The caller's number (callerNumber) shows only the last four digits (*******5678). Transcripts and recordings are not provided, and calls the operator deleted in the console do not appear.

List or webhook — which to use

MethodUse it when
The list (GET …/calls, this page)Showing calls on a screen, or filling a gap you missed
Webhooks (call.completed)You need to act the moment a call ends

Read recent calls

TENANT_ID="<customerId from the create response>"

curl -s "$LS_BASE_URL/v1/tenants/$TENANT_ID/calls?limit=20" \
  -H "Authorization: Bearer $LS_PARTNER_KEY"
const BASE_URL = process.env.LS_BASE_URL;
const API_KEY = process.env.LS_PARTNER_KEY;
const tenantId = '<customerId from the create response>';

const url = new URL(`${BASE_URL}/v1/tenants/${tenantId}/calls`);
url.searchParams.set('limit', '20');
const page = await (
  await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } })
).json();
for (const call of page.calls) {
  console.log(call.startedAt, call.title, call.resolution);
}
import os, requests

BASE_URL = os.environ["LS_BASE_URL"]
API_KEY = os.environ["LS_PARTNER_KEY"]
tenant_id = "<customerId from the create response>"

page = requests.get(
    f"{BASE_URL}/v1/tenants/{tenant_id}/calls",
    headers={"Authorization": f"Bearer {API_KEY}"},
    params={"limit": 20},
).json()
for call in page["calls"]:
    print(call["startedAt"], call["title"], call["resolution"])
{
  "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": "eyJvZmZzZXQiOjIwfQ"
}

Poll for new calls only

Store the startedAt of the last call you processed and pass it as since next time to get only what came after. since includes the exact time, so a call on the boundary can come back once more — de-duplicate by callId before storing.

TENANT_ID="<customerId from the create response>"

# Only calls whose summary was stored after 2026-09-09T00:00:00Z
curl -s "$LS_BASE_URL/v1/tenants/$TENANT_ID/calls?since=1788912000000&limit=200" \
  -H "Authorization: Bearer $LS_PARTNER_KEY"
const BASE_URL = process.env.LS_BASE_URL;
const API_KEY = process.env.LS_PARTNER_KEY;

async function fetchCallsSince(tenantId, sinceMs) {
  const calls = [];
  let cursor = null;
  do {
    const url = new URL(`${BASE_URL}/v1/tenants/${tenantId}/calls`);
    url.searchParams.set('limit', '200');
    url.searchParams.set('since', String(sinceMs));
    if (cursor) url.searchParams.set('cursor', cursor);
    const page = await (
      await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } })
    ).json();
    calls.push(...page.calls);
    cursor = page.nextCursor;
  } while (cursor);
  return calls;
}
import os, requests

BASE_URL = os.environ["LS_BASE_URL"]
API_KEY = os.environ["LS_PARTNER_KEY"]

def fetch_calls_since(tenant_id, since_ms):
    calls, cursor = [], None
    while True:
        params = {"limit": 200, "since": since_ms}
        if cursor:
            params["cursor"] = cursor
        page = requests.get(
            f"{BASE_URL}/v1/tenants/{tenant_id}/calls",
            headers={"Authorization": f"Bearer {API_KEY}"},
            params=params,
        ).json()
        calls += page["calls"]
        cursor = page.get("nextCursor")
        if not cursor:
            return calls

An invalid or expired cursor answers 400 INVALID_CURSOR — start again without a cursor. A non-integer since also answers 400. All failure responses are in Errors & limits.

To be told the moment a call ends instead of polling, see Webhooks.