Public API & webhooks
API keys, the REST surface, signed webhook events.
RepCue's control-plane API is the same one the console uses. Everything you see in the console is reachable with an API key.
API keys
Create keys in Settings → API keys. Each key has a name, a role (rep, manager or admin; it can't exceed yours), and shows its prefix only; the secret is displayed once.
Authorization: Bearer rk_live_3f9c…
Keys are scoped to your organisation. Revoke instantly from the same page; last used helps you find forgotten ones.
Base URL and envelope
https://api.repcue.io/v1
Every response is an envelope:
{ "success": true, "data": { … } }
{ "success": false, "error": { "code": "not_found", "message": "…" } }
Reference
The OpenAPI 3.1 document and an interactive explorer are served at https://api.repcue.io/docs for authenticated API keys and admin sessions. The main resources:
| Resource | Endpoints |
|---|---|
| Calls | GET /calls?q=&from=&to=&repUserId= · GET /calls/:id · GET /calls/:id/utterances · GET /calls/:id/artifacts · GET /calls/:id/recording · GET/PATCH /calls/:id/scorecard · DELETE /calls/:id |
| Knowledge | GET/POST /kb/documents · POST /kb/documents/upload · POST /kb/import/url · GET /kb/search?q= |
| Battlecards & playbooks | GET/POST/PATCH/DELETE /battlecards, /battlecards/:id/versions, /playbooks |
| Deals | GET/POST/PATCH /deals · GET /deals/:id/timeline · GET /deals/:id/risk · GET /deals/forecast |
| CRM diffs | GET /crm/diffs · POST /crm/diffs/:id/approve · …/reject |
| Analytics | GET /analytics/{suggestion-adoption,objection-frequency,talk-ratio,outcomes,roi,latency,leaderboard}; all accept from, to, repUserId, scope, format=csv |
| Coaching | GET /calls/:id/comments · POST /calls/:id/snippets · GET /coaching/skills |
| Teams | GET/POST /teams · GET/PATCH/DELETE /teams/:id · POST /teams/:id/members · DELETE /teams/:id/members/:userId |
| Goals | GET/POST/PATCH/DELETE /goals · GET /goals/progress?scope= |
| Notifications | GET /notifications · POST /notifications/:id/read · POST /notifications/read-all · GET/PUT /notifications/prefs |
| Policies & rubrics | GET/PUT /policies?teamId= · GET /policies/for-user/:userId · GET/POST/PATCH/DELETE /scorecard-templates · GET/POST/DELETE /vocabulary |
| Views & reports | GET/POST/PATCH/DELETE /saved-views · …/scheduled-reports |
| Search | GET /search?q=&types=calls,deals,people,documents |
| People | GET/PATCH/DELETE /users · POST /users/invite |
| Audit | GET /audit?action=&actor=&from=&to= |
| Admin | GET /admin/health-summary · POST /admin/view-as |
| Webhooks | GET/POST/DELETE /webhooks · POST /webhooks/:id/test-delivery |
| Org | GET /orgs/me · GET /orgs/me/export |
Rate limit: 300 requests/minute per key, with Retry-After on 429.
The scope parameter
List endpoints for calls, deals, analytics, coaching, usage events and search accept ?scope=me | org | team:<id>.
The server decides what that resolves to, based on the key's role. A rep key is always forced to its own records; a manager key is bounded by the teams it manages and is refused org; an admin key may request anything. Passing a scope you aren't entitled to does not widen access; see Roles & permissions.
Fetching a single record that is out of scope returns 404, not 403, so a response cannot confirm the record exists.
Webhooks
Register an HTTPS endpoint in Settings → Webhooks (or POST /webhooks) and choose events:
| Event | When |
|---|---|
utterance.final | A final transcript turn (only when the policy permits transcript egress) |
suggestion.shown · suggestion.used | HUD card lifecycle |
call.completed | Post-call pipeline finished; payload includes artifact ids |
crm.synced | A diff was approved and written |
email.sent | Follow-up delivered |
usage.recorded | A live hour was metered |
user.deleted · org.deleted | GDPR erasure completed |
Verifying signatures
Every delivery carries:
X-RepCue-Event: call.completed
X-RepCue-Delivery: evt_01J…
X-RepCue-Timestamp: 1755772800
X-RepCue-Signature: sha256=…
Compute HMAC_SHA256(secret, timestamp + "." + rawBody) and compare in constant time. Reject timestamps older than five minutes.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(secret, headers, rawBody) {
const ts = headers["x-repcue-timestamp"];
const expected = "sha256=" + createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
const given = headers["x-repcue-signature"] ?? "";
return expected.length === given.length && timingSafeEqual(Buffer.from(expected), Buffer.from(given));
}
Delivery
2xx within 10 s counts as delivered. Failures retry twice immediately, then hourly up to 10 attempts. Test delivery sends a signed ping event so you can check your verifier before going live. Endpoints resolving to private networks are rejected.