Skip to content

02 Get your data in /Integrations

Trustpilot

Send Trustpilot service reviews for a business unit to Dimension Labs with the universal API.

  1. T TrustpilotTickets, 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 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.

  • 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.

Trustpilot’s steps are in Authentication and Client credentials.

  1. 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.
  2. Find your Business Unit ID once and store it:
Terminal window
curl -G -H "apikey: $TRUSTPILOT_API_KEY" --data-urlencode "name=yourdomain.com" \
"https://api.trustpilot.com/v1/business-units/find"
  1. Private review data needs an OAuth 2.0 access token. With the client credentials grant, POST to https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken with grant_type=client_credentials and Authorization: Basic BASE64(API_KEY:API_SECRET). Run this server side only.
  2. 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 returns 429.
Terminal window
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 referenceId and referralEmail. Trustpilot limits it to 100,000 records.
  • Incremental: startDateTime and endDateTime filter by date and time (2013-09-07T13:37:00; with no time, 00:00:00). Sort with orderBy=createdat.asc.
  • Pagination: page and perPage. 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.

Each review is one incoming message under its own sessionId. A company reply is an outgoing message in the same session.

Dimension LabsTrustpilotNotes
texttitle and text (incoming), companyReply.text (outgoing)Join the title and body with a line break.
userIdconsumer.idTrustpilot’s internal id for the reviewer. Don’t send consumer.displayName or referralEmail.
incomingtrue for the review, false for the company reply.
sessionIdid
conversationIdid
dimensionlabs_timestampcreatedAt (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.
platformJsonstars, language, tags, source, isVerified, location.id, location.externalId, referenceIdreferenceId (your order or customer reference) is the field to join to your own data, as long as it isn’t an email address.
// 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.

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-01 sends 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.

Checked against Trustpilot’s documentation on 2026-10-13.