REST API reference
Base URL: https://api.sentnelops.com — every body is JSON, every request carries Authorization: Bearer <session JWT | org api key>. Roles shown are the minimum; the api key acts as admin.
Errors & rate limits
| Status | Meaning |
|---|---|
401 | Missing/invalid credential, expired session, disabled account |
403 | Role too low, segregation-of-duties violation, or wrong current password |
404 | Doesn't exist — or belongs to another tenant (deliberately identical) |
409 | State conflict: lifecycle, already-decided approval, duplicate email, last admin |
422 | Validation error (detail in body) |
429 | Rate limited — default 600 req/min per credential; responses carry X-RateLimit-*, over-limit adds Retry-After |
Accounts & sessions
| Endpoint | Role | Notes |
|---|---|---|
POST /orgs/register | public | Org + api key (shown once) + first admin, auto-logged-in |
POST /auth/login | public | { email, password } → { token, user } — 12 h session |
GET /auth/me | viewer | Who am I: via, org_id, role, user |
POST /auth/password | session | { current_password, new_password } |
GET /users · POST /users | admin | List / create (email, password, role, name?) |
PATCH /users/:id | admin | role | status | name; 409 on last admin |
Agents & lifecycle
| Endpoint | Role | Notes |
|---|---|---|
POST /agents | developer | → 201 { agent, token } — agent JWT shown once. production starts as draft |
GET /agents | viewer | Filters: environment, risk_level, status, owner, limit≤200, offset |
GET /agents/:id | viewer | |
PATCH /agents/:id | developer | owner, allowed_mcp, denied_mcp, risk_level, expires_at (+actor). Never status |
POST /agents/:id/approve | security | { approved_by, note? } — SoD enforced |
POST /agents/:id/activate | developer | { actor } — approved → active only |
POST /agents/:id/suspend | security | { actor, reason } — reason mandatory |
POST /agents/:id/reactivate | security | { actor } — ≤30 d, else re-approval |
DELETE /agents/:id?actor= | security | Decommission — terminal, tokens revoked |
POST /agents/:id/review | security | Records review; advances next_review by risk cadence |
POST /agents/:id/rotate?actor= | developer | → { agent, token } — all prior tokens revoked |
GET /agents/:id/audit | viewer | Append-only event trail, newest first |
Lifecycle errors return { code, detail }: illegal_transition · segregation_of_duties · approval_required · reapproval_required · reason_required · terminal_state · scope_frozen.
Policy & reporting
| Endpoint | Role | Notes |
|---|---|---|
POST /policy/check | viewer | { agent_id, mcp_server, tool? } → { permitted, reason, policy_rule } — audited |
GET /policy/source | viewer | The org's editable policy YAML — its own document, or the platform default as a template |
PUT /policy/source | security | { yaml, dry_run? } — strictly validated (422 invalid_policy with line), audited; live within ~5 s |
DELETE /policy/source | security | Remove the org document — revert to the platform default |
GET /agents/export.csv | viewer | Full registry (SOC 2 evidence) |
GET /reports/governance?days=30 | viewer | 5-section governance CSV |
MCP proxy & observability
| Endpoint | Auth | Notes |
|---|---|---|
POST /mcp-servers | security | { name, upstream_url } — upserts per org |
GET /mcp-servers | viewer | |
ANY /proxy/:server/:path | agent JWT | The transparent proxy — see the proxy guide for status codes |
GET /mcp-calls | viewer | Filters: agent_id, would_block, status (permitted|error|blocked), limit≤1000, offset |
GET /mcp-calls/export.csv?days=30 | viewer | SIEM-ready call log |
GET /cimd/:agent_id.json | public | Resolvable agent identity — metadata only, no secrets |
WS /ws/calls?key=<api-key> | machine | Live feed; a tail, not the log |
Approvals
| Endpoint | Role | Notes |
|---|---|---|
GET /approvals | viewer | Filter status: pending | approved | denied | timeout |
POST /approvals/:id/approve · /deny | security | { approver?, note? } — sessions decide as themselves; api key must name approver; 409 if already decided |
Interactive docs
https://api.sentnelops.com/docs # Swagger UI — try every endpoint live https://api.sentnelops.com/health # liveness, never rate-limited