Skip to main content
HoundDog API Documentation

Events

Your account's event log: everything that happened to your parties, certificates, requests and settings, in the same feed the dashboard shows. The log is append-only, so it doubles as a change feed: store the last id you processed and ask for everything after it. Webhooks deliver the same events as they happen (Webhooks).

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

Only customer-visible events are served. Staff-only events never appear here or in webhooks. An event that belongs to one of your individuals is not served.

The event entity

{
  "id": 9120044,
  "event_type": "Vendor Became Compliant",
  "message": "Acme Electric became compliant",
  "details": null,
  "party_id": 191537,
  "certificate_id": 5521,
  "project_id": null,
  "compliance_request_id": 88120,
  "w9_id": null,
  "signing_request_id": null,
  "signing_template_id": null,
  "parent_event_id": null,
  "user_id": null,
  "api_key_id": null,
  "created_at": "2026-10-07T14:03:11Z",
  "links": { "self": "/api/v2/events/9120044", "party": "/api/v2/parties/191537" }
}
Field Meaning
event_type The event's type, from the catalog below. The strings are stable and shared with v1 and webhooks
message A readable sentence
details Structured detail as text, when the event has any. Often JSON; parse it when it parses
party_id, certificate_id, project_id, compliance_request_id What the event is about, where it applies
w9_id The W-9 a W-9 event is about, when the event carries one; null otherwise
signing_request_id, signing_template_id The signing request and its template, for a signing event
parent_event_id The event this one belongs to. The email-health child events (Email Skipped (Suppressed), Email Recipients Skipped) carry no party or request id and link to the send they belong to only through it
user_id The dashboard user who acted, when one did
api_key_id The API key that acted, when one did. Events your own API calls cause carry your key's id

Fields of features your account does not use are present with an empty value.

GET /events

Events in id order, oldest first, in the collection envelope.

Parameter Meaning
event_type[] One or more types
party_id One party's events. Another account's id is 422 validation_failed naming party_id
parent_event_id The children of one event (for example, which recipients of a reminder were skipped because their address is suppressed)
user_id Events a given dashboard user performed (kept from v1)
since_id Events with an id greater than this: the cursor for incremental reads (see the note below the example)
since, until ISO-8601 bounds on created_at
page, per_page See Pagination

The id of one of your individuals as party_id is also 422 naming party_id.

A status sync loop:

GET /api/v2/events?since_id=9120044&event_type[]=Vendor%20Became%20Compliant&event_type[]=Vendor%20Became%20Noncompliant&per_page=200

Repeat with the largest id you received until has_more is false.

since_id is not a lossless cursor: an event's id is assigned when it is written, and a long-running operation can make an event with a lower id visible after you have read past it. Re-poll with an overlap (from an id, or a since time, a few minutes back) and de-duplicate by id.

GET /events/:id

One event. 404 for a staff-only event or another account's event. Also 404 for an event of one of your individuals.

Event types

The full, current list is served by GET /webhook_event_types (Webhook subscriptions): every customer-visible type the app records. Types are never renamed. The ones below are the types this reference relies on.

Parties and compliance

