Skip to main content
CrewPass pushes a webhook to your registered endpoint when data about a crew member on your fleet changes — so you don’t have to poll. Delivery is asynchronous, signed, retried with backoff, and dead-lettered after repeated failure. You receive an event only for a crew member on your fleet, only for an event whose scope you hold, and only when that crew member’s consent allows it — the same gate as the read surface.

How it works

CrewPass continuously watches the data behind your fleet. When something relevant changes — a certificate finishes verifying, compliance flips, a status or profile updates — CrewPass builds the matching event and delivers it to the callback URL you registered. There is nothing to run on your side beyond an HTTPS endpoint that accepts a POST, verifies the signature, and returns 2xx. Two things worth knowing:
  • You don’t poll. Events are pushed in near-real-time off CrewPass’s own change feed; you react to them.
  • Delivery is at-least-once. The same event may arrive more than once (e.g. after a retry), so deduplicate on event_id.

Subscribing

Webhook registration is not self-serve. Ask your CrewPass contact to register your callback URL and the events you want; they set it up for you during onboarding, or whenever you need it changed. CrewPass then issues a webhook signing secret used to sign every delivery (this is separate from your API key; reads are not signed).

The envelope

Every delivery is a JSON body with this shape:
And these headers:

Signature scheme

The webhook signature signs the timestamp, a dot, then the raw request body bytes ("{timestamp}." + body), with no nonce. Build your receiver’s verification against exactly that string.

Verifying a delivery

Python
Node

Receiver requirements

  1. Verify the signature against the raw bytes.
  2. Deduplicate on event_id — delivery is at-least-once, so the same event may arrive more than once.
  3. Respond 2xx quickly and process asynchronously.
  4. Anything else is retried with exponential backoff (up to 8 attempts), then dead-lettered. A 4xx (other than 408/429) is treated as a permanent rejection and not retried.

Event catalogue (v1)

crew.document.processed / crew.document.updated

crew.compliance.changed

crew.status.changed

crew.profile.updated

Reacting to an event

Every payload carries a crew_unique_id: the join key between CrewPass and your own records. You learn it once, store it against your own crew record, then use it to look up the detail behind any event. Discover a crew member’s crew_unique_id once, then keep it:
  • GET /api/v2/employers/me/fleet returns the fleet roster, where every crew member arrives with their crew_unique_id.
  • POST /api/v2/employers/me/crew/lookup resolves a single known crew member to their crew_unique_id.
From then on, an event’s crew_unique_id tells you exactly which of your records changed. An event is a signal, not a full snapshot: the document events carry their metadata inline, and for the others you call the matching read endpoint to fetch the current detail. crew.document.processed and crew.document.updated. The payload already has the document metadata (type, category, issuer, verification status, issue and expiry dates, document number). To fetch the file, call GET /api/v2/employers/me/crew/{crew_unique_id}/documents/{document_id}/download and follow the download_url it returns; that link is short-lived, so use it straight away rather than storing it. Both crew_unique_id and document_id come from the event payload.
Document events fire on verification completion (processingStatus.overall == "completed"), not on raw upload. Expect a short delay between a crew member uploading a certificate and the matching event arriving.
crew.compliance.changed. The payload is a summary (overall status plus the requirement counts). For the full role, STCW, and medical breakdown, call POST /api/v2/employers/me/crew/{crew_unique_id}/compliance-checks. The overall_status values (compliant, at_risk, non_compliant, no_role) mean the same here as on the compliance read. crew.profile.updated. The event is a change signal, not a diff: it tells you the profile changed, not what changed. Call GET /api/v2/employers/me/crew/{crew_unique_id}/profile to read the current profile. crew.status.changed. The payload carries the new verification_status and background_check_status directly, so update your own record straight from the payload. No follow-up read is required.
Background-check status uses CrewPass’s standardised, provider-agnostic vocabulary.