02 Get your data in /Integrations
Trustpilot
Send Trustpilot service reviews for a business unit to Dimension Labs with the universal API.
- T TrustpilotTickets, 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 service reviews of your Trustpilot business unit: each review as a customer message, with its stars and tags, and your company reply when there is one. You run it on your side with the universal API, using Trustpilot’s Business Units API.
What you need
Section titled “What you need”- A Trustpilot for Business account with the API module. Trustpilot sells the module in three tiers of yearly API calls: 200,000, 1,000,000 or unlimited.
- A Trustpilot API key and API secret from an API application, and your Business Unit ID.
- A Dimension Labs API key for a new Universal API source. See Your API key.
1. Get API access in Trustpilot
Section titled “1. Get API access in Trustpilot”Trustpilot’s steps are in Authentication and Client credentials.
- Create an API application in Trustpilot Business to get an API key (client ID) and API secret. Trustpilot’s authentication page links to its help center for this step.
- Find your Business Unit ID once and store it:
curl -G -H "apikey: $TRUSTPILOT_API_KEY" --data-urlencode "name=yourdomain.com" \ "https://api.trustpilot.com/v1/business-units/find"- Private review data needs an OAuth 2.0 access token. With the client credentials grant,
POSTtohttps://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstokenwithgrant_type=client_credentialsandAuthorization: Basic BASE64(API_KEY:API_SECRET). Run this server side only. - Send the token as
Authorization: Bearer ACCESS_TOKEN. Trustpilot says access tokens last 100 hours, and asks you to reuse a token until it expires: requesting new ones too often returns429.
2. Pull new reviews
Section titled “2. Pull new reviews”curl -H "Authorization: Bearer $TRUSTPILOT_TOKEN" \ "https://api.trustpilot.com/v1/private/business-units/BUSINESS_UNIT_ID/reviews?startDateTime=2026-10-01T00:00:00&orderBy=createdat.asc&perPage=100&page=1"- “Get private reviews for a business unit” returns your reviews with private fields such as
referenceIdandreferralEmail. Trustpilot limits it to 100,000 records. - Incremental:
startDateTimeandendDateTimefilter by date and time (2013-09-07T13:37:00; with no time,00:00:00). Sort withorderBy=createdat.asc. - Pagination:
pageandperPage. A page past the end returns an empty array. Trustpilot’s API module page says one call returns up to 100 reviews or 1 MB of data. - The company reply is in the same review, under
companyReply, so there is no second call. - Rate limits (Trustpilot’s): Trustpilot recommends staying under 833 calls per 5 minutes and 10,000 calls per hour. Data calls also count against your API module allowance.
- If you store review data, Trustpilot’s API module overview asks you to mirror its deletions by calling the Deletions API every 28 days.
3. Map the fields
Section titled “3. Map the fields”Each review is one incoming message under its own sessionId. A company reply is an outgoing message in the same session.
| Dimension Labs | Trustpilot | Notes |
|---|---|---|
text | title and text (incoming), companyReply.text (outgoing) | Join the title and body with a line break. |
userId | consumer.id | Trustpilot’s internal id for the reviewer. Don’t send consumer.displayName or referralEmail. |
incoming | true for the review, false for the company reply. | |
sessionId | id | |
conversationId | id | |
dimensionlabs_timestamp | createdAt (review), companyReply.createdAt (reply) | Convert with toMillis, which reads a date without a time zone as UTC. A reply within a second of the review is moved a second later. |
platformJson | stars, language, tags, source, isVerified, location.id, location.externalId, referenceId | referenceId (your order or customer reference) is the field to join to your own data, as long as it isn’t an email address. |
4. Send it
Section titled “4. Send it”// trustpilot.mjs. Environment: TRUSTPILOT_API_KEY, TRUSTPILOT_API_SECRET, TRUSTPILOT_BUSINESS_UNIT_ID, 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://api.trustpilot.com/v1';let token = null, tokenExpires = 0; // reused while the process lives, as Trustpilot asks
async function accessToken() { if (token && Date.now() < tokenExpires - HOUR) return token; const auth = Buffer.from(`${process.env.TRUSTPILOT_API_KEY}:${process.env.TRUSTPILOT_API_SECRET}`).toString('base64'); const res = await fetch(`${API}/oauth/oauth-business-users-for-applications/accesstoken`, { method: 'POST', body: new URLSearchParams({ grant_type: 'client_credentials' }), headers: { Authorization: `Basic ${auth}` } }); if (!res.ok) throw new Error(`Trustpilot token request returned ${res.status}: ${await res.text()}`); const body = await res.json(); token = body.access_token; tokenExpires = Date.now() + Number(body.expires_in ?? 3600) * 1000; return token;}
// Retries Trustpilot'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: `Bearer ${await accessToken()}` } }); if (res.ok) return res.json(); if (res.status === 401 && attempt === 0) { token = null; continue; } if ((res.status !== 429 && res.status < 500) || attempt === 5) throw new Error(`Trustpilot returned ${res.status}: ${await res.text()}`); await sleep((Number(res.headers.get('retry-after')) || 2 ** attempt) * 1000); }}
// Sends every review created at or after `since` (Unix ms). Returns the new `since`.export async function syncTrustpilot({ since, historical = false }) { let newest = since, from = since; for (;;) { let restart = false; for (let page = 1; ; page++) { const q = new URLSearchParams({ startDateTime: new Date(from).toISOString().slice(0, 19), orderBy: 'createdat.asc', perPage: '100', page: String(page) }); const { reviews = [] } = await get(`${API}/private/business-units/${process.env.TRUSTPILOT_BUSINESS_UNIT_ID}/reviews?${q}`); for (const r of reviews) { const created = toMillis(r.createdAt); newest = Math.max(newest, created); const base = { userId: r.consumer?.id ?? r.id, sessionId: r.id, conversationId: r.id, platformJson: { stars: r.stars, language: r.language, tags: r.tags, source: r.source, isVerified: r.isVerified, locationId: r.location?.id, locationExternalId: r.location?.externalId, referenceId: r.referenceId } }; const text = [r.title, r.text].filter((x) => x?.trim()).join('\n'); if (text) await sendToDimensionLabs({ ...base, text, incoming: true, dimensionlabs_timestamp: created }, { historical: historical || created < Date.now() - HOUR }); if (r.companyReply?.text?.trim()) { const replied = Math.max(toMillis(r.companyReply.createdAt), created + 1000); await sendToDimensionLabs({ ...base, text: r.companyReply.text.trim(), incoming: false, dimensionlabs_timestamp: replied }, { historical: historical || replied < Date.now() - HOUR }); } } if (!reviews.length) break; if (page === 1000) { restart = true; break; } // Trustpilot stops at 100,000 records: start again from the newest seen } if (!restart) return newest; from = newest; }}The list stops at 100,000 records (1,000 pages of 100), so on a big history load the code starts again from the newest review it has sent. This picks reviews up by createdAt, so a company reply written after the review was pulled is not sent. To catch those, run a history load over the last few weeks now and then (node run.mjs with a recent date): it sends the new replies, and everything else in it is a duplicate, removed automatically. Then run a backfill.
5. Run it
Section titled “5. Run it”Save the code as trustpilot.mjs in a project set up as in Set up your project, and run it with the scheduled sync runner: import { syncTrustpilot as sync } from './trustpilot.mjs';. Trustpilot asks you to reuse a token until it expires; the code keeps it for as long as the process lives, so a warm Lambda reuses it between runs.
- History first:
node run.mjs 2020-01-01sends every review since that date to/trackhistorical. Then start a backfill from the Backfill tab. - Then every 15 minutes: the scheduled job sends new reviews to
/track, and they are enriched automatically every day. Anything 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.
Deletions. Trustpilot asks API module users who store review data to mirror its deletions. You can’t delete individual records in Dimension Labs yourself: email [email protected] with the source and the review ids for a targeted deletion.
If you have reviews in a file instead, upload it and check it first with the file checker, then run a backfill.
Trustpilot reference
Section titled “Trustpilot reference”- Get started with Trustpilot for Business
- API module overview
- Authentication
- Client credentials
- Business Units API overview
- Business Units API
- Rate limiting best practices
Checked against Trustpilot’s documentation on 2026-10-13.