Skip to Content

API

Base path /api/v1; the OpenAPI document is served at /api/v1/openapi.json and the interactive browser at /api/v1/docs. Program routes live under /programs/{program_id}/... (constant PROGRAM_PREFIX in app/routers/_scope.py), organisation routes under /orgs/current/.... The API is designed: 117 routes are mounted and answer with the contract’s DTOs, connection providers and tools are stubs, and the agent runtime is a fake unless AGENT_RUNTIME_URL is set. Design target host api.trovensa.com; local http://localhost:8100.

Conventions

  • Every list route returns Page[T] (items[], total, limit, offset) with limit 1 to 200 (default 50) and offset from 0.
  • Every *Out carries id, created_at, updated_at; scoped rows carry organization_id, program_id, stage_id; agent-capable rows carry origin, agent_run_id, illustrative.
  • Exactly one require_permission(...) per route (the RBAC matrix test fails on any unlisted mounted route). Health routes are public; /me, /permissions, /personas and /providers need only a valid token.
  • Every mutation writes an audit row <target>.<verb> in the same transaction (app/services/audit.py::write_audit); the worker writes no audit rows.
  • Request bodies are capped by BodySizeLimitMiddleware; protocols, reports and SOPs get the larger document limit.
  • Success codes: 201 on create, 202 when a run is queued (sync, agent-runs, checks, invocations), 204 on delete, otherwise 200.

Errors: problem+json

Errors are RFC 7807 documents with media type application/problem+json. type is https://console.trovensa.com/errors/<slug> (for example .../forbidden), and every document carries the request_id that the X-Request-ID response header also exposes. A 403 adds permission; a 422 adds errors[] with loc, msg, type.

{ "type": "https://console.trovensa.com/errors/forbidden", "title": "Forbidden", "status": 403, "detail": "this action requires permission evidence.hypotheses.approve", "request_id": "6f1c0d0e-illustrative", "permission": "evidence.hypotheses.approve" }

Without a token every non-health route answers 401 with a WWW-Authenticate: Bearer challenge.

Identity and the development mode

Production tokens are RS256 from the identity provider with issuer and audience pinned by AUTH_ISSUER, AUTH_AUDIENCE and AUTH_JWKS_URL. Development and tests use HS256 tokens with header kid: dev signed with DEV_TOKEN_SECRET; they are accepted only when APP_ENV is dev or test, and validate_deployed_secrets() refuses to start a deployed environment that still carries the placeholder secret. Mint one with:

uv run python scripts/dev_token.py --user owner@example.com --org trovensa-demo --roles org_owner,program_owner

Routes

117 designed routes, grouped by router in mount order (ROUTERS in app/main.py). The legacy router (410 responses for retired paths) is mounted last and is empty.

Router health (2)

GET/healthpublic, no token
GET/health/readypublic, no token

Router me (1)

GET/meany signed-in user

Router permissions (1)

GET/permissionsany signed-in user

Router personas (1)

GET/personasany signed-in user

Router providers (1)

GET/providersany signed-in user

Router orgs (14)

GET/orgs/currentorg.settings.read
PATCH/orgs/currentorg.settings.update
GET/orgs/current/programsorg.programs.read
POST/orgs/current/programs201org.programs.create
PATCH/orgs/current/programs/{program_id}org.programs.manage
GET/orgs/current/usersorg.users.read
GET/orgs/current/groupsorg.groups.read
POST/orgs/current/groups201org.groups.manage
PATCH/orgs/current/groups/{group_id}org.groups.manage
DELETE/orgs/current/groups/{group_id}204org.groups.manage
GET/orgs/current/role-assignmentsorg.roles.read
POST/orgs/current/role-assignments201org.roles.manage
DELETE/orgs/current/role-assignments/{assignment_id}204org.roles.manage
GET/orgs/current/auditorg.audit.read

Router programs (7)

GET/programs/{program_id}program.settings.read
PATCH/programs/{program_id}program.settings.update
GET/programs/{program_id}/membersprogram.members.read
GET/programs/{program_id}/role-assignmentsprogram.roles.read
POST/programs/{program_id}/role-assignments201program.roles.manage
DELETE/programs/{program_id}/role-assignments/{assignment_id}204program.roles.manage
GET/programs/{program_id}/auditprogram.audit.read

Router connections (6)

