# Gorgias

> Send Gorgias tickets and their messages to Dimension Labs with the universal API.

This brings in each Gorgias ticket as one conversation: the customer's messages and your agents' and rules' replies, across email, chat, SMS and social channels. You run it on your side: a small script pulls from the Gorgias REST API and posts each message to the [universal API](/api/tracker).

## What you need

- A Gorgias account owner or admin: they can see the API credentials and create API keys.
- Your Gorgias username (the email address on your account) and API key.
- A Dimension Labs API key for a new **Universal API** source. See [Your API key](/api/tracker#your-api-key).

## 1. Get API access in Gorgias

1. In your helpdesk, click the **Settings** icon in the bottom left corner.
2. Under **Account**, select **REST API**.
3. Under **API Access & Credentials**, copy the **Base API URL** (`https://{your-domain}.gorgias.com/api/`) and your **Username**.
4. Under **Password (API Key)**, click **Create API Key** if you don't have one, then copy it.
5. Authenticate with Basic auth: your username and the API key ([access your REST API credentials](https://docs.gorgias.com/en-US/rest-api-208286), [access tokens](https://developers.gorgias.com/docs/access-tokens-api-keys)).

The key acts as the user who holds it, with that user's permissions.

## 2. Pull new tickets

[List tickets](https://developers.gorgias.com/reference/list-tickets) ordered by when they last changed, newest first, and stop once you reach tickets older than your cursor:

```bash
curl -u "$GORGIAS_USERNAME:$GORGIAS_API_KEY" \
  "https://YOUR_DOMAIN.gorgias.com/api/tickets?order_by=updated_datetime:desc&limit=100"
```

`limit` goes up to 100. Pass `meta.next_cursor` from the response as `cursor` to get the next page ([pagination](https://developers.gorgias.com/reference/pagination)).

For each ticket, [list messages](https://developers.gorgias.com/reference/list-messages) with `GET /api/messages?ticket_id=ID&order_by=created_datetime:asc&limit=100`. The older "list messages of a ticket" endpoint is deprecated.

From September 8, 2026, Gorgias archives the original `body_text` and `body_html` of email messages 30 days after they are sent or received, and sets those fields to `null` when a stripped version exists. Use `stripped_text`, which isn't affected, and fall back to `body_text` ([email message data retention](https://developers.gorgias.com/changelog/new-email-message-data-retention-policy)).

Rate limits, per Gorgias: API key integrations can make 40 requests in a 20 second window (Enterprise accounts: a 10 second window). Going over returns `429` with a `Retry-after` header ([rate limits](https://developers.gorgias.com/reference/limitations)).

## 3. Map the fields

| Dimension Labs | Gorgias | Notes |
|---|---|---|
| `text` | message `stripped_text`, else `body_text` | `stripped_text` drops signatures and quoted replies. Skip messages where `public` is `false`: those are internal notes. |
| `userId` | ticket `customer.id` | Gorgias's internal customer id, on both their messages and your replies. Fall back to the `sessionId`. |
| `incoming` | message `from_agent` | `from_agent` is `true` when your company sent the message, so `incoming` is its opposite. |
| `sessionId` | ticket `id` | Prefix it, for example `gorgias-123`. |
| `conversationId` | ticket `id` | Same value as `sessionId`. |
| `dimensionlabs_timestamp` | message `created_datetime` | Convert with `toMillis`. Gorgias's example values have no time zone offset; `toMillis` reads those as UTC. |
| `platformJson` | ticket `channel`, `status`, `tags`, `language`; message `channel`, `via` | To join to order or account data, use `customer.external_id` (your own customer id) if you set it. |

**Personal data.** Don't send `customer.email` or the customer's name. Messages can hold addresses, phone numbers and order details: redact them before you send. See [PII redaction](/data/pii-redaction).

## 4. Send it

```js
// gorgias.mjs. Environment: GORGIAS_DOMAIN, GORGIAS_USERNAME, GORGIAS_API_KEY, DL_API_KEY.


const HOUR = 60 * 60 * 1000;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const base = `https://${process.env.GORGIAS_DOMAIN}.gorgias.com/api`;
const auth = 'Basic ' + Buffer.from(`${process.env.GORGIAS_USERNAME}:${process.env.GORGIAS_API_KEY}`).toString('base64');

// Retries Gorgias's rate limits (429) and server errors (5xx), honoring Retry-After.
async function get(url) {
  for (let attempt = 0; ; attempt++) {
    const res = await fetch(url, { headers: { Authorization: auth } });
    if (res.ok) return res.json();
    if ((res.status !== 429 && res.status < 500) || attempt === 5) throw new Error(`Gorgias returned ${res.status}: ${await res.text()}`);
    await sleep((Number(res.headers.get('retry-after')) || 2 ** attempt) * 1000);
  }
}

// Reads every page, or stops after the first page where stop(item) is true.
async function list(path, stop = () => false) {
  const items = [];
  for (let cursor = ''; cursor !== null; ) {
    const page = await get(`${base}${path}&limit=100${cursor ? `&cursor=${encodeURIComponent(cursor)}` : ''}`);
    items.push(...page.data);
    cursor = page.data.some(stop) ? null : page.meta?.next_cursor ?? null;
  }
  return items;
}

// Sends every public message written at or after `since` (Unix ms). Returns the new `since`.
export async function syncGorgias({ since, historical = false }) {
  let newest = since;
  const changed = (t) => toMillis(t.updated_datetime) >= since;
  const tickets = await list('/tickets?order_by=updated_datetime:desc', (t) => !changed(t));
  for (const t of tickets.filter(changed)) {
    for (const m of await list(`/messages?ticket_id=${t.id}&order_by=created_datetime:asc`)) {
      const ts = toMillis(m.created_datetime);
      const text = m.stripped_text ?? m.body_text;
      if (!m.public || ts < since || !text?.trim()) continue;
      await sendToDimensionLabs({
        text,
        userId: t.customer?.id ? String(t.customer.id) : `gorgias-${t.id}`,
        incoming: !m.from_agent,
        sessionId: `gorgias-${t.id}`,
        conversationId: `gorgias-${t.id}`,
        dimensionlabs_timestamp: ts,
        platformJson: { channel: m.channel, via: m.via, status: t.status, tags: t.tags, language: t.language, customer_external_id: t.customer?.external_id },
      }, { historical: historical || ts < Date.now() - HOUR });
      newest = Math.max(newest, ts);
    }
  }
  return newest;
}
```

## 5. Run it

Save the code as `gorgias.mjs` in a project set up as in [Set up your project](/api/tracker#set-up-your-project), and run it with the [scheduled sync](/api/scheduled-sync) runner: `import { syncGorgias as sync } from './gorgias.mjs';`.

- **History first:** `node run.mjs 2025-01-01` sends every message since that date to `/trackhistorical`. Then start a [backfill](/dimensions/backfill) from the **Backfill** tab.
- **Then every 15 minutes:** the scheduled job sends new messages to `/track`, and they are enriched automatically every day. A message that is more than an hour old when the job sees it goes to `/trackhistorical`, and needs a backfill.
- **Re-runs are safe:** duplicates are removed automatically.

Gorgias allows 40 requests in 20 seconds, and each ticket costs at least one call, so a history load takes a while; the code waits whenever Gorgias asks it to. You can also [upload a file](/data/upload-a-file) of exported tickets (check it with the [file checker](/data/check-a-file)), then run a backfill.

## Gorgias reference

- [Access your Gorgias REST API credentials](https://docs.gorgias.com/en-US/rest-api-208286)
- [Access tokens (API keys)](https://developers.gorgias.com/docs/access-tokens-api-keys)
- [Authentication](https://developers.gorgias.com/reference/authentication)
- [List tickets](https://developers.gorgias.com/reference/list-tickets)
- [The Ticket object](https://developers.gorgias.com/reference/the-ticket-object)
- [List messages](https://developers.gorgias.com/reference/list-messages)
- [The TicketMessage object](https://developers.gorgias.com/reference/the-ticketmessage-object)
- [Pagination](https://developers.gorgias.com/reference/pagination)
- [Rate limits](https://developers.gorgias.com/reference/limitations)
- [New email message data retention policy](https://developers.gorgias.com/changelog/new-email-message-data-retention-policy)

Checked against Gorgias's documentation on 2026-10-13.
