Skip to main content

FRIA

A FRIA is a Fundamental Rights Impact Assessment under EU AI Act Article 27 — the artefact a deployer of a high-risk (Annex III) AI system must complete before putting the system into use. The FRIA carries its own SHA-256 chain anchor (chainHash) that is separate from the Decision Hash Chain. One FRIA per high-risk AI system; wizard-driven on the dashboard, API-callable for deployer-side automation. Tested against API version v1. JWT auth on every endpoint; plan-gated by friaWizard (Governance and above).

The FRIA object

FieldTypeRequiredDescription
_id / idstringyesMongoDB ObjectId
organizationIdstringyesOwning org
systemNamestringyesThe high-risk AI system this FRIA covers
deployerProfileIdstringnoReference to the org's Deployer Profile
purposestringnoWizard section — intended purpose of the system
affectedPersonsstringnoCategories of natural persons affected (Art. 27(1)(a))
usageContextstringnoOperational context for the deployment
durationOfUsestringnoExpected operational period
identifiedRisksRisk[]noStructured array of risk rows; see schema below
humanOversightSummarystringnoArt. 14 oversight measures
complaintsMechanismstringnoAffected-person complaint channel
statusenumnodraft (default), review, approved, archived
approvedBystringnoUser ObjectId of the approver
approvedAtstring (ISO 8601)noSet on approval
chainHashstringnoSHA-256 anchor over canonical FRIA contents at submission
createdAt / updatedAtstring (ISO 8601)noStandard timestamps

Risk sub-document

FieldTypeRequiredDescription
titlestringyesShort risk label
descriptionstringnoRisk narrative
likelihoodenumnolow, medium (default), high
severityenumnolow, medium (default), high
affectedRightsstring[]noCharter / fundamental-rights references
mitigationstringnoCounter-measure narrative
residualRiskenumnolow, medium (default), high after mitigation

The dashboard's wizard collapses two free-text fields (risksIdentified, mitigations) into a synthetic single-row risk array on save; structured API consumers should send identifiedRisks directly to keep the per-row severity and likelihood signals.

State machine

            ┌────────────────────────────────────────────┐
│ draft ── /submit ──▶ review │
│ ▲ │ │
│ │ ▼ │
│ └───── /transition ── approved │
│ │ │
│ ▼ │
│ archived │
└────────────────────────────────────────────┘

The wizard's submit step writes the FRIA's chainHash — a SHA-256 over the canonicalised assessment contents at the moment of submission. The hash is the reviewer's signature anchor and persists across subsequent edits in review state (the chain detects post-submission tampering).

Endpoints

GET    /api/v1/fria
POST /api/v1/fria
GET /api/v1/fria/:id
PATCH /api/v1/fria/:id
POST /api/v1/fria/:id/transition
POST /api/v1/fria/:id/submit
POST /api/v1/fria/:id/approve
DELETE /api/v1/fria/:id

/submit and /approve are aliases that call the unified /transition handler with a fixed target status (review and approved respectively). Use them when integrating with the wizard; use /transition for state changes that don't fit the draft→review→approved wizard path (for example, rolling an approved FRIA back to draft for a re-assessment).

List FRIAs

GET /api/v1/fria
Query parameterDescription
statusFilter by draft / review / approved / archived
searchSubstring on systemName
limitPage size; capped server-side
curl
curl "https://api.adjudon.com/api/v1/fria?status=approved" \
-H "Authorization: Bearer $ADJUDON_API_KEY"
Python
import os, requests
r = requests.get(
"https://api.adjudon.com/api/v1/fria",
params={"status": "approved"},
headers={"Authorization": f"Bearer {os.environ['ADJUDON_API_KEY']}"},
)

Errors: 401, 403 UPGRADE_REQUIRED, 500 FRIA_LIST_FAILED.

Create a FRIA

POST /api/v1/fria

Creates a new FRIA in draft status. systemName is required; every other field is optional and can be filled in via subsequent PATCH calls as the wizard progresses.

