TrustLayer Webhooks

Webhooks let you receive real-time notifications from the TrustLayer platform whenever specific events occur. Configure endpoints, subscribe to events, and react to changes in your data as they happen.

Contact TrustLayer Support
support@trustlayer.io
License Apache 2.0
https://apache.org/licenses/LICENSE-2.0
Terms of Service https://trustlayer.io/terms-of-service
OpenAPI specification /webhooks/webhooks-api.yaml

Webhooks Overview

 

The Current webhooks model is the supported shape for all new integrations. It uses a generic object / record terminology that extends safely beyond Parties and Projects to any custom entity you define in TrustLayer.

Notifications are delivered via HTTP POST to a URL you register, carrying a JSON payload that describes the event and the records it applies to. The endpoint management API is shared with the legacy model — see Managing webhooks for how to register, list, and delete webhooks.

Request headers

Each delivery is an HTTP POST with the following headers:

Header Value
Content-Type Always application/json. Cannot be overridden.
User-Agent Defaults to TrustLayer-Webhooks/<version>. The version reflects the platform release that delivered the event and may change over time — do not match against a specific value. Can be overridden via workspace-configured custom headers.
X-Hmac-Hash Sent only when an HMAC secret is configured for your workspace. Contains the HMAC-SHA256 of the JSON body, hex-encoded. Use it to verify request authenticity. Cannot be overridden.

Workspace administrators can configure additional custom headers (for example, Authorization: Bearer …) that are appended to every delivery. Custom headers may override User-Agent but cannot replace Content-Type or X-Hmac-Hash.

If your endpoint sits behind a WAF or bot-protection service, make sure it does not block requests based on the User-Agent value — legitimate webhook deliveries always carry one, and rules that filter unknown agents will reject them.

Terminology

TrustLayer models your data as a small set of generic entities. Each entity comes in two layers: the object (the schema) and the record (an individual instance).

Concept Description Example object
Primary record The subject of most events (e.g. a vendor you’re tracking). Party
Context record Scopes or groups primary records for a given use case. Project
Request record Connects a primary record with an optional context record, and tracks compliance for that pair. Party on Project link

Every event references at least one object / record pair, so consumers always know both what kind of thing changed and which instance it was.

Common payload shape

All current events include the following top-level fields:

{
  "workspaceId": "ID of your TrustLayer workspace",
  "eventType": "The event type identifier (see lists below)"
}

Legacy events use organizationId instead of workspaceId. The underlying value is the same — the field name changed to match the rest of the platform.

Events that reference a primary entity add:

{
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" }
}

Events that reference a context entity add:

{
  "contextObject": { "id": "...", "name": "Project" },
  "contextRecord": { "id": "...", "name": "North Campus" }
}

Events that reference a request entity always carry the primary pair, and optionally carry the context pair:

{
  "requestObject": { "id": "...", "name": "Project-Party" },
  "requestRecord": { "id": "...", "name": "Acme @ North Campus" },
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "contextObject": { "id": "...", "name": "Project" },
  "contextRecord": { "id": "...", "name": "North Campus" }
}

The .name field on a record is optional — it may be absent when the record has no display name yet (for example, a primary record created as a stub before enrichment).

Primary record events

Fired when a primary record is created, updated, or transitions state.

Identifier Description
primary_record:created A new primary record was created
primary_record:updated An existing primary record changed
primary_record:deleted A primary record was deleted
primary_record:activated A primary record was reactivated (unarchived)
primary_record:archived A primary record was archived

Payload:

{
  "workspaceId": "...",
  "eventType": "primary_record:created",
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" }
}

Primary record tag events

Fired when a tag is attached to or removed from a primary record.

Identifier Description
primary_record:tag:added A tag was added to a primary record
primary_record:tag:removed A tag was removed from a primary record

Payload: primary record payload plus a tag object.

{
  "workspaceId": "...",
  "eventType": "primary_record:tag:added",
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "tag":           { "id": "...", "name": "high-risk" }
}

Primary record attribute events

Fired when a custom-field value on a primary record is set, changed, or cleared. Each individual attribute change produces one delivery — bulk edits produce one event per changed attribute.

Identifier Description
primary_record:attribute:updated A custom field on a primary record changed

Payload: primary record payload plus an attribute delta with the new and previous value.