GET/programs/{program_id}/connectionsprogram.connections.read
POST/programs/{program_id}/connections201program.connections.manage
PATCH/programs/{program_id}/connections/{connection_id}program.connections.manage
DELETE/programs/{program_id}/connections/{connection_id}204program.connections.manage
POST/programs/{program_id}/connections/{connection_id}/sync202program.connections.sync
GET/programs/{program_id}/connections/{connection_id}/runsprogram.connections.read

Router agent_runs (4)

GET/programs/{program_id}/agent-runsprogram.agent_runs.read
GET/programs/{program_id}/agent-runs/{run_id}program.agent_runs.read
GET/programs/{program_id}/agent-runs/{run_id}/eventsprogram.agent_runs.read
POST/programs/{program_id}/agent-runs/{run_id}/cancelprogram.agent_runs.manage

Router evidence (22)

GET/programs/{program_id}/evidence/questionsevidence.questions.read
POST/programs/{program_id}/evidence/questions201evidence.questions.manage
GET/programs/{program_id}/evidence/questions/{question_id}evidence.questions.read
PATCH/programs/{program_id}/evidence/questions/{question_id}evidence.questions.manage
DELETE/programs/{program_id}/evidence/questions/{question_id}204evidence.questions.manage
GET/programs/{program_id}/evidence/sourcesevidence.sources.read
POST/programs/{program_id}/evidence/sources201evidence.sources.manage
GET/programs/{program_id}/evidence/sources/{source_id}evidence.sources.read
PATCH/programs/{program_id}/evidence/sources/{source_id}evidence.sources.manage
POST/programs/{program_id}/evidence/sources/{source_id}/links201evidence.sources.link
GET/programs/{program_id}/evidence/findingsevidence.findings.read
POST/programs/{program_id}/evidence/findings201evidence.findings.manage
GET/programs/{program_id}/evidence/findings/{finding_id}evidence.findings.read
PATCH/programs/{program_id}/evidence/findings/{finding_id}evidence.findings.manage
GET/programs/{program_id}/evidence/hypothesesevidence.hypotheses.read
POST/programs/{program_id}/evidence/hypotheses201evidence.hypotheses.manage
GET/programs/{program_id}/evidence/hypotheses/{hypothesis_id}evidence.hypotheses.read
PATCH/programs/{program_id}/evidence/hypotheses/{hypothesis_id}evidence.hypotheses.manage
POST/programs/{program_id}/evidence/hypotheses/{hypothesis_id}/decisionevidence.hypotheses.approve
GET/programs/{program_id}/evidence/gapsevidence.gaps.read
PATCH/programs/{program_id}/evidence/gaps/{gap_id}evidence.gaps.manage
POST/programs/{program_id}/evidence/agent-runs202evidence.agents.use

Router plans (26)

GET/programs/{program_id}/plans/plansplans.plans.read
POST/programs/{program_id}/plans/plans201plans.plans.manage
GET/programs/{program_id}/plans/plans/{plan_id}plans.plans.read
PATCH/programs/{program_id}/plans/plans/{plan_id}plans.plans.manage
POST/programs/{program_id}/plans/plans/{plan_id}/transitionplans.plans.manage
POST/programs/{program_id}/plans/plans/{plan_id}/approveplans.plans.approve
GET/programs/{program_id}/plans/protocolsplans.protocols.read
POST/programs/{program_id}/plans/protocols201plans.protocols.manage
GET/programs/{program_id}/plans/protocols/{protocol_id}plans.protocols.read
PATCH/programs/{program_id}/plans/protocols/{protocol_id}plans.protocols.manage
POST/programs/{program_id}/plans/protocols/{protocol_id}/transitionplans.protocols.manage
POST/programs/{program_id}/plans/protocols/{protocol_id}/approveplans.protocols.approve
GET/programs/{program_id}/plans/experimentsplans.experiments.read
POST/programs/{program_id}/plans/experiments201plans.experiments.manage
GET/programs/{program_id}/plans/experiments/{experiment_id}plans.experiments.read
PATCH/programs/{program_id}/plans/experiments/{experiment_id}plans.experiments.manage
GET/programs/{program_id}/plans/reportsplans.reports.read
POST/programs/{program_id}/plans/reports201plans.reports.manage
GET/programs/{program_id}/plans/reports/{report_id}plans.reports.read
PATCH/programs/{program_id}/plans/reports/{report_id}plans.reports.manage
POST/programs/{program_id}/plans/reports/{report_id}/transitionplans.reports.manage
POST/programs/{program_id}/plans/reports/{report_id}/approveplans.reports.approve
GET/programs/{program_id}/plans/toolsplans.tools.read
POST/programs/{program_id}/plans/tools/{tool_id}/invocations202plans.tools.use
GET/programs/{program_id}/plans/tools/invocations/{invocation_id}plans.tools.read
POST/programs/{program_id}/plans/agent-runs202plans.agents.use

