> ## Documentation Index
> Fetch the complete documentation index at: https://docs.crewpass.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# Check compliance

> Is a crew member fully certified for their role? Read the role, STCW, and medical breakdown.

Compliance answers one question: **is this crew member fully certified for the role
they hold on this vessel?** CrewPass works that out for you by matching the role's
requirements against the crew member's verified documents — you read the result,
you don't compute it.

<Info>**Requires** `crew:compliance:read`. Authenticated with your API key as a Bearer token over TLS; reads are not signed. It's a read-only `POST` with an empty JSON body.</Info>

## What feeds compliance

Four kinds of requirement are checked, each a row in the matrix with its own
`group`:

* **Medical** (`group: "medical"`) — the ENG1 (or equivalent) seafarer medical:
  status and expiry. CrewPass never exposes the doctor or clinic.
* **STCW basic safety training** (`group: "stcw"`) — the standard safety modules
  (Personal Survival, Fire Prevention, First Aid, Personal Safety…), with a
  per-module `modules[]` breakdown.
* **Certificates** (`group: "certificate"`) — the specific certificates the crew
  member's position requires (e.g. Ship Security Officer, Helideck courses).
* **Qualifications** (`group: "qualification"`) — advanced/rank qualifications and
  endorsements (e.g. Master `<3000GT`, ECDIS, GMDSS), matched from the crew's
  maritime competence profile.

## Get a compliance snapshot

```bash cURL theme={null}
curl -sS "$BASE/api/v2/employers/me/crew/crew_001/compliance-checks" \
  -H "Authorization: Bearer $CPK_KEY" -H "Content-Type: application/json" \
  -d '{}'
```

If a crew member is on more than one of your vessels, add `?vessel_id=<ves_…>`
(from their fleet row) so the check is for the right position.

The response is a single **requirement matrix**: one row per role requirement —
Medical, STCW, each Certificate, each Qualification — with its own `status` and
the document(s) that satisfy it. The `summary` always reconciles (the parts sum
to `total`, and `total` equals the number of rows).

```json Response theme={null}
{
  "crew_unique_id": "crew_001",
  "vessel_id": "ves_draak",
  "position_name": "Captain",
  "as_of": "2026-07-01T12:00:00Z",
  "overall_status": "non_compliant",
  "compliance_source": "live_evaluator",
  "summary": { "total": 4, "met": 2, "expiring": 0, "expired": 1, "missing": 1, "pending": 0 },
  "requirements": [
    { "key": "medical:SEAFARERS_MEDICAL", "group": "medical", "title": "ENG1 Medical Certificate",
      "status": "met", "expiry_date": "2027-01-21", "days_until_expiry": 204, "required": true,
      "satisfied_by": [
        { "document_id": "doc_med", "title": "ENG 1 (Medical Certificate)", "expiry_date": "2027-01-21",
          "download_path": "https://partners.crewpass.co.uk/api/v2/employers/me/crew/crew_001/documents/doc_med/download" }
      ] },
    { "key": "explicit:sso", "group": "certificate", "title": "Ship Security Officer",
      "status": "met", "required": true,
      "satisfied_by": [ { "document_id": "doc_sso", "title": "Certificate of Proficiency as Ships Security Officer", "download_path": "…" } ] },
    { "key": "qualification:II/2", "group": "qualification", "code": "II/2", "title": "Master <3000GT",
      "status": "met", "required": true, "satisfied_by": [] },
    { "key": "certificate:lithium_ion", "group": "certificate", "title": "Lithium-Ion Battery Safety",
      "status": "missing", "required": true, "satisfied_by": [] }
  ]
}
```

### Reading the result

Start with **`overall_status`** (`compliant` · `at_risk` · `non_compliant` · `no_role`),
then work the **`requirements[]`** matrix:

* **`group`** buckets the requirement: `medical` · `stcw` · `certificate` · `qualification`.
* **`status`** is the verdict: `met` · `expiring` · `expired` · `missing` · `pending`.
* **`satisfied_by[]`** is the document(s) that meet it — each with a `document_id`,
  `title`, `expiry_date`, and a ready `download_path` (pass it to the
  [document download](/guides/documents) flow). Empty when the requirement is unmet.
* The STCW basic row carries a `modules[]` breakdown (per-module status).
* **`summary`** gives the counts and always reconciles with the rows.

**`compliance_source`** tells you how the result was produced: `live_evaluator`
(the full matrix incl. certificates + qualifications) or `crewCompliance_fallback`
(STCW + Medical only, used if the evaluation service is briefly unavailable).

The verdict is computed by CrewPass's compliance engine — you read it, you don't
recompute it. A practical "who needs attention" filter: any crew member with
`overall_status` `non_compliant`/`at_risk`, or any requirement whose `status` is
`missing`, `expired`, or `expiring`.

## Next

* [Documents & downloads](/guides/documents) — pull the certificate behind a
  requirement.
* [Webhooks](/webhooks) — get a `crew.compliance.changed` event instead of polling.