{
  "workspaceId": "...",
  "eventType": "primary_record:attribute:updated",
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "attribute": {
    "id":   "...",
    "name": "Region",
    "value":         { "value": "EMEA" },
    "previousValue": { "value": "NA"   }
  }
}
Field Description
attribute.id ID of the custom field whose value changed.
attribute.name Display name of the custom field.
attribute.value The new value. Omitted when the field is being cleared.
attribute.previousValue The prior value. Omitted when the field had no value before.
value.value / previousValue.value The literal value (string or number). For dropdown / option-typed fields, the option’s display value.
value.optionId / previousValue.optionId Set for dropdown / option-typed fields. The id of the chosen option.

Primary record message events

Fired for conversation-level email activity tied to a primary record. Payloads are metadata only — message bodies and attachments are never delivered through webhooks.

Identifier Description
primary_record:message:sent A message was sent to a primary record
primary_record:message:received A message was received from a primary record’s contact
primary_record:message:failed Delivery of a message failed (bounce, invalid address, etc.)

The payload shape varies by sub-type.

primary_record:message:sent

{
  "workspaceId": "...",
  "eventType": "primary_record:message:sent",
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "conversationId": "...",
  "conversationSubject": "Certificate of insurance renewal",
  "senderEmail": "ops@yourcompany.example",
  "senderName": "Jane Operator",
  "recipients": ["insurance@acme.example"]
}

primary_record:message:received

{
  "workspaceId": "...",
  "eventType": "primary_record:message:received",
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "conversationId": "...",
  "conversationSubject": "Re: Certificate of insurance renewal",
  "senderEmail": "insurance@acme.example",
  "senderName": "Acme Insurance"
}

primary_record:message:failed

{
  "workspaceId": "...",
  "eventType": "primary_record:message:failed",
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "contactEmail": "insurance@acme.example",
  "reason": "Mailbox does not exist"
}

reason is best-effort and may be omitted if the upstream provider did not report one.

Context record events

Fired when a context record (e.g. a Project) is created, updated, or transitions state.

Identifier Description
context_record:created A new context record was created
context_record:updated A context record changed
context_record:deleted A context record was deleted
context_record:activated A context record was activated
context_record:archived A context record was archived

Payload:

{
  "workspaceId": "...",
  "eventType": "context_record:created",
  "contextObject": { "id": "...", "name": "Project" },
  "contextRecord": { "id": "...", "name": "North Campus" }
}

Context record attribute events

Fired when a custom-field value on a context record is set, changed, or cleared. Each individual attribute change produces one delivery. Date-typed values are normalized to ISO 8601 strings on the wire.

Identifier Description
context_record:attribute:updated A custom field on a context record changed

Payload: context record payload plus an attribute delta with the new and previous value.

{
  "workspaceId": "...",
  "eventType": "context_record:attribute:updated",
  "contextObject": { "id": "...", "name": "Project" },
  "contextRecord": { "id": "...", "name": "North Campus" },
  "attribute": {
    "id":   "...",
    "name": "StartDate",
    "value":         { "value": "2026-01-01T00:00:00.000Z" },
    "previousValue": { "value": "2025-12-01T00:00:00.000Z" }
  }
}

The attribute object follows the same shape as in Primary record attribute events. Date-typed custom fields are delivered as ISO 8601 strings.

Request record events

Fired when the link between a primary record and an (optional) context record is created, updated, or transitions state. A request record without a context represents a global requirement on a primary record.

Identifier Description
request_record:created A request record was created (e.g. a party was added to a project)
request_record:updated A request record changed
request_record:deleted A request record was deleted (e.g. a party was removed from a project)
request_record:activated A request record was activated
request_record:archived A request record was archived

Payload:

{
  "workspaceId": "...",
  "eventType": "request_record:created",
  "requestObject": { "id": "...", "name": "Project-Party" },
  "requestRecord": { "id": "...", "name": "Acme @ North Campus" },
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "contextObject": { "id": "...", "name": "Project" },
  "contextRecord": { "id": "...", "name": "North Campus" }
}

contextObject and contextRecord are omitted when the request record is not scoped to a context.

Request record attribute events

Fired when a custom-field value on a request record is set, changed, or cleared. Each individual attribute change produces one delivery — bulk edits produce one event per changed attribute.

Identifier Description
request_record:attribute:updated A custom field on a request record changed