curl
curl -X POST https://api.adjudon.com/api/v1/fria \
-H "Authorization: Bearer $ADJUDON_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"systemName": "Underwriter v1 — credit screening",
"purpose": "Screen retail loan applications under €50,000",
"affectedPersons": "Retail credit applicants in DACH region"
}'
Python — full structured create
fria = {
"systemName": "Underwriter v1 — credit screening",
"purpose": "Screen retail loan applications under €50,000",
"affectedPersons": "Retail credit applicants in DACH region",
"usageContext": "Online application form; downstream of KYC",
"durationOfUse": "Continuous; reviewed annually",
"identifiedRisks": [
{
"title": "Disparate-impact risk",
"description": "Model under-approves applicants from low-income postal codes",
"likelihood": "medium",
"severity": "high",
"affectedRights": ["non-discrimination", "right to good administration"],
"mitigation": "Quarterly fairness audit + Review Queue thresholds",
"residualRisk": "low"
}
],
"humanOversightSummary": "All denials below confidence 0.7 land in Review Queue",
"complaintsMechanism": "[email protected] — 30-day SLA"
}
import os, requests
r = requests.post(
"https://api.adjudon.com/api/v1/fria",
json=fria,
headers={"Authorization": f"Bearer {os.environ['ADJUDON_API_KEY']}"},
)

Errors: 401, 403, 500 FRIA_CREATE_FAILED.

Get one FRIA

GET /api/v1/fria/:id

Returns the FRIA with a completeness score (the controller's projection helper computes a 0–100 percentage of populated wizard fields). Errors: 401, 404 NOT_FOUND, 500 FRIA_GET_FAILED.

Update a FRIA

PATCH /api/v1/fria/:id

Partial update of any wizard section. Permitted in draft and review states; an approved FRIA must transition back to draft before further edits.

curl — extend mitigation
curl -X PATCH https://api.adjudon.com/api/v1/fria/65b1f2c4 \
-H "Authorization: Bearer $ADJUDON_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "humanOversightSummary": "Updated to add SLA on Review Queue: 24h." }'

Errors: 401, 404, 500 FRIA_UPDATE_FAILED.

Submit (draftreview)

POST /api/v1/fria/:id/submit

Transitions the FRIA from draft to review and writes chainHash. Equivalent to POST /transition with body: { status: "review" }.

curl
curl -X POST https://api.adjudon.com/api/v1/fria/65b1f2c4/submit \
-H "Authorization: Bearer $ADJUDON_API_KEY"

Errors: 400 FRIA_TRANSITION_FAILED (illegal current state), 401, 404, 500.

Approve (reviewapproved)

POST /api/v1/fria/:id/approve

Transitions the FRIA to approved and stamps approvedBy and approvedAt. Equivalent to POST /transition with body: { status: "approved" }. The chain hash is re-anchored on approval so the approved artefact is independently verifiable.

Errors: 400 FRIA_TRANSITION_FAILED, 401, 404, 500.

Generic transition

POST /api/v1/fria/:id/transition
Body fieldRequiredDescription
statusyesTarget status: draft, review, approved, or archived
curl — archive an approved FRIA
curl -X POST https://api.adjudon.com/api/v1/fria/65b1f2c4/transition \
-H "Authorization: Bearer $ADJUDON_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "archived" }'

Errors: 400 VALIDATION_ERROR (missing status), 400 FRIA_TRANSITION_FAILED (state-machine rejected), 401, 404, 500.

Delete a FRIA

DELETE /api/v1/fria/:id

Hard-deletes a FRIA — permitted only on draft records that have never been submitted. Approved or archived FRIAs cannot be deleted; the operations audit-log entry on fria.delete would remain by Cardinal Rule 5 in any case.

Errors: 401, 404 NOT_FOUND (also returned when the FRIA exists but is not deletable), 500 FRIA_DELETE_FAILED.

Common gotchas

  • Plan-gate. The whole resource requires the friaWizard feature. Sandbox and Scale plans receive 403 UPGRADE_REQUIRED.
  • Two chains. The FRIA chainHash is separate from the Decision Hash Chain. Verifying a FRIA does not require pulling the trace chain export. See Audit Log & Security for the two-chain split.
  • Dashboard vs structured payload. The wizard sends risksIdentified + mitigations text fields; the API consumer contract is identifiedRisks[] with structured rows. The controller collapses the former into a single synthetic Risk Summary row. Send identifiedRisks directly to preserve per-row likelihood / severity / affected-rights data.
  • State-machine transitions. Submitting requires draft; approving requires review; archive can be reached from any state. A rejected attempt returns 400 FRIA_TRANSITION_FAILED.
  • Approved FRIA edits. Direct PATCH against an approved record is rejected; transition back to draft first, edit, re-submit. The chain hash is re-anchored on each approval.

See also