CrystalQore
DevelopersRecipes

Pull call records

Export CrystalQore call detail records on a schedule for BI or compliance.

Pull call records

A nightly job can page through GET /api/v1/cdr and write rows to your warehouse.

Windowing

  • Send startDate and endDate (ISO dates).
  • Set tz to the IANA zone your reports use so day boundaries match the wall clock.
  • Retention still applies: CrystalQore will not return records older than the plan cutoff, even if startDate is older.
async function fetchCdrPage({ startDate, endDate, tz, offset = 0 }) {
  const url = new URL("https://app.crystalqore.com/api/v1/cdr");
  url.searchParams.set("startDate", startDate);
  url.searchParams.set("endDate", endDate);
  url.searchParams.set("tz", tz);
  url.searchParams.set("limit", "100");
  url.searchParams.set("offset", String(offset));
 
  const res = await fetch(url, {
    headers: {
      "X-API-Key": process.env.CRYSTALQORE_API_KEY,
      "X-Tenant-Id": process.env.CRYSTALQORE_TENANT_ID,
    },
  });
  const body = await res.json();
  if (!body.success) {
    throw new Error(`${body.error.code}: ${body.error.message}`);
  }
  return body;
}
 
export async function exportDay(day, tz = "America/New_York") {
  const rows = [];
  let offset = 0;
  for (;;) {
    const page = await fetchCdrPage({
      startDate: day,
      endDate: day,
      tz,
      offset,
    });
    rows.push(...page.data.records);
    if (!page.meta.pagination.hasMore) break;
    offset += page.meta.pagination.limit;
  }
  return rows;
}

Scoping

Omit X-User-Email for an organization-wide export (needs a key allowed on that tenant). Send the header to export one agent's calls.

direction can be inbound, outbound, internal, or all.

Use hasRecording as a flag only — this endpoint does not download media. Recordings live in the CrystalQore Recordings experience.

On this page