Skip to content

02 Get your data in /Integrations

Dialpad

Send call transcripts from Dialpad to Dimension Labs with the universal API.

  1. D DialpadTickets, chats, calls, reviews
  2. ⟳ Your jobPull new · map fields · every 15 min
  3. { } Universal APIPOST /track · /trackhistorical
  4. Dimension LabsRead in full · enriched daily

This brings in Dialpad call transcripts, line by line, as Dialpad AI transcribed them. One call becomes one conversation in Dimension Labs. You run it on your side: a small script pulls from the Dialpad API and posts each message to the universal API.

  • Dialpad AI transcripts on the calls you want. The API returns the Dialpad AI transcript of a call; a call Dialpad AI didn’t transcribe has none.
  • A Dialpad Company Admin to create an API key. Only Company Admins can create one.
  • A Dimension Labs API key for a new Universal API source. See Your API key.
  1. Go to Admin Settings > My Company > Authentication > API Keys and select Add Key. Dialpad’s steps are in Manual API Key Generation.
  2. Name the key, set when it expires, and under Additional Scopes add calls:list. Select Save.
  3. Send the key as Authorization: Bearer YOUR_API_KEY.

A company-level key lists every call in the company. Dialpad warns that API keys are more powerful than passwords, so keep it in your secret store. OAuth is only for apps used across several Dialpad companies; you don’t need it for your own.

List calls, then get each call’s transcript:

Terminal window
curl -H "Authorization: Bearer $DIALPAD_API_KEY" \
"https://dialpad.com/api/v2/call?started_after=1761436800000"
curl -H "Authorization: Bearer $DIALPAD_API_KEY" \
"https://dialpad.com/api/v2/transcripts/CALL_ID"
  • Call -- List only returns calls that have already ended, most recent first by start time. started_after and started_before are UTC milliseconds since the epoch.
  • Each response has a cursor: send it back as cursor for the next page.
  • The list filters by start time, so the code looks back DIALPAD_LOOKBACK_HOURS (24 by default) before the cursor and keeps calls that ended since the last run (date_ended).
  • Calls tied to deleted users are anonymized and left out unless you add include_anonymized=true.
  • The transcript has lines[], each with content, time, type, and either user_id (a Dialpad user, your side) or contact_id (the other party). type is transcript for spoken lines; moment, custom_moment, real_time_moment and ai_question lines are Dialpad AI tags, not speech.
Dimension LabsDialpadNotes
textlines[].contentOnly lines with type transcript.
userIdcall contact.idDialpad’s id for the contact. If the call has none, the code uses the sessionId.
incominglines[].user_idfalse when the line has a user_id (a Dialpad user: an agent, or a bot). true otherwise.
sessionIdcall_idOne call is one conversation in Dimension Labs.
conversationIdcall_idSame value as sessionId.
dimensionlabs_timestamplines[].timeThe time has no zone; the code reads it as UTC. Lines closer than a second apart are spaced to 1,000 ms.
platformJsondirection, group_id, master_call_id, labels, csat_score, moment namesLeave out name, contact.name, contact.phone, contact.email, external_number and internal_number: they are names and phone numbers.

Personal data. Transcripts hold what people say: names, phone numbers, card and account numbers. Each line’s name is the speaker’s name or phone number, so the code never sends it. Redact the text before you send. See PII redaction.

// dialpad.mjs. Environment: DIALPAD_API_KEY (a company API key with the calls:list scope), DIALPAD_LOOKBACK_HOURS (default 24), DL_API_KEY.
import { sendToDimensionLabs, toMillis } from './dimensionlabs.mjs';
const HOUR = 60 * 60 * 1000;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const API = 'https://dialpad.com/api/v2';
const LOOKBACK = Number(process.env.DIALPAD_LOOKBACK_HOURS ?? 24) * HOUR;
// Retries rate limits (429) and server errors (5xx). Returns null on 404 (a call with no transcript).
async function get(url) {
for (let attempt = 0; ; attempt++) {
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.DIALPAD_API_KEY}` } });
if (res.ok) return res.json();
if (res.status === 404) return null;
if ((res.status !== 429 && res.status < 500) || attempt === 5) throw new Error(`Dialpad returned ${res.status}: ${await res.text()}`);
await sleep((Number(res.headers.get('retry-after')) || 2 ** attempt) * 1000);
}
}
// Sends every call that ended at or after `since` (Unix ms). Returns the new `since`.
export async function syncDialpad({ since, historical = false }) {
let newest = since;
let cursor;
do {
// Calls are listed by start time, so look back far enough to catch calls that started before `since`.
const q = new URLSearchParams({ started_after: String(since - LOOKBACK) });
if (cursor) q.set('cursor', cursor);
const page = await get(`${API}/call?${q}`);
for (const c of page?.items ?? []) {
const ended = toMillis(c.date_ended ?? c.date_started);
if (ended < since) continue;
const transcript = await get(`${API}/transcripts/${c.call_id}`);
const lines = transcript?.lines ?? [];
const moments = lines.filter((l) => l.type !== 'transcript').map((l) => l.content);
const sessionId = `dialpad-${c.call_id}`;
const userId = c.contact?.id ? `dialpad-${c.contact.id}` : sessionId;
let last = 0;
for (const l of lines) {
if (l.type !== 'transcript' || !l.content?.trim()) continue;
const ts = Math.max(toMillis(l.time), last + 1000); // keep lines at least a second apart
last = ts;
await sendToDimensionLabs({
text: l.content,
userId,
incoming: l.user_id == null, // lines from a Dialpad user are your side
sessionId,
conversationId: sessionId,
dimensionlabs_timestamp: ts,
platformJson: { direction: c.direction, groupId: c.group_id, masterCallId: c.master_call_id, labels: c.labels, csatScore: c.csat_score, moments },
}, { historical: historical || ts < Date.now() - HOUR });
}
newest = Math.max(newest, ended);
}
cursor = page?.items?.length ? page.cursor : null;
} while (cursor);
return newest;
}

Save the code as dialpad.mjs in a project set up as in Set up your project, and run it with the scheduled sync runner: import { syncDialpad as sync } from './dialpad.mjs';.

  • History first: node run.mjs 2025-01-01 sends every call since that date to /trackhistorical. Then start a backfill from the Backfill tab.
  • Then every 15 minutes: the scheduled job sends calls that ended since the last run to /track, and they are enriched automatically every day. Lines of a call longer than an hour go to /trackhistorical, and need a backfill.
  • Re-runs are safe: duplicates are removed automatically.
  • Rate limits: Dialpad allows 20 requests a second per company, and 1,200 a minute each for listing calls and getting transcripts. The code waits whenever Dialpad returns 429.

You can also upload a file and check it first with the file checker, then run a backfill.

Checked against Dialpad’s documentation on 2026-10-26.