Skip to main content
HoundDog API Documentation

Requirement statuses

One row per party, per scope, per requirement: each required coverage. Under multi-factor compliance, also the W-9 and each signing template. Each row says whether that one requirement is satisfied, waived, missing, lapsed or deficient, and why. The scope is the party itself or one of its projects.

Before you build on these. Both endpoints answer 501 not_implemented until requirement statuses are enabled on the service, and then start answering with no change on your side; see "Available when enabled" below.

Operation Scope
GET /parties/:id/requirement_statuses read
GET /requirement_statuses read

Available when enabled. These endpoints answer 501 not_implemented on an environment where per-requirement statuses are not enabled. This is a property of the service, not of your account.

Things to know

  • Rows are read-only; the API never writes them.
  • W-9 and signing rows exist on multi-factor compliance accounts only.
  • Rows of archived parties are frozen as they were at archiving. Parties archived before the feature launched have no rows at all, so lifecycle[]=archived returns only parties archived since.
  • Rows can lag the party's own status until its next recompute, so the party entity's summary and these rows may briefly disagree. A row is current as of the party's last recompute or the daily recheck; status_since and changed_at say when it last changed.
  • changed_at moves only when a row's content changes: a recompute that changes nothing writes nothing.
  • Rows are deleted when a requirement no longer applies: the party's requirement changes, its compliance profile changes, it is detached from a project, or it reaches No Requirements. changed_since never reports a deletion, and many causes of one (an edit to a requirement, a project completing) record no event, so reconcile a stored copy with a periodic full re-read; GET /parties/:id/requirement_statuses refreshes a party you already know changed.
  • Pages are offsets over rows ordered by changed_at. A row that changes during your read moves to the front and can be repeated (de-duplicate by id); a row that leaves the result during your read (deleted, its party archived or paused, or no longer matching your filters) shifts later rows up, so an unchanged row can be skipped. An overlapping changed_since recovers the first case, not the second: re-read the same window until two passes agree, or rely on the periodic full re-read.
  • A lifecycle change does not move changed_at: when a party becomes active again (completed, unpaused, unarchived) its rows return to the default list with their old changed_at. Pass every lifecycle[] you track, or refresh such parties with the per-party list.
  • Which lifecycle applies: GET /parties/:id/requirement_statuses serves the named party's rows whatever its lifecycle (as GET /parties/:id serves the party); GET /requirement_statuses applies lifecycle[], active by default.
  • The rows of your individuals are never served.

The requirement status entity

{
  "id": 700145,
  "party_id": 191537,
  "scope": { "type": "party", "id": 191537 },
  "factor": "insurance",
  "requirement_key": "gl",
  "status": "deficient",
  "waiver_source": null,
  "evidence_status": null,
  "reason_codes": ["limits"],
  "failures": [
    { "certificate_field": "gl_limits_each_occurance", "requirement_field": "gl_per_occurance_minimum", "required": 1000000, "carried": 500000, "message": "General Liability each occurrence limit is below the required $1,000,000" }
  ],
  "insurance_requirement_ids": [42],
  "governing_insurance_requirement_id": 42,
  "certificate_id": 5521,
  "approval_override_id": null,
  "expires_on": "2027-03-01",
  "lapsed_on": null,
  "status_since": "2026-10-07T14:03:11Z",
  "recheck_at": null,
  "changed_at": "2026-10-07T14:03:11Z",
  "links": { "party": "/api/v2/parties/191537", "certificate": "/api/v2/certificates/5521" }
}
Field Meaning
scope {"type": "party" or "project", "id"}
factor insurance
requirement_key For insurance, a coverage prefix such as gl
factor w9 and document_signing The other compliance factors: requirement_key is w9 for the W-9 and signing:<template id> for a signing template
status satisfied, waived, missing, lapsed or deficient
waiver_source, evidence_status, reason_codes Why the status is what it is
failures The recorded failures as stored: certificate_field is the compliance engine's own key (it includes synthetic keys such as auto_subtype_or_check and <prefix>_present, and custom coverage keys), not a path into the certificate entity; carried is what the certificate showed
insurance_requirement_ids, governing_insurance_requirement_id The requirements that apply, and the one that decided the status
certificate_id, approval_override_id The evidence
expires_on, lapsed_on, status_since, recheck_at, changed_at Dates: expires_on is when the evidence ends (null when it has no end), lapsed_on when a lapsed requirement's last valid evidence ended, status_since when the row entered its current status, recheck_at the next moment the status can change on its own, changed_at when the row last changed
links Related paths: always party; certificate when the row names one; insurance_requirement for the governing requirement; project for a project scope; signing_template for a signing row. They are paths, not a promise that the key can read them: a certificate that /certificates excludes answers 404, and a project path answers 403 feature_disabled while projects are off

GET /parties/:id/requirement_statuses

The party's rows, whatever the party's lifecycle (an archived party's rows are frozen as they were at archiving), ordered by scope, factor and requirement key. Filters: scope_type (party or project) and scope_id; scope_id needs scope_type (400 otherwise). An individual's id, or an id from another account, is 404.

GET /requirement_statuses

Rows across the account, most recently changed first (changed_at descending, then id descending).

Parameter Meaning
status[], requirement_key[], factor Row filters; each array matches any of its values
party_id One party's rows. An individual's id, or an id from another account, is 422
project_id The rows scoped to one project (only project-compliance accounts have them). Needs projects on the account (403 feature_disabled otherwise); an id from another account is 422
lifecycle[] The party's lifecycle, as on GET /parties. When lifecycle[] is omitted, active applies even when other filters (status[], party_id, project_id and the rest) are given; send every lifecycle you want to widen it
expires_before, expires_after expires_on strictly before, or strictly after, the date (YYYY-MM-DD). A row with no end date matches neither
lapsed_since lapsed_on on or after the date
changed_since changed_at at or after the time (ISO-8601)
page, per_page See Pagination

For example, the requirements failing for active parties, most recently changed first:

GET /api/v2/requirement_statuses?status[]=missing&status[]=lapsed&status[]=deficient&per_page=200

And the satisfied coverage that expires before April 1, 2027:

GET /api/v2/requirement_statuses?status[]=satisfied&expires_before=2027-04-01