Corsac API
REST · JSON over HTTPS · bearer-token auth. Everything customer-facing lives under /api/app/*. Browse the eval library, push your runs, and read or write the human review decision on each one.
https://api.corsac.ai/openapi.json (rendered at /docs and /swagger). The page below is a hand-written tour of the same surface; field-level shapes always defer to OpenAPI.Getting started
Browse GET /api/app/evals to find a spec, mint a workspace API key in the Corsac dashboard, then push your first eval result from CI in three lines. Every Corsac eval — automated or human-reviewed — flows through a single ingestion endpoint and is then queryable per org.
curl https://api.corsac.ai/api/app/evals/clinical_safety/external-run \
-H "Authorization: Bearer $CORSAC_API_KEY" \
-H "Content-Type: application/json" \
-d @eval-result.jsonAuthentication
Most endpoints authenticate with a workspace API key in the Authorization header. Keys are prefixed csk_ and minted by an org admin from the Corsac dashboard. There is one active key per organization at a time; regenerating auto-revokes the previous key.
Authorization: Bearer csk_...The eval-library list endpoint (GET /api/app/evals) is the one exception — it's anonymous so crawlers and unauthenticated visitors can discover available evals. Spec detail (rubric, evaluators, cases) and everything run/review-related require auth.
Read endpoints also accept the session cookie issued to a signed-in user, so the same paths back both the SDK and the dashboard. Endpoints that record a human decision (the PUT on a review action) require a session — API-key callers receive a 403 by design.
Errors
Errors follow the FastAPI convention: a JSON body with a single detail field plus a conventional HTTP status code. Validation failures (422) include a structured list under detail with the offending field path.
| Status | When |
|---|---|
| 400 | Malformed request: wrong content-type, conflicting path/body values, or an unrecoverable parse error. |
| 401 | Missing, invalid, or revoked bearer token; or no active session. |
| 403 | Authenticated but not allowed: API-key caller hit a session-only endpoint, or non-admin hit an admin endpoint. |
| 404 | Resource doesn't exist or is in another organization. |
| 422 | Validation failure on the request body. See `detail` for field path and message. |
| 5xx | Server error. Retry with backoff; surface request id from logs if it persists. |
{
"detail": "Spec not found: clinical_safety"
}Pagination
List endpoints accept limit (max 200, default 50) and pre-filter by the actor's organization. There is no cursor today; ordering is newest-first bystarted_at.
OpenAPI reference
The autogenerated schema is the source of truth for request and response shapes:
GET https://api.corsac.ai/openapi.json— raw schemahttps://api.corsac.ai/docs— ReDoc referencehttps://api.corsac.ai/swagger— interactive Swagger console
List evals
Anonymous browse of the eval library. Returns the thin list shape (name, slug, vendor, use-case, short description, counts) so crawlers and unauthenticated visitors can discover what's available. No auth header required.
curl https://api.corsac.ai/api/app/evals[
{
"spec_id": "clinical_safety",
"name": "Clinical Safety",
"vendor": "Hippocratic AI",
"use_case": "Patient intake",
"short_description": "PHI redaction, medication safety, citation fidelity.",
"evaluator_count": 4,
"case_count": 412
}
]Get eval spec detail
Full eval spec including rubric, evaluator configs (thresholds, weights, severity), and example cases. Requires auth — this is the deliberate marketplace wall: anonymous visitors can browse names and descriptions via the list endpoint, but rubric internals require signup.
spec_id path stringrequired | The eval spec slug (e.g. clinical_safety). |
include_examples query booloptional | Include example cases inline. Default true. |
max_examples query integeroptional | 0–200; default 20. |
curl https://api.corsac.ai/api/app/evals/clinical_safety \
-H "Authorization: Bearer $CORSAC_API_KEY"{
"spec_id": "clinical_safety",
"name": "Clinical Safety",
"vendor": "Hippocratic AI",
"use_case": "Patient intake",
"description": "...",
"evaluators": [ /* full rubric */ ],
"examples": [ /* sample cases */ ]
}Push an eval result
Ingest a pre-computed eval result for a spec. This is the canonical SDK entry point — your CI or runner does the scoring locally, then sends the EvalResult JSON to Corsac for storage, gating, and routing to review.
spec_id path stringrequired | The eval spec slug (e.g. clinical_safety). Must match the optional spec_id in the body if present. |
body EvalResult (JSON)required | Per-example metrics, aggregates, and run metadata. Field shape lives in the OpenAPI ExternalRunRequestV2 schema. |
curl https://api.corsac.ai/api/app/evals/clinical_safety/external-run \
-H "Authorization: Bearer $CORSAC_API_KEY" \
-H "Content-Type: application/json" \
-d @eval-result.json{
"run_id": "run_2fJ4...",
"spec_id": "clinical_safety",
"organization_id": "org_8c12...",
"status": "completed",
"gate_status": "passed",
"aggregates": { /* ... */ },
"failed_metrics": [],
"started_at": "2026-05-13T15:42:11Z",
"finished_at": "2026-05-13T15:42:14Z"
}List runs
Paginated list of runs in the caller's organization, newest first. Accepts either a session cookie or a bearer API key.
spec_id query stringoptional | Filter to a single eval spec slug. |
limit query integeroptional | 1–200; default 50. |
curl 'https://api.corsac.ai/api/app/runs?spec_id=clinical_safety&limit=20' \
-H "Authorization: Bearer $CORSAC_API_KEY"[
{
"run_id": "run_2fJ4...",
"spec_id": "clinical_safety",
"status": "completed",
"gate_status": "passed",
"started_at": "2026-05-13T15:42:11Z",
"finished_at": "2026-05-13T15:42:14Z"
}
]Get a run
Fetch a single run by id. Org-scoped — runs in another organization return 404.
run_id path stringrequired | The run identifier returned by external-run or list. |
curl https://api.corsac.ai/api/app/runs/run_2fJ4... \
-H "Authorization: Bearer $CORSAC_API_KEY"{
"run_id": "run_2fJ4...",
"spec_id": "clinical_safety",
"organization_id": "org_8c12...",
"status": "completed",
"gate_status": "passed",
"aggregates": { /* ... */ },
"failed_metrics": [],
"failed_primary_metrics": [],
"blocked_reason": null
}List review decisions
All human review decisions recorded against runs in the caller's organization.
curl https://api.corsac.ai/api/app/review-actions \
-H "Authorization: Bearer $CORSAC_API_KEY"[
{
"run_id": "run_2fJ4...",
"decision": "approved",
"notes": "Reviewed by clinical lead; rubric pass.",
"updated_at": "2026-05-13T16:02:11Z",
"updated_by_user_id": "user_..."
}
]Get a review decision
Read the current review decision for a single run. 404 if no decision has been recorded yet.
run_id path stringrequired | The run identifier. |
curl https://api.corsac.ai/api/app/review-actions/run_2fJ4... \
-H "Authorization: Bearer $CORSAC_API_KEY"{
"run_id": "run_2fJ4...",
"decision": "approved",
"notes": "Reviewed by clinical lead; rubric pass.",
"updated_at": "2026-05-13T16:02:11Z",
"updated_by_user_id": "user_..."
}Set a review decision
Record or update the human review decision on a run. Session-only — API-key callers get 403 because review decisions are human-accountability artifacts and we record the acting user id on every transition.
run_id path stringrequired | The run identifier. |
decision body enumrequired | Allowed values are defined by the review-decision policy on the backend; consult OpenAPI for the current set. |
notes body string?optional | Free-text rationale captured alongside the decision. |
curl -X PUT https://api.corsac.ai/api/app/review-actions/run_2fJ4... \
-H "Cookie: corsac_session=..." \
-H "Content-Type: application/json" \
-d '{ "decision": "approved", "notes": "Reviewed by clinical lead." }'{
"run_id": "run_2fJ4...",
"decision": "approved",
"notes": "Reviewed by clinical lead.",
"updated_at": "2026-05-13T16:02:11Z",
"updated_by_user_id": "user_..."
}Coming soon
Official TypeScript and Python SDKs are on the roadmap. In the meantime, the API is small enough to call with fetch or requests; the snippets in Getting started are copy-pasteable.
If you'd like early access to the SDKs or a specific language wrapper, email hello@corsac.ai.
Mint a workspace API key from the dashboard and push your first run in under a minute.