Router review (16)

GET/programs/{program_id}/review/sopsreview.sops.read
POST/programs/{program_id}/review/sops201review.sops.manage
GET/programs/{program_id}/review/sops/{sop_id}review.sops.read
PATCH/programs/{program_id}/review/sops/{sop_id}review.sops.manage
POST/programs/{program_id}/review/sops/{sop_id}/approvereview.sops.approve
GET/programs/{program_id}/review/checksreview.checks.read
POST/programs/{program_id}/review/checks202review.agents.use
GET/programs/{program_id}/review/checks/{check_id}review.checks.read
GET/programs/{program_id}/review/findingsreview.findings.read
GET/programs/{program_id}/review/findings/{finding_id}review.findings.read
PATCH/programs/{program_id}/review/findings/{finding_id}review.findings.manage
POST/programs/{program_id}/review/findings/{finding_id}/decisionreview.findings.approve
GET/programs/{program_id}/review/deviationsreview.deviations.read
POST/programs/{program_id}/review/deviations201review.deviations.manage
GET/programs/{program_id}/review/deviations/{deviation_id}review.deviations.read
PATCH/programs/{program_id}/review/deviations/{deviation_id}review.deviations.manage

Router progress (16)

GET/programs/{program_id}/progress/overviewprogress.milestones.read
GET/programs/{program_id}/progress/milestonesprogress.milestones.read
POST/programs/{program_id}/progress/milestones201progress.milestones.manage
GET/programs/{program_id}/progress/milestones/{milestone_id}progress.milestones.read
PATCH/programs/{program_id}/progress/milestones/{milestone_id}progress.milestones.manage
DELETE/programs/{program_id}/progress/milestones/{milestone_id}204progress.milestones.manage
GET/programs/{program_id}/progress/dependenciesprogress.dependencies.read
POST/programs/{program_id}/progress/dependencies201progress.dependencies.manage
DELETE/programs/{program_id}/progress/dependencies/{dependency_id}204progress.dependencies.manage
GET/programs/{program_id}/progress/open-itemsprogress.open_items.read
POST/programs/{program_id}/progress/open-items201progress.open_items.manage
PATCH/programs/{program_id}/progress/open-items/{item_id}progress.open_items.manage
GET/programs/{program_id}/progress/approvalsprogress.approvals.read
POST/programs/{program_id}/progress/approvals201progress.approvals.manage
POST/programs/{program_id}/progress/approvals/{approval_id}/withdrawprogress.approvals.manage
POST/programs/{program_id}/progress/approvals/{approval_id}/decisionprogress.approvals.approve

Providers

GET /providers returns the four connection providers of app/integrations/registry.py, every one designed:

idnamecategoryauth methodscheduled sync
literature_searchLiterature searchliteratureapi_keyyes
elnElectronic lab notebookelnoauth2yes
document_libraryDocument librarydocumentsoauth2yes
analysis_toolsAnalytical and design toolstoolsapi_keyno

Agent runs

POST .../evidence/agent-runs (kind in evidence_compare, evidence_gaps, evidence_hypotheses with a question_id), POST .../plans/agent-runs (plans_draft_protocol, plans_draft_report with a plan_id) and POST .../review/checks (review_check) create an AgentRunOut in status queued. The worker claims it, drives the runtime through bootstrap, start, status, submit, and writes the result as new records with origin = agent: findings and hypotheses with an assertion_kind, drafts in status draft, review findings with decision open. Public error codes on failure: runtime_unavailable, session_lost, budget_exhausted, timed_out, cancelled_by_user, attribution_leak, internal_error.

Source: api/app/main.py, api/app/routers/_scope.py, api/app/routers/health.py, api/app/routers/me.py, api/app/routers/permissions.py, api/app/routers/personas.py, api/app/routers/providers.py, api/app/routers/orgs.py, api/app/routers/programs.py, api/app/routers/connections.py, api/app/routers/agent_runs.py, api/app/routers/evidence.py, api/app/routers/plans.py, api/app/routers/review.py, api/app/routers/progress.py, api/app/errors.py, api/app/config.py, api/app/integrations/registry.py, api/app/services/agent_runtime.py, api/scripts/designed-routes.json, api/README.md

Last updated on