← Guides

Sync reviews into your own database

Pull the full history once, then keep it current with a cursor. About 30 lines of code.

Most integrations end up wanting reviews in their own store - to join against orders, run reports, or feed a dashboard. The pattern is a full backfill followed by incremental catch-up, and the only part with sharp edges is pagination.

New here?

Repuso collects customer reviews from Google, TripAdvisor, Trustpilot, the App Store and 50+ other platforms, and serves them through one REST API in a single JSON schema - with rating history, sentiment, AI summaries and webhooks on new reviews. You point it at a public profile; it keeps that profile current and tells you when something changes.

This guide assumes you already have an API key and at least one profile connected. Both take about two minutes: start with the quickstart, or get a key in the console - the trial is 10 days and needs no card.

1. Find the profiles you are syncing

curl -u :$REPUSO_KEY https://api.repuso.com/public/v1/profiles/get

Each profile has an id, a type (google, tripadvisor, trustpilot…) and its current score and reviews count. Keep the id: it is what you filter reviews by.

2. Page through the reviews

The list endpoint is a cursor, not page numbers - reviews arrive continuously, so offsets would duplicate and skip rows. Ask for a page, then send back both cursor values you get:

curl -u :$REPUSO_KEY \
  'https://api.repuso.com/public/v1/reviews/get?limit=100&profiles=49331'

curl -u :$REPUSO_KEY \
  'https://api.repuso.com/public/v1/reviews/get?limit=100&profiles=49331&before_ts=1788825600&before_id=11109383'

Every response carries what you need to decide whether to continue:

{
  "count": 1284,          // total matching your filters, not this page
  "limit": 100,
  "has_more": true,       // loop while this is true
  "items": [ ... ],
  "next_before_ts": 1788825600,
  "next_before_id": 11109383
}

3. The loop

import requests

API  = "https://api.repuso.com/public/v1"
AUTH = ("", "YOUR_API_KEY")          # key goes in the password field

def fetch_all(profile_id):
    params = {"limit": 100, "profiles": profile_id}
    while True:
        r = requests.get(f"{API}/reviews/get", params=params, auth=AUTH, timeout=30)
        r.raise_for_status()
        page = r.json()

        yield from page["items"]

        if not page.get("has_more"):
            break
        params["before_ts"] = page["next_before_ts"]
        params["before_id"] = page["next_before_id"]

for review in fetch_all(49331):
    upsert(review)                    # keyed on review["id"]

Three things that will bite you

4. Staying current

After the backfill, you only want what is new. Two options, and they compose:

Belt and braces is a webhook for freshness plus a nightly since sweep to catch anything a failed delivery missed.

Schema worth storing

id              bigint primary key    -- stable, use it for upserts
profile_id      bigint                -- which profile it came from
type            text                  -- google, tripadvisor, ...
rating_value    numeric               -- normalise with rating_scale
rating_scale    int                   -- 5 for most, 10 for some platforms
sentiment       text                  -- positive | neutral | negative
text            text
from_name       text
posted_on       timestamp
media           jsonb                 -- [{type, url, src}]

Ratings are not all out of five - rating_scale tells you what the platform used, so store both and divide when you report.

Rate limits

Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. A backfill at limit=100 rarely gets near the ceiling; if you do hit a 429, Retry-After tells you how long to wait.

Get an API key Full API reference

← All guides