Test mode and feedback

Test mode

  1. Integrate with sk_test_ / pk_test_ keys.
  2. Fire each event type you use at least once (the canonical payloads are fine).
  3. In the dashboard, flip the mode toggle to Test and confirm the events appear with verdicts and reasons.
  4. Trigger your block path deliberately — add a blocklist entry in Settings → Lists (your own email domain works) — and confirm your UX shows the generic rejection.
  5. Swap the env var to live keys. Nothing else changes.

Test-mode data is fully isolated — test velocity counters and clusters never touch live decisions.

Reporting outcomes back (feedback)

Feedback is what makes the identity graph sharp for you specifically:

1import { Portreeve } from "portreeve";
2
3const portreeve = new Portreeve(process.env.PORTREEVE_SECRET_KEY!);
4
5// An allowed user turned out abusive — marks their whole linked cluster.
6await portreeve.feedback("evt_01J8Z3K9", "confirmed_abuse", "chargeback on first invoice");
7
8// A flagged user turned out real — the false-positive metric we track weekly.
9await portreeve.feedback("evt_01J8Z3KA", "false_positive");
  • confirmed_abuse marks the user’s whole linked cluster; future linked accounts get blocked.
  • false_positive is the metric we hold ourselves to weekly — send it even when it feels minor.
  • Safe to retry — no idempotency key needed. The SDK retries once on a 5xx or network failure, and the API deduplicates on (event id, outcome): reposting the same outcome returns {"ok": true} without recording a second row or double-counting the cluster mark. Replay whole batches freely. The dedupe key is the outcome, not the call — sending false_positive for an event you earlier reported as confirmed_abuse is new, distinct feedback.
  • Unlike verdict(), feedback() throws on failure rather than degrading — silently losing abuse feedback would be worse than an exception.

Next