Skip to main content
The Fairness API computes group-fairness metrics (demographic parity, disparate-impact ratio, four-fifths rule, equal-opportunity and equalized-odds gaps) over either caller-supplied samples or a slice of decision traces joined to a protected attribute. Every evaluation writes an AuditLog row for EU AI Act traceability. Both endpoints are tenant-scoped (authenticate with an API key or session). They are not role-gated. They are rate limited per tenant and fail closed.

POST /api/v1/fairness/evaluate

Compute a fairness report. Rate limit: 20 requests / 60 s.

Query parameters

ParameterValuesDefaultDescription
metricsbasic, advancedbasicadvanced adds intersectional analysis, mitigation recommendations, per-group Gini and KS tests, and (with a modelKey) counterfactual + LIME analysis.

Request body

A discriminated union on mode, plus optional advanced auto-run fields. Inline mode — pass samples directly:
{
  "mode": "inline",
  "samples": [
    { "group": "A", "prediction": true, "label": true },
    { "group": "B", "prediction": false, "label": true }
  ]
}
FieldTypeRequiredDescription
mode"inline"YesSelects inline mode.
samples[].groupstringYesProtected-group label.
samples[].predictionbooleanYesWhether the customer got a positive decision.
samples[].labelbooleanNoGround-truth label (enables equal-opportunity / equalized-odds).
samples[].intersectionalGroupsobjectNo{ axis: value } map for advanced intersectional analysis.
samples[].attributesobjectNoFeature map used for counterfactual + LIME when metrics=advanced and a modelKey is supplied.
Trace-join mode — pull decision traces in a window and match by customer:
{
  "mode": "trace-join",
  "from": "2026-06-01T00:00:00Z",
  "to": "2026-07-01T00:00:00Z",
  "offerId": "off_...",
  "groupLookup": { "cust_1": "A", "cust_2": "B" },
  "labelLookup": { "cust_1": true },
  "maxTraces": 5000
}
FieldTypeRequiredDescription
mode"trace-join"YesSelects trace-join mode.
from / tostring (ISO-8601)YesTrace window.
offerIdstringNoPositive = this offer was selected. Omitted = any offer selected.
groupLookupobjectYescustomerId → group map.
labelLookupobjectNocustomerId → boolean ground-truth map.
intersectionalLookupobjectNocustomerId → { axis: value } map.
maxTracesinteger (1-20000)NoCap on traces scanned. Default 5000.
Advanced auto-run fields (only used with metrics=advanced): modelKey, modelGroupKey, counterfactualGroup, limeBaseline, limeOptions ({ samples, seed }).

Response 200

{
  "groups": [
    { "group": "A", "count": 120, "positiveRate": 0.62 },
    { "group": "B", "count": 118, "positiveRate": 0.41 }
  ],
  "demographicParityGap": 0.21,
  "disparateImpactRatio": 0.66,
  "fourFifthsRuleViolated": true,
  "equalOpportunityGap": 0.18,
  "equalizedOddsGap": 0.2,
  "warnings": ["disparate impact ratio 0.66 below the 0.8 four-fifths threshold"],
  "sampleSize": 238,
  "meta": { "mode": "inline", "sampleCount": 238, "metricsTier": "basic" }
}
When metrics=advanced, the response may also include intersectional, mitigations, giniByGroup, ksByGroup, counterfactualFairness, and lime. Any advanced primitive that could not run (e.g., no modelKey, no intersectional groups) is listed by reason in advancedAwaitingConfig.

Errors

CodeReason
400Request body failed validation.
429Rate limit exceeded (20 / 60 s per tenant).
500Trace-join query failed.

POST /api/v1/fairness/report

Run the same evaluation and return a formatted EU AI Act conformity report instead of JSON. Rate limit: 10 requests / 60 s.

Request body

The same inline / trace-join body as /evaluate, plus:
FieldTypeDefaultDescription
format"csv", "html""html"Output format.
titlestring (max 200)Report title (HTML only).
subtitlestring (max 300)Report subtitle (HTML only).

Response 200

  • format: "csv"text/csv attachment (fairness-report-<ts>.csv).
  • format: "html"text/html document, suitable for headless-Chromium PDF rendering.
Not a JSON response. A fairness_report audit-log row is written on every generation so it is discoverable in DSAR exports.