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 |