Type When
Party Added A party was created on the dashboard or through v2 (v1 records Vendor Added)
Party Edited A person changed a party. Recorded by: the party edit form on the dashboard; on the party's dashboard page, adding or removing a tag, removing the party from a project and removing one of its insurance requirements; PATCH /parties/:id; and PATCH /parties/:id/contacts/:contact_id when it changes the primary contact's name, email or phone (those are the party's own fields). details lists every changed field with its old and new value (see Edit details). Not recorded when the save changed nothing, nor for imports, integrations, compliance updates or merges, nor when a project edit attaches or detaches parties (the project form, POST and DELETE /projects/:id/parties), which project events cover
Vendor Became Compliant, Vendor Became Noncompliant The party's compliance status flipped
Party Archived, Party Unarchived Party lifecycle actions
Party Paused, Party Unpaused Pausing and resuming outreach
Override Added, Marked Compliant, Override Revoked Approval overrides (Approval overrides)
Certificate Submitted A certificate was received (at upload, before it is processed)
Certificate Processed A certificate's status became Processed: when intake completes its review, when the pipeline automatically processes a state-fund workers' compensation proof, or when a person converts one. Recorded once per transition into Processed (a re-key that leaves the status Processed does not record it again), and never for a certificate the API does not serve (see Certificates: a tax form, for example), so its certificate_id is served when the event is recorded. Its parsed data is now served (see Certificates)
Certificate Rejected A certificate was rejected at intake
Certificate Upload Failed A file sent through a direct upload never reached storage or could not be stored; recorded once, after the upload is given up on. The certificate's download answers 404
Certificate Invalidated, Certificate Restored Certificate invalidation
Project Removed, Project Marked Complete, Project Marked Incomplete, Project Archived, Project Unarchived Project actions
Parties Added to Project, Parties Removed from Project (named with your dashboard's labels, for example Parties Added to Project) A party was attached to or detached from a project (Projects); the event carries project_id and no party_id (the party is named in the message). Not available for webhook subscriptions

Custom fields

Type When
Custom Field Definition Created, Custom Field Definition Updated, Custom Field Definition Archived, Custom Field Definition Restored A custom field definition was created, changed, archived or restored, on the dashboard or through Custom fields. Account-level: no party_id. See Custom field events
Custom Field Definition Deleted Support staff permanently deleted a custom field and its values (never through the API)

Email health

Type When
Vendor Email Bounced, Vendor Email Complaint, Vendor Email Unsubscribed A party's address bounced, complained or unsubscribed; details carries the address and reason
Email Skipped (Suppressed), Email Recipients Skipped A send was dropped (all or some recipients) because an address is suppressed; linked to the send by parent_event_id

Custom field events

The custom field definition events name the field in their message, for example Custom field "Area" updated (name, where it appears) by API key "Sync" (the name after the change). details describes the field in the API's own words (field_type is its API name, applies_to a list, as Custom fields serves them):

{
  "custom_field_id": 12,
  "name": "Area",
  "field_type": "string",
  "applies_to": ["parties", "projects"],
  "show_on_triage_queue": false,
  "changes": [
    { "attribute": "name", "old": "Region", "new": "Area" },
    { "attribute": "applies_to", "old": ["parties"], "new": ["parties", "projects"] }
  ]
}

changes is on Custom Field Definition Updated only (one entry per changed attribute: name, field_type, applies_to, show_on_triage_queue). Custom Field Definition Deleted adds values_removed, the number of values deleted with the field. A record's custom field value changing is not one of these events: on parties it is part of Party Edited.

Edit details

For a Party Edited event, the message names the fields that changed and never their values, for example Name, Contact Email and City changed. details is a JSON-encoded string (parse it) holding an object with one entry per changed field:

{
  "changes": [
    { "key": "name", "name": "Name", "old": "Acme Electric", "new": "Acme Electric LLC" },
    { "key": "email_address", "name": "Contact Email", "old": "[email protected]", "new": "[email protected]" },
    { "key": "insurance_requirement_id", "name": "Insurance Requirement", "old": 12, "new": 15,
      "old_display": "Standard", "new_display": "High Risk" },
    { "key": "tags", "name": "Tags", "old": [3], "new": [3, 5], "old_display": ["Electrical"], "new_display": ["Electrical", "Union"] },
    { "key": "custom_field:12", "name": "Region", "old": null, "new": { "value": "Central", "user_id": null } }
  ]
}
Member Meaning
key A stable key: the party field's name as the API writes it (name, email_address, phone_number, external_id, address, city, insurance_requirement_id, compliance_profile_id, archive_date, note_to_party, ...), insurance_requirement_ids (on accounts with several requirements per party, in place of insurance_requirement_id; with compliance profiles only compliance_profile_id is listed), tags, projects, or custom_field:<id> for a custom field. Four keys exist only on the dashboard form and are neither accepted nor served by the v2 party endpoints: detected_insurance_contact_name, detected_insurance_contact_email, detected_insurance_contact_phone and detected_insurance_producer (the insurance contact read from a certificate)
name The label the dashboard shows, in your account's wording
old, new The value before and after. Text is a string, a blank value is null, a switch is true or false, a date and time is an ISO 8601 UTC timestamp. Requirement, compliance profile, tag and project values are ids (a list of ids, sorted, for tags, projects and insurance_requirement_ids); a custom field is {"value": ..., "user_id": ...} as Parties serves it in custom_fields, or null when it has no value
old_display, new_display Present on id-valued entries only: the names of those ids, in the same order

A custom field counts as changed only when its served value changes. A blank value (empty, or only spaces) is no value, the same rule the parties endpoints use, so saving a blank field again is not a change, and clearing a field shows its old value and null. Contact people, insurance agents and certificate uploads have their own records and are not listed here.

Webhooks

Type When
Webhook Delivery Failing The first failed delivery attempt in a run of failures for a subscription. Names the subscription by id, event type and host only; details carries webhook_subscription_id, event_type, endpoint_host, error and response_code
Webhook Disabled A subscription was disabled because every delivery attempted for 7 days failed. Named the same way; details adds failing_since and last_error
Webhook Test Sent A test delivery was sent with POST /webhook_subscriptions/:id/test. It goes only to the subscription being tested, so it cannot be subscribed to and is not in GET /webhook_event_types

Users and settings

Type When
User Added A user was invited, on the dashboard or through the API
User Updated An API key changed a user's name or tier (PATCH /users/:id); details holds the changed fields as [before, after]
User Removed An API key removed a user (DELETE /users/:id): an unaccepted invitation was deleted or the user was deactivated
Account Settings Updated The account's settings were changed, on the dashboard's Settings page or with PATCH /account; details holds the changes

W-9s

Type When
W9 Request Sent A W-9 request was sent
W9 Submitted The party signed the W-9 online or uploaded a file on the public form
W9 Uploaded Account staff or an API key uploaded the W-9
W9 Submitted from JobTread The W-9 arrived through JobTread
W-9 Requests Exhausted Every W-9 reminder went unanswered (accounts without multi-factor compliance)
W9 Removed A W-9 was deleted

A certificate converted into a W-9 records no W-9 event: its Certificate Submitted already fired, and that certificate id is no longer served once converted. Find such W-9s with GET /w9s?updated_since= (W-9s).

Document signing

Type When
Message Sent A signing email (initial, follow-up or completion) went out
Manual Signing Reminder Sent A signer was reminded
Document Signed by Vendor A party seat signed
Document Signed A seat other than the party's signed
Document Completed Every signer signed, emitted only for documents with more than one recipient, and may be missed or duplicated (a known defect); key on Document Signed by Vendor and the request's status instead
Signing Request Invalidated A request was marked no longer needed
Signing Request Signed After Invalidation A signer completed a request that had already been marked no longer needed
External Signed Document Uploaded A document signed outside the e-signature service was recorded
Signed Document Submitted from JobTread A signed document arrived through JobTread
Automatic Signing Request Generated A signing request was created automatically for an unresponsive party
Signing Requests Exhausted Every signing reminder went unanswered (accounts without multi-factor compliance)

API keys

Type When
API Key Updated A key's w9 grant or rate limit was changed