02 Get your data in /Integrations
Dialpad
Send call transcripts from Dialpad to Dimension Labs with the universal API.
- D DialpadTickets, chats, calls, reviews
- ⟳ Your jobPull new · map fields · every 15 min
- { } Universal APIPOST /track · /trackhistorical
- 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.
What you need
Section titled “What you need”- 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. Get API access in Dialpad
Section titled “1. Get API access in Dialpad”- Go to Admin Settings > My Company > Authentication > API Keys and select Add Key. Dialpad’s steps are in Manual API Key Generation.
- Name the key, set when it expires, and under Additional Scopes add
calls:list. Select Save. - 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.
2. Pull new calls
Section titled “2. Pull new calls”List calls, then get each call’s transcript:
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 -- Listonly returns calls that have already ended, most recent first by start time.started_afterandstarted_beforeare UTC milliseconds since the epoch.- Each response has a
cursor: send it back ascursorfor 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 withcontent,time,type, and eitheruser_id(a Dialpad user, your side) orcontact_id(the other party).typeistranscriptfor spoken lines;moment,custom_moment,real_time_momentandai_questionlines are Dialpad AI tags, not speech.
3. Map the fields
Section titled “3. Map the fields”| Dimension Labs | Dialpad | Notes |
|---|---|---|
text | lines[].content | Only lines with type transcript. |
userId | call contact.id | Dialpad’s id for the contact. If the call has none, the code uses the sessionId. |
incoming | lines[].user_id | false when the line has a user_id (a Dialpad user: an agent, or a bot). true otherwise. |
sessionId | call_id | One call is one conversation in Dimension Labs. |
conversationId | call_id | Same value as sessionId. |
dimensionlabs_timestamp | lines[].time | The time has no zone; the code reads it as UTC. Lines closer than a second apart are spaced to 1,000 ms. |
platformJson | direction, group_id, master_call_id, labels, csat_score, moment names | Leave 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.
4. Send it
Section titled “4. Send it”// 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;}5. Run it
Section titled “5. Run it”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-01sends 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.
Dialpad reference
Section titled “Dialpad reference”Checked against Dialpad’s documentation on 2026-10-26.