Skip to content

02 Get your data in /Integrations

Re:amaze

Send Re:amaze conversations and their messages to Dimension Labs with the universal API.

  1. RA Re:amazeTickets, 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 each Re:amaze conversation as one conversation: the customer’s messages and your staff’s replies, across email, chat, social, SMS, WhatsApp and the other channels a brand connects. You run it on your side: a small script pulls from the Re:amaze API and posts each message to the universal API.

  • A Re:amaze user whose API token you can use. Every user has their own token, and the API acts as that user.
  • The login email of that user, and the host of each brand you want to bring in, for example yourbrand.reamaze.io. It’s on the Brand Settings page.
  • A Dimension Labs API key for a new Universal API source. See Your API key.
  1. In your Re:amaze account, go to Settings.
  2. Under Developer, click API Token.
  3. Click Generate New Token and copy it.
  4. Authenticate with Basic auth: the user’s login email and the token. Send Accept: application/json on every request, or add .json to the URL (API introduction).

Requests are scoped by brand, through the host. An account with several brands needs one pull per brand host.

Retrieve messages across every conversation in the brand, filtered by when they were written. Ask for customer and staff messages separately, so you know who wrote each one:

Terminal window
curl -u "$REAMAZE_EMAIL:$REAMAZE_API_TOKEN" -H "Accept: application/json" \
"https://YOUR_BRAND.reamaze.io/api/v1/messages?filter=customer&start_date=2026-10-01T00:00:00Z&page=1"

start_date and end_date (ISO 8601) filter on the message’s creation date. filter=customer returns only customer messages and filter=staff only staff messages. Results come newest first, 30 to a page: keep adding 1 to page up to the page_count in the response.

Each message has body, visibility, origin, created_at and its conversation (slug, subject, category). The conversation slug uniquely identifies a conversation.

Rate limits, per Re:amaze: a set number of requests per minute per API token, which Re:amaze doesn’t publish. Going over returns 429 (API introduction).

Dimension LabsRe:amazeNotes
textmessage bodySkip messages where visibility is 1 (internal note) or 2 (collision detected message). Keep 0 (regular).
userIdconversation slugMessages identify the sender only by name and email, so use the sessionId.
incomingthe filter you asked fortrue for messages from filter=customer, false for messages from filter=staff.
sessionIdconversation slugPrefix it with the brand, for example reamaze-yourbrand-knock-knock.
conversationIdconversation slugSame value as sessionId.
dimensionlabs_timestampmessage created_atConvert with toMillis. Re:amaze times carry a time zone offset. Messages with the same time in one conversation get 1,000 ms added each.
platformJsonmessage origin; conversation category.slug, category.channelorigin says where the message came from, for example 1 for email and 9 for SMS.

Personal data. Don’t send the message’s user or recipients, or the conversation’s author: they hold names and email addresses. Messages can hold addresses, phone numbers and order details: redact them before you send. See PII redaction.

// reamaze.mjs. Environment: REAMAZE_BRAND (yourbrand, from yourbrand.reamaze.io), REAMAZE_EMAIL, REAMAZE_API_TOKEN, DL_API_KEY.
import { sendToDimensionLabs, toMillis } from './dimensionlabs.mjs';
const HOUR = 60 * 60 * 1000;
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const brand = process.env.REAMAZE_BRAND;
const base = `https://${brand}.reamaze.io/api/v1`;
const auth = 'Basic ' + Buffer.from(`${process.env.REAMAZE_EMAIL}:${process.env.REAMAZE_API_TOKEN}`).toString('base64');
// Retries Re:amaze'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, Accept: 'application/json' } });
if (res.ok) return res.json();
if ((res.status !== 429 && res.status < 500) || attempt === 5) throw new Error(`Re:amaze returned ${res.status}: ${await res.text()}`);
await sleep((Number(res.headers.get('retry-after')) || 2 ** (attempt + 2)) * 1000);
}
}
// Every message of one kind (customer or staff) written at or after `since`.
async function messages(filter, since) {
const all = [];
const start = encodeURIComponent(new Date(since).toISOString());
for (let page = 1, pages = 1; page <= pages; page++) {
const res = await get(`${base}/messages?filter=${filter}&start_date=${start}&page=${page}`);
all.push(...res.messages);
pages = res.page_count;
}
return all.map((m) => ({ ...m, incoming: filter === 'customer' }));
}
// Sends every regular message written at or after `since` (Unix ms). Returns the new `since`.
export async function syncReamaze({ since, historical = false }) {
let newest = since;
const all = [...await messages('customer', since), ...await messages('staff', since)]
.filter((m) => m.visibility === 0 && m.conversation?.slug && m.body?.trim() && toMillis(m.created_at) >= since)
.sort((a, b) => a.conversation.slug.localeCompare(b.conversation.slug) || toMillis(a.created_at) - toMillis(b.created_at));
let last = { slug: null, ts: 0 };
for (const m of all) {
const slug = m.conversation.slug;
let ts = toMillis(m.created_at);
if (slug === last.slug && ts <= last.ts) ts = last.ts + 1000;
last = { slug, ts };
const id = `reamaze-${brand}-${slug}`;
await sendToDimensionLabs({
text: m.body,
userId: id,
incoming: m.incoming,
sessionId: id,
conversationId: id,
dimensionlabs_timestamp: ts,
platformJson: { brand, origin: m.origin, category: m.conversation.category?.slug, channel: m.conversation.category?.channel },
}, { historical: historical || ts < Date.now() - HOUR });
newest = Math.max(newest, toMillis(m.created_at));
}
return newest;
}

Save the code as reamaze.mjs in a project set up as in Set up your project, and run it with the scheduled sync runner: import { syncReamaze as sync } from './reamaze.mjs';. For several brands, run one job per brand, each with its own REAMAZE_BRAND and its own cursor file.

  • History first: node run.mjs 2025-01-01 sends every message since that date to /trackhistorical. Then start a 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.

Pages hold 30 messages, so a history load makes many calls; the code waits whenever Re:amaze returns 429. You can also upload a file of exported conversations with one row per message (check it with the file checker), then run a backfill.

Checked against Re:amaze’s documentation on 2026-10-26.