Payload: request record payload plus an attribute delta with the new and previous value.

{
  "workspaceId": "...",
  "eventType": "request_record:attribute:updated",
  "requestObject": { "id": "...", "name": "Project-Party" },
  "requestRecord": { "id": "...", "name": "Acme @ North Campus" },
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "contextObject": { "id": "...", "name": "Project" },
  "contextRecord": { "id": "...", "name": "North Campus" },
  "attribute": {
    "id":   "...",
    "name": "Status",
    "value":         { "optionId": "...", "value": "Approved" },
    "previousValue": { "optionId": "...", "value": "Pending"  }
  }
}

contextObject and contextRecord are omitted when the request record is not scoped to a context. The attribute object follows the same shape as in Primary record attribute events.

Primary record document events

Fired when a document is associated with a primary record. This is the v2 event for the document-to-primary-record relationship; it dispatches alongside the legacy document:assigned:to:party.

Metadata-only. Webhook payloads never carry document file contents, binary data, or storage keys. Fetch the document via the REST API using document.id.

Identifier Description
document:primary_record:assigned A document was assigned to a primary record

Payload — v2 common envelope plus primaryRecord, document, and the acting user’s identity. Unlike other primary-record events, primaryObject is not included.

{
  "workspaceId": "...",
  "eventType": "document:primary_record:assigned",
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "document":      { "id": "...", "name": "policy.pdf" },
  "userName": "Jane Operator",
  "userEmail": "jane@yourcompany.example"
}
Field Description
primaryRecord.id ID of the primary record (for example, the Party) the document was assigned to.
primaryRecord.name Display name of the primary record. Always present and non-empty — falls back to "Unknown" when the source has no name.
document.id ID of the assigned document.
document.name File name of the assigned document. May be an empty string.
userName Name of the user who performed the assignment. Empty string for system / automated actors.
userEmail Email of the user who performed the assignment. Empty string for system / automated actors.

Triggers. Fires whenever a document is attached to a primary record — through the UI, a document upload that resolves to a known primary record, or the REST API. Bulk assignments produce one webhook delivery per (document, primaryRecord) pair, not a single batched payload. Reassigning a document to a different primary record fires a new event for the new target.

Parallel legacy dispatch. Every successful document-to-primary-record assignment also fires the legacy document:assigned:to:party event. Legacy dispatch is best-effort: it is wrapped in a guard so that a legacy delivery failure cannot block the v2 event or the underlying assignment. Both events follow at-least-once delivery semantics, the same as every other webhook.

v1 → v2 field mapping

For integrations migrating from the legacy document:assigned:to:party event:

Legacy (document:assigned:to:party) Current (document:primary_record:assigned)
organizationId workspaceId
partyId primaryRecord.id
partyName primaryRecord.name (always present; falls back to "Unknown")
documentId document.id
documentName document.name
userName userName
userEmail userEmail

Request record compliance events

Fired when the compliance status of a request record changes. The score is always an integer from 0 to 100.

Identifier Description
request_record_compliance:changed The compliance score of the request record changed
request_record_compliance:reached The request record reached full compliance
request_record_compliance:lost The request record fell out of compliance

Payload: the request record payload plus compliance fields.

{
  "workspaceId": "...",
  "eventType": "request_record_compliance:reached",
  "requestObject": { "id": "...", "name": "Project-Party" },
  "requestRecord": { "id": "...", "name": "Acme @ North Campus" },
  "primaryObject": { "id": "...", "name": "Party" },
  "primaryRecord": { "id": "...", "name": "Acme Construction" },
  "contextObject": { "id": "...", "name": "Project" },
  "contextRecord": { "id": "...", "name": "North Campus" },
  "prevSubjectsComplianceScore": 80,
  "subjectsComplianceScore": 100,
  "subjectsCount": 5,
  "compliantSubjectsCount": 5
}
Field Description
prevSubjectsComplianceScore Score immediately before this event. Omitted on first evaluation.
subjectsComplianceScore Current compliance score (0–100).
subjectsCount Total number of subjects evaluated on the request record.
compliantSubjectsCount Number of those subjects currently compliant.

Full event list

Identifier Category
primary_record:created Primary record
primary_record:updated Primary record
primary_record:deleted Primary record
primary_record:activated Primary record
primary_record:archived Primary record
primary_record:tag:added Primary record — tag
primary_record:tag:removed Primary record — tag
primary_record:attribute:updated Primary record — attribute
primary_record:message:sent Primary record — message
primary_record:message:received Primary record — message
primary_record:message:failed Primary record — message
document:primary_record:assigned Primary record — document
context_record:created Context record
context_record:updated Context record
context_record:deleted Context record
context_record:activated Context record
context_record:archived Context record
context_record:attribute:updated Context record — attribute
request_record:created Request record
request_record:updated Request record
request_record:deleted Request record
request_record:activated Request record
request_record:archived Request record
request_record:attribute:updated Request record — attribute
request_record_compliance:changed Compliance
request_record_compliance:reached Compliance
request_record_compliance:lost Compliance

Wildcards are supported when subscribing — e.g. primary_record:* matches every primary record event, including tag and message events.

 

Webhooks Overview

 

Webhooks allow third-party developers to be notified whenever a specific event occurs on the TrustLayer platform. Notifications are performed via HTTP POST calls to a provided endpoint URL, carrying with them a payload with the relevant data.

You can set up webhooks either via the UI (in the Settings→TrustLayer API pane), or via API calls (with more precise control).

Request headers

Each delivery is an HTTP POST with the following headers:

Header Value
Content-Type Always application/json. Cannot be overridden.
User-Agent Defaults to TrustLayer-Webhooks/<version>. The version reflects the platform release that delivered the event and may change over time — do not match against a specific value. Can be overridden via workspace-configured custom headers.
X-Hmac-Hash Sent only when an HMAC secret is configured for your workspace. Contains the HMAC-SHA256 of the JSON body, hex-encoded. Use it to verify request authenticity. Cannot be overridden.

Workspace administrators can configure additional custom headers (for example, Authorization: Bearer …) that are appended to every delivery. Custom headers may override User-Agent but cannot replace Content-Type or X-Hmac-Hash.

If your endpoint sits behind a WAF or bot-protection service, make sure it does not block requests based on the User-Agent value — legitimate webhook deliveries always carry one, and rules that filter unknown agents will reject them.

The payload that is sent with each webhook notification will have some common attributes:

{
  "organizationId": "The id of your organization",
  "eventType": "The type identifier of the event (see list below)"
}

Most webhooks are relative either to a party or a project (or both). In this case the payload will carry these properties:

{
  "partyId": "Id of the affected party",
  "partyName": "Name of the party",
  "projectId": "Id of the affected project",
  "projectName": "Name of the project"
}

For tag-related events, these attributes are included:

{
  "tagId": "Id of the affected tag",
  "tagName": "Name of the tag"
}

For document-related events, these attributes are supported (not all of them will be present at all times):

{
  "documentId": "Id of the affected document",
  "documentName": "Name of the document",
  "documentReviewed": "Boolean flag, true if the document was reviewed",
  "flagSeverityLevel": "Either 'low', 'medium' or 'high'",
  "flagNotes": "Text entered in the flag notes",
  "verificationNotes": "Text entered in the verification notes"
}

For document:assigned:to:party, the payload includes the acting user’s identity:

{
  "userName": "Name of the user who performed the assignment",
  "userEmail": "Email of the user who performed the assignment"
}

Both fields are empty strings for system or automated actors. Document file contents are never delivered through webhooks — fetch the document through the REST API using documentId.

Compliance-related events always carry this attribute:

{
  "complianceScore": "Numeric value representing the score of the compliance status (0-100)"
}

Currently, these events are supported:

Identifier Description
comment:created A new comment was added to the activity timeline
party:created A new party was created
party:updated A change was made to an existing party
party:deleted A party was deleted
party:tag:added A tag was added to a party
party:tag:removed A tag was removed from a party
project:created A new project was created
project:updated A change was made to an existing project
project:deleted A project was deleted
project_compliance:lost Project-level compliance is no longer satisfied
project:activated A project was activated
project:inactivated A project was inactivated
project:party_added A party was added to a project
project:party_removed A party was removed from a project
party_compliance:changed The compliance score of a party changed
party_compliance:reached A party’s global compliance is satisfied
party_compliance:lost A party’s global compliance is no longer satisfied
project_compliance:changed A party’s project-level compliance score changed
project_compliance:reached A party’s project-level compliance is satisfied
document:uploaded A document was uploaded
document:processed A document was processed
document:reviewed A document was reviewed
document:archived A document was archived
document:flagged A flag was added to a document
document:verified A document was verified
document:flag_removed A flag was removed from a document
document:verification_removed A verification was removed from a document
document:deleted A document was deleted
document:assigned:to:party A document was assigned to a party
 

Managing webhooks

 

You can create a webhook via the public API:

curl -XPOST -H"Authorization: Bearer ${token}" \
    --data '{ \
      "id": "webhook_id", \
      "namespace": "my_app", \
      "url": "https://my-app.example.com/notify", \
      "events": ["party:created", "party:updated"], \
      "enabled": true
     }' \
    https://api.trustlayer.io/v1/webhooks
  • The namespace parameter can be whatever you want, but the "trustlayer" value is reserved for internal use.
  • The url parameter needs to be unique relative to the namespace; if you perform a second POST request using the same values, you will overwrite the existing webhook
  • The events parameter is a list of the events you’re interested in; they can also be specified using wildcards (e.g. "party:*") to express interest for a whole class of events. Finally, if you specify an empty list, your endpoint will be notified for all events.
  • The enabled parameter can be omitted, and it will default to true.

Note that webhooks created via the API will not be displayed in the platform Settings page. You can list these webhooks via a GET request:

curl -XGET -H "Authorization: Bearer ${token}" https://api.trustlayer.io/v1/webhooks

You can also delete a webhook via the API:

curl -XDELETE
    -H "Authorization: Bearer ${token}" \
    https://api.trustlayer.io/v1/webhooks/webhook_id

Where webhook_id is the unique identifier of the webhook you want to delete as defined in the POST response:

{
  "id": "webhook_id",
  "namespace": "my_app",
  "url": "https://my-app.example.com/notify",
  "events": ["party:created", "party:updated"],
  "enabled": true
}
 

TrustLayer Webhooks — Legacy management API

Legacy REST endpoints for managing webhook subscriptions and organization-level webhook settings. Retained for backwards compatibility. All requests are made against https://api.trustlayer.io/v1 with a valid API token in the Authorization: Bearer header.

 

Webhooks

 

GET /webhooks

List webhooks

List webhook subscriptions.

Available filters:

  • namespace
https://api.trustlayer.io/v1/webhooks?filter[namespace]=value

Query Parameters

filter[namespace] optional

Filter webhooks by namespace.

Responses

200 OKContent-Type: application/json{"data":[{"id":"string","type":"string","namespace":"string","url":"string","events":["string"],"enabled":"boolean","createdAt":"string"}

],"status":"string","meta":{"count":"number","pages":"number","totalCount":"number","totalPages":"number"}

}

POST /webhooks

Create a webhook

Create a webhook subscription.

  • namespace may be any value you choose, but the value trustlayer is reserved for internal use.
  • url must be unique within a namespace. Re-posting with the same namespace + url overwrites the existing webhook.
  • events accepts event identifiers or wildcards (for example party:*). An empty list subscribes to all events.
  • enabled defaults to true.
https://api.trustlayer.io/v1/webhooks

Request Body

Content-Type: application/json{"webhook":{"namespace":"string","url":"string","events":["string"],"enabled":"boolean"}

}

Responses

200 OKContent-Type: application/json{"status":"string","data":{"id":"string","type":"string","namespace":"string","url":"string","events":["string"],"enabled":"boolean","createdAt":"string"}

}

Settings

 

GET /settings/webhooks

Fetch webhooks settings

Returns the organization-level settings for webhooks.

https://api.trustlayer.io/v1/settings/webhooks

Responses

200 OKContent-Type: application/json{"status":"string","data":{"headers":[{"name":"string","value":"string"}

]}

}

PUT /settings/webhooks

Update webhooks settings

Updates the organization-level settings for webhooks. Custom headers configured here are appended to every webhook delivery.

https://api.trustlayer.io/v1/settings/webhooks

Request Body

Content-Type: application/json{"settings":{"headers":[{"name":"string","value":"string"}

]}

}

Responses

200 OKContent-Type: application/json{"settings":{"headers":[{"name":"string","value":"string"}

]}

}

Models

 

webhook

id string
type string
namespace string
url string
events array
enabled boolean
createdAt string

Webhook settings

headers array