API Reference

Base URL https://api.reviewintelligence.dev/v1 · local http://localhost:3000/v1. All responses are JSON and include an X-Request-Id header plus X-RateLimit-* headers.

Quickstart

Run the API locally in mock mode (no credentials needed):

npm install
npm run dev          # boots on :3000 in mock mode
# authenticate with the dev key printed at startup:
curl localhost:3000/v1/analyze \
  -H "Authorization: Bearer rik_local_dev_key" \
  -H "Content-Type: application/json" \
  -d '{"text":"Great product, slow shipping","options":{"suggest_reply":true}}'

Authentication

Send your key as a bearer token. Keys are shown once and stored only as a hash.

Authorization: Bearer rik_live_xxx

Errors

Every error uses a stable envelope:

{ "error": { "code": "rate_limited", "message": "Too many requests", "request_id": "req_..." } }
HTTPcode
400invalid_request
401unauthorized
402quota_exceeded
404not_found
422unprocessable
429rate_limited
503ai_unavailable

POST /v1/analyze · 1 AU + 1/4,000 chars

{ "text": "Checkout was fast but support never replied.",
  "rating": 3, "options": { "suggest_reply": true, "reply_tone": "professional" } }
{ "id": "...", "sentiment": { "score": -0.18, "label": "negative", "confidence": 0.81 },
  "emotion": "frustration", "topics": ["checkout speed","support"], "language": "en",
  "suggested_reply": "Thanks for the feedback...", "usage": { "au_cost": 1 } }

POST /v1/analyze/batch · 1 AU/review + 1/4,000 chars

Asynchronous. Returns 202 with a job id; poll /v1/jobs/:id or receive a signed webhook.

{ "reviews": [ { "external_id": "r1", "text": "Love it" } ], "webhook_url": "https://..." }
→ { "job_id": "...", "status": "queued", "review_count": 1, "estimated_au": 1 }

POST /v1/themes · 4 AU + 1/1,250 chars

{ "reviews": ["...","..."], "max_themes": 8 }
→ { "themes": [ { "label": "onboarding", "frequency": 14, "sentiment": -0.42, "examples": ["..."] } ] }

POST /v1/summarize · 6 AU + 1/1,250 chars

{ "reviews": ["...","..."], "audience": "product_team" }
→ { "summary": { "headline": "...", "highlights": [], "lowlights": [], "recommended_actions": [] } }

POST /v1/respond · 1 AU

{ "text": "Waited 40 minutes and the food was cold.", "tone": "apologetic" }
→ { "reply": "We're truly sorry...", "tone": "apologetic", "usage": { "au_cost": 1 } }

Projects & ingestion

POST /v1/projects                 { "name": "Acme", "store_text": true }
POST /v1/projects/:id/ingest      { "reviews": [ { "text": "..." } ] }

GET /v1/jobs/:id

{ "job_id": "...", "status": "completed", "result": { "reviews": [...], "aggregate": {...} } }

GET /v1/usage

{ "plan": "growth", "period": "2026-06", "included_au": 40000,
  "used_au": 12480, "remaining_au": 27520, "overage_au": 0,
  "rate_limit": { "limit_per_min": 240 } }

POST /v1/webhooks

Deliveries are signed: header X-Webhook-Signature: sha256=<hmac> over the raw body.

{ "url": "https://example.com/hooks/ria", "events": ["job.completed","job.failed"] }
→ { "id": "...", "signing_secret": "whsec_review_intelligence_...", "active": true }