02 Get your data in /Integrations
Gladly
Send Gladly conversation items to Dimension Labs with the universal API.
- G GladlyTickets, chats, calls, reviews
- ⟳ Your jobPull new · map fields · every 15 min
- { } Universal APIPOST /track · /trackhistorical
- Dimension LabsRead in full · enriched daily
This brings in the conversation items on your Gladly customer timelines: chat, email, SMS and other messages from customers, agents and Gladly’s AI, grouped by conversation. You run it on your side: a small script picks up Gladly’s export files and posts each message to the universal API.
Gladly works differently from the other support desks: its data arrives in export files, once a day by default, so most messages are more than an hour old when the file appears. Those go to /trackhistorical, and their Dimensions need a backfill after each export.
What you need
Section titled “What you need”- A Gladly administrator, to give a user the API User permission. Gladly recommends a dedicated user for API calls.
- An API token for that user, and the user’s email address.
- A Dimension Labs API key for a new Universal API source. See Your API key.
1. Get API access in Gladly
Section titled “1. Get API access in Gladly”- Open the menu in the top left corner and go to Settings > Users.
- Open the user’s profile, select the API User permission while keeping their Agent role, and click Save.
- Signed in as that user, open More settings, click API Tokens, then Create Token. You only see the token once.
- Authenticate with Basic auth: the user’s email as the username and the API token as the password (getting started, authentication).
2. Pull new conversation items
Section titled “2. Pull new conversation items”The Export API writes your conversations to files on a schedule. By default each organization has a daily export job. Gladly Support can change it to hourly, and hourly jobs are created roughly two hours after their period starts. Jobs and files are kept for 14 days.
- List jobs that completed since your cursor.
startAtfilters on the job’supdatedAtand can’t be more than 14 days ago:
curl -u "$GLADLY_EMAIL:$GLADLY_API_TOKEN" \ "https://YOUR_ORG.gladly.com/api/v1/export/jobs?status=COMPLETED&startAt=2026-10-13T00:00:00.000Z"- For each job, get the file
conversation_items.jsonl:GET /api/v1/export/jobs/{jobId}/files/conversation_items.jsonl. Each line is one conversation item.
For one conversation at a time, list items in a conversation, GET /api/v1/conversations/{conversationId}/items, returns its timeline. The Gladly-Limited-Data response header says when the conversation has more items than were returned.
Rate limits, per Gladly: 10 requests per second for each HTTP method, unless an API documents its own limit. Responses carry Ratelimit-Limit-Second and Ratelimit-Remaining-Second headers, and going over returns 429 (default rate limit, handling rate limit).
3. Map the fields
Section titled “3. Map the fields”| Dimension Labs | Gladly | Notes |
|---|---|---|
text | item content.content | Present on message items such as CHAT_MESSAGE and EMAIL. Skip items without it, such as CONVERSATION_STATUS_CHANGE, TOPIC_CHANGE and CONVERSATION_NOTE (an internal note, with its text in body). |
userId | item customerId | Gladly’s internal customer id, on every item in the conversation. |
incoming | item initiator.type | true when it is CUSTOMER. AGENT is a person on your team and SYSTEM is automation, such as Gladly’s AI. |
sessionId | item conversationId | Gladly ids have no colons. |
conversationId | item conversationId | Same value as sessionId. |
dimensionlabs_timestamp | item timestamp | Convert with toMillis. |
platformJson | item content.type, content.sessionId, initiator.type, id | content.type is the channel. To join to your own data, customers.jsonl in the same job maps each customer to your externalCustomerId. |
Personal data. customers.jsonl also holds customer emails and names: don’t send them. Message text can hold them too: redact it before you send. See PII redaction.
4. Send it
Section titled “4. Send it”// gladly.mjs. Environment: GLADLY_ORG, GLADLY_EMAIL, GLADLY_API_TOKEN, DL_API_KEY.import { sendToDimensionLabs, toMillis } from './dimensionlabs.mjs';
const HOUR = 60 * 60 * 1000;const DAY = 24 * HOUR;const sleep = (ms) => new Promise((r) => setTimeout(r, ms));const base = `https://${process.env.GLADLY_ORG}.gladly.com/api/v1/export/jobs`;const auth = 'Basic ' + Buffer.from(`${process.env.GLADLY_EMAIL}:${process.env.GLADLY_API_TOKEN}`).toString('base64');
// Retries Gladly's rate limits (429) and server errors (5xx), honoring Retry-After when it is sent.async function get(url) { for (let attempt = 0; ; attempt++) { const res = await fetch(url, { headers: { Authorization: auth } }); if (res.ok) return res; if ((res.status !== 429 && res.status < 500) || attempt === 5) throw new Error(`Gladly returned ${res.status}: ${await res.text()}`); await sleep((Number(res.headers.get('retry-after')) || 2 ** attempt) * 1000); }}
// Sends the items of every export job completed after `since` (Unix ms). Returns the new `since`.export async function syncGladly({ since, historical = false }) { const startAt = Math.max(since + 1, Date.now() - 14 * DAY + HOUR); // Gladly keeps jobs for 14 days const jobs = await (await get(`${base}?status=COMPLETED&startAt=${new Date(startAt).toISOString()}`)).json(); jobs.sort((a, b) => toMillis(a.updatedAt) - toMillis(b.updatedAt)); let newest = since; for (const job of jobs) { if (job.files?.includes('conversation_items.jsonl')) { const lines = (await (await get(`${base}/${job.id}/files/conversation_items.jsonl`)).text()).split('\n'); for (const line of lines) { if (!line.trim()) continue; const item = JSON.parse(line); const text = item.content?.content; if (typeof text !== 'string' || !text.trim()) continue; const ts = toMillis(item.timestamp); await sendToDimensionLabs({ text, userId: item.customerId, incoming: item.initiator?.type === 'CUSTOMER', sessionId: item.conversationId, conversationId: item.conversationId, dimensionlabs_timestamp: ts, platformJson: { channel: item.content.type, chat_session_id: item.content.sessionId, initiator_type: item.initiator?.type, item_id: item.id }, }, { historical: historical || ts < Date.now() - HOUR }); // most export items are older than an hour } } newest = Math.max(newest, toMillis(job.updatedAt)); } return newest;}5. Run it
Section titled “5. Run it”Save the code as gladly.mjs in a project set up as in Set up your project, and run it with the scheduled sync runner: import { syncGladly as sync } from './gladly.mjs';.
- Which endpoint: each item goes to
/trackif it is less than an hour old when the file is read, and to/trackhistoricalotherwise. With Gladly’s daily export, that is almost everything; even hourly jobs appear about two hours after their period starts. So plan on/trackhistorical. - Backfill after each export: start a backfill from the Backfill tab once the day’s job has been sent. A backfill typically shows up within the hour, depending on how much data is being enriched. Running the job once a day, after the export, keeps this to one backfill a day.
- History:
node run.mjs 2026-10-01sends the jobs of the last 14 days (Gladly keeps no more). For older history, ask Gladly Support for a one-time export (Gladly notes a fee may apply beyond six months), upload the file (check it with the file checker), then run a backfill. - Re-runs are safe: duplicates are removed automatically.
Gladly reference
Section titled “Gladly reference”- Getting started
- Authentication
- Default rate limit
- Conversation items
- Export
- List jobs
- Get file
- List items in a conversation
- Gladly developer documentation index
Checked against Gladly’s documentation on 2026-10-13.