Skip to content
DataCourt AI
Sign inAudit a dataset

CI & API

Data-contract gate for CI, tokens and the REST API.

DataCourt exposes a JSON REST API under /api/v1. The web app uses the same API. The interactive OpenAPI schema is served at /api/v1/docs (Swagger UI) and /api/v1/openapi.json.

Authentication

ClientMechanism
Browserdc_session HttpOnly cookie from POST /api/v1/auth/login. State-changing requests must send x-datacourt-csrf: 1.
Automation / CIAuthorization: Bearer dct_… API token, created by a workspace admin under Settings → API tokens

Token scopes:

ScopeAllows
contracts:readGET /ci/contract
audits:readread endpoints for the token's workspace
audits:writestart audits (acts with the admin role inside the token's workspace)

Tokens only reach data in the workspace that created them. Objects in other workspaces return 404.

Data-contract gate for CI

The typical flow: a pipeline uploads or registers a dataset version, waits for its audit, then fails the build if the version breaks the project's data contract or the preflight gate is BLOCKED.

With the datacourt-ci command

datacourt-ci is a single file, services/api/datacourt/ci_client.py, and uses only the Python standard library. Copy that file into your pipeline, or install the package, which also installs the full backend dependencies:

export DATACOURT_TOKEN=dct_...            # secret; scope contracts:read
python ci_client.py --api https://<your-app>/api/v1 --dataset-version <dataset-version-id>
# or, after `pip install ./services/api`:
datacourt-ci --api https://<your-app>/api/v1 --dataset-version <dataset-version-id>

Example output:

DataCourt data contract: DataCourt default contract v0
Preflight: BLOCKED  ·  Dataset Debt: HIGH

  [FAIL] Exact duplicate evaluation samples across splits: 12 <= 0
  [FAIL] High/critical leakage findings: 3 <= 0
  [PASS] Smallest class size: 55 >= 30
  [PASS] Unresolved STRONG_REVIEW / POSSIBLE_RELABEL cases: 18 <= 20
  [PASS] Largest / smallest class ratio: 3.1 <= 10
  [PASS] Required splits present: ["test", "train", "val"] includes ["train"]
  [FAIL] Preflight blocking checks: exact_eval_leakage

FAILED

Exit codes: 0 passed · 1 contract failed or preflight BLOCKED · 2 usage, network or API error. Add --json for the raw response.

GitHub Actions example

With ci_client.py copied into your repository as tools/datacourt_ci.py:

- name: DataCourt data contract
  env:
    DATACOURT_TOKEN: ${{ secrets.DATACOURT_TOKEN }}
  run: |
    python tools/datacourt_ci.py --api "${{ vars.DATACOURT_API_URL }}" --dataset-version "${{ vars.DATASET_VERSION_ID }}"

Raw HTTP

curl -fsS -H "Authorization: Bearer $DATACOURT_TOKEN" \
  "https://<your-app>/api/v1/ci/contract?dataset_version_id=<id>"
{
  "passed": false,
  "contract": { "name": "…", "version": 3, "passed": false, "results": [
    { "metric": "exact_cross_split_duplicates", "title": "…", "op": "<=", "expected": 0, "actual": 12, "passed": false }
  ]},
  "preflight": { "status": "BLOCKED", "effective_status": "BLOCKED", "blocking": ["exact_eval_leakage"] },
  "debt": "HIGH",
  "dataset_version_id": "…"
}

passed is true only when every contract rule passes and the effective preflight status (after any admin override) is not BLOCKED.

Contract rules

Contracts are edited per project (Project → Contract & CI) or with PUT /projects/{id}/contract:

{ "name": "Release gate", "rules": [
  { "metric": "exact_cross_split_duplicates", "op": "<=", "value": 0 },
  { "metric": "leakage_findings_high", "op": "<=", "value": 0 },
  { "metric": "min_images_per_class", "op": ">=", "value": 50 },
  { "metric": "quality_issue_rate", "op": "<=", "value": 0.03 },
  { "metric": "debt_level", "op": "<=", "value": "MODERATE" },
  { "metric": "required_splits", "op": "includes", "value": ["train", "test"] }
]}

Metrics: exact_cross_split_duplicates, leakage_eval_samples, leakage_findings_high, min_images_per_class, class_imbalance_ratio, unresolved_strong_review_cases, unresolved_high_priority_cases, quality_issue_rate, duplicate_rate, shortcut_max_cramers_v, unreadable_fraction, debt_level (LOW < MODERATE < HIGH < CRITICAL), required_splits, preflight_status (READY < READY_WITH_WARNINGS < BLOCKED). GET /contract-metrics lists them with descriptions.

Operators: <=, <, >=, >, ==, includes. Every contract change creates a new contract version.

Main endpoints

AreaEndpoints
AuthPOST /auth/register, POST /auth/login, POST /auth/logout, POST /auth/demo, GET /auth/me, DELETE /auth/account
WorkspacesPOST /orgs, GET/PATCH/DELETE /orgs/{id}, members, tokens, GET /orgs/{id}/ledger, /ledger/verify, /security-log, /metrics
ProjectsGET/POST /orgs/{id}/projects, GET /projects/{id}, GET/PUT /projects/{id}/audit-config, PUT /projects/{id}/contract
DatasetsPOST /projects/{id}/datasets, POST /datasets/{id}/versions (returns an upload plan: one presigned PUT, or presigned multipart part URLs), POST /versions/{id}/upload/parts (fresh part URLs), GET /versions/{id}/upload (received parts), POST /versions/{id}/upload/abort, POST /versions/{id}/finalize-upload, POST /versions/{id}/retry-ingest (ingest a failed version again from the archive it stored), GET /versions/{id}, GET /versions/{id}/samples, GET /samples/{id}
AuditsPOST /audits, GET /audits/{id}, /progress, /cancel, /retry, GET /versions/{id}/audit-estimate
FindingsGET /versions/{id}/{overview, quality, duplicates, leakage, labels, rare-or-wrong, shortcuts, coverage, cartography, influence, failures, privacy, debt, preflight, dna, compare}
Court & reviewGET /versions/{id}/cases, GET /cases/{id}, POST /cases/{id}/decision, POST /decisions/{id}/undo, POST /cases/{id}/explain, GET /cases/{id}/counterfactuals, POST /review-budget, review sessions
ExperimentsPOST /what-if, GET /what-if/{id}, GET /what-if/action-types, GET /failures/{id}/blame-map
OutputsPOST /exports, GET /exports/{id}/download, POST /reports, GET /reports/{id}
SystemGET /health, GET /algorithms, GET /ci/contract, GET /jobs/{id} (execution status of a background job)

GET /samples/{id} returns image_url, a short-lived link to a picture browsers can display: the original, or for HEIC/HEIF (which most browsers cannot show) its WebP copy, marked by attributes.browser_copy. original_url downloads the original file, unchanged, under its own name.

Long-running operations (ingestion, audits, What-if runs, exports, reports, contamination checks) return immediately with a queued status and run on a worker (GitHub Actions in the hosted deployment). Poll the resource until it is completed or failed; while it is pending, its job / execution block reports where it stands (waiting: starting_worker, retry_scheduled, dispatch_failed), the worker run's URL, attempts and errors.

Errors and limits

  • Errors are JSON {"detail": "…"} with a conventional status code:
    • 400: invalid confirmation;
    • 401: unauthenticated;
    • 403: role or scope;
    • 404: missing or other tenant;
    • 409: state conflict;
    • 410: expired archive;
    • 422: validation;
    • 429: rate limited.
  • Every response carries X-Request-ID. Include it when reporting a problem.
  • Rate limits: 20 authentication requests per minute, 120 CI requests per minute and 600 other requests per minute, per client.