telyzer

API & webhooks

Read calls and reports with read-only API keys, and receive signed webhook events.

Documentation menu

API keys and webhooks are managed under API & webhooks in the portal. They are available on the Enterprise plan and during your trial. The API serves the same data and filters as the portal; it is read-only.

API keys

Choose New key, give it a name and an expiry, and pick its access:

ScopeAllows
calls.readCall records, with external numbers masked.
calls.unmaskShow full phone numbers.
reports.readReports, exports and the wallboard.

The key starts with tzk_ and is shown once, so copy it straight away. Telyzer stores only a hash of it. Revoke stops a key immediately.

Authentication and limits

Send the key as a Bearer token. The base address is https://app.telyzer.com/api/v1.

curl -H "Authorization: Bearer $TELYZER_KEY" \
  "https://app.telyzer.com/api/v1/calls?from=2026-10-01&to=2026-10-07&limit=200"
  • Up to 300 requests a minute per key. Above that the API answers 429.
  • 401: missing or invalid key. 403: the key lacks the scope the request needs.
  • Times ending in Local are wall-clock times at the site; times ending in Utc are UTC.

Endpoints

RequestReturnsScope
GET /api/v1/callsCalls, one row per conversation, newest first.calls.read
GET /api/v1/calls/{id}One call with every transfer segment and the raw PBX line.calls.read
GET /api/v1/reportsAvailable reports.reports.read
GET /api/v1/reports/{key}A report as JSON: columns, rows and the rule that produced them.reports.read
GET /api/v1/reports/{key}/exportA report file: format=csv|xlsx|pdf, lang=en|ar.reports.read
GET /api/v1/wallboardToday so far: totals, missed calls not yet called back, latest calls.reports.read

Report keys: summary, daily, hourly, extensions, unanswered, top-numbers, destinations, sites, costs, after-hours, service-level, callers, trunks, account-codes, data-quality, calls, plus your saved custom reports.

Filters

Calls and reports accept from and to (YYYY-MM-DD, at most 366 days), siteId, departmentId, direction, outcome, category, extension, number, afterHours and minTalk (seconds).

Run a report
curl -H "Authorization: Bearer $TELYZER_KEY" \
  "https://app.telyzer.com/api/v1/reports/extensions?from=2026-10-01&to=2026-10-31"
Download a report as CSV
curl -H "Authorization: Bearer $TELYZER_KEY" -o daily.csv \
  "https://app.telyzer.com/api/v1/reports/daily/export?format=csv&lang=en&from=2026-10-01&to=2026-10-31"

Pagination

/calls returns a page of up to limit calls (1–200, default 50) and a nextCursor. Pass it back as cursor for the next page; it is null on the last page.

// Node.js 18+: read every call in a date range, 200 per page
let cursor = null;
do {
  const url = new URL("https://app.telyzer.com/api/v1/calls");
  url.searchParams.set("from", "2026-10-01");
  url.searchParams.set("to", "2026-10-31");
  url.searchParams.set("limit", "200");
  if (cursor) url.searchParams.set("cursor", cursor);
  const res = await fetch(url, { headers: { Authorization: "Bearer " + process.env.TELYZER_KEY } });
  if (res.status === 429) { await new Promise((r) => setTimeout(r, 1000)); continue; }
  const page = await res.json();
  for (const call of page.items) console.log(call.startLocal, call.direction, call.outcome);
  cursor = page.nextCursor; // null on the last page
} while (cursor);

The full contract is published as OpenAPI 3.1 at app.telyzer.com/api/v1/openapi.json.

Webhooks

Choose New webhook, enter your HTTPS endpoint URL and pick the events. Telyzer POSTs a signed JSON event when one happens:

EventSent when
alert.triggeredAn alert rule fired.
report.deliveredA scheduled report was emailed.
source.silentA phone system stopped sending records.
  • Send test sends a test event and shows your endpoint's answer; Delivery log shows recent attempts.
  • Failed deliveries are retried for about two days with growing delays. An endpoint is switched off after 20 failures in a row.
  • Events are delivered only to public internet addresses.

Verifying the signature

Each webhook has a signing secret, shown once when you create it and later under Signing secret. Every request carries X-Telyzer-Signature: t=<unix time>,v1=<hex>, where v1 is the HMAC-SHA256 of t, a dot, and the raw request body, keyed with the secret. Compute it on the raw body before parsing JSON, compare in constant time, and reject old timestamps.

// Node.js: verify X-Telyzer-Signature ("t=<unix>,v1=<hex>") on the raw request body
import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const expected = crypto.createHmac("sha256", secret).update(parts.t + "." + rawBody).digest("hex");
  const a = Buffer.from(parts.v1 ?? "", "hex"), b = Buffer.from(expected, "hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // reject replays older than 5 minutes
  return a.length === b.length && crypto.timingSafeEqual(a, b) && fresh;
}
# Python: the same check
import hmac, hashlib, time

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    signed = parts["t"].encode() + b"." + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    fresh = abs(time.time() - int(parts["t"])) < 300
    return hmac.compare_digest(expected, parts.get("v1", "")) and fresh