SDKs & tools

Official, dependency-free clients for the Repuso Monitoring API. Each is a single file you drop into your project - auth is handled for you. Get your API key from the console.

JavaScript / TypeScript

Node 18+ or any modern browser (global fetch).

Python

Python 3.7+, standard library only.

PHP

PHP 7.4+, ext-curl. Webhook signature check built in.

Postman

Import, set the apiKey variable, first call in minutes.

Quick start

// list recent 4-5 star reviews (each item carries a sentiment label)
import { Repuso } from './repuso.js';
const repuso = new Repuso('YOUR_API_KEY');

const { items } = await repuso.reviews.list({ profiles: '123', min_rating: 4 });

// AI insights: sentiment breakdown + strengths + opportunities
const insights = await repuso.profiles.insights(123);
console.log(insights.sentiment.positive_pct, insights.strengths);

// safe retries - the same key never creates a duplicate
await repuso.reviews.create(
  { from_name: 'Jane', text: 'Great!', rating_value: 5, rating_scale: 5 },
  'order-9982'
);
from repuso import Repuso
repuso = Repuso("YOUR_API_KEY")

reviews = repuso.reviews.list(profiles="123", min_rating=4, translate="es")
insights = repuso.profiles.insights(123)
print(insights["sentiment"]["positive_pct"], insights["strengths"])
require 'Repuso.php';
$repuso = new Repuso\Client('YOUR_API_KEY');

$reviews  = $repuso->reviews->list(['profiles' => '123', 'since' => '2026-01-01']);
$insights = $repuso->profiles->insights(123);

Pagination

Lists return a next_before_ts and next_before_id cursor. Pass both back for the next page - together they guarantee no review is skipped, even when many share the same timestamp.

let params = { profiles: '123', limit: 100 };
let page = await repuso.reviews.list(params);
while (page.items.length) {
  process(page.items);
  if (!page.next_before_id) break;
  page = await repuso.reviews.list({ ...params, before_ts: page.next_before_ts, before_id: page.next_before_id });
}
params = {"profiles": "123", "limit": 100}
page = repuso.reviews.list(**params)
while page["items"]:
    process(page["items"])
    if not page.get("next_before_id"):
        break
    page = repuso.reviews.list(**params, before_ts=page["next_before_ts"], before_id=page["next_before_id"])
$params = ['profiles' => '123', 'limit' => 100];
$page = $repuso->reviews->list($params);
while (!empty($page['items'])) {
    process($page['items']);
    if (empty($page['next_before_id'])) break;
    $page = $repuso->reviews->list($params + ['before_ts' => $page['next_before_ts'], 'before_id' => $page['next_before_id']]);
}

Verifying webhook signatures

Every delivery includes X-Repuso-Signature: t=<unix>,v1=<hex> where <hex> is HMAC-SHA256(secret, "<t>.<raw body>"). The signing secret is shown once when you create the webhook. Always use a constant-time compare and reject stale timestamps.

// Node
import crypto from 'crypto';
function verify(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(',').map(kv => kv.split('=')));
  if (!parts.t || !parts.v1) return false;
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > toleranceSec) return false;
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
import hashlib, hmac, time

def verify(raw_body, header, secret, tolerance_sec=300):
    parts = dict(kv.split("=", 1) for kv in header.split(",") if "=" in kv)
    if "t" not in parts or "v1" not in parts:
        return False
    if abs(time.time() - int(parts["t"])) > tolerance_sec:
        return False
    expected = hmac.new(secret.encode(), f"{parts['t']}.{raw_body}".encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])
// built into the PHP client
require 'Repuso.php';

$ok = Repuso\_Webhooks::verifySignature(
    file_get_contents('php://input'),
    $_SERVER['HTTP_X_REPUSO_SIGNATURE'] ?? '',
    $secret
);
Every endpoint is documented in the API reference. The clients also expose a generic request(method, path, opts) escape hatch for anything not wrapped as a named helper.