Acessing Audit Data
Audit entries provide a detailed record of changes made to entities within the Salsa platform. As a partner, you can query audit entries for your employers to track modifications, monitor activity, and maintain compliance records.
Authorization
To query audit entries, you'll need to authenticate using your API credentials. See our authorization documentation for details on obtaining and using access tokens.
GraphQL Query
The auditEntries query allows you to retrieve audit logs with various filtering and sorting options. This query returns paginated results with information about who made changes, what was changed, and when.
Query Signature
auditEntries(
page: Int = 0
size: Int = 500
filterBy: AuditEntriesFilterBy
orderBy: AuditEntriesOrderBy! = { field: AUDIT_TIMESTAMP, sort: ASCENDING }
): AuditEntryConnection!Available Fields
Here is the complete list of fields available on an AuditEntry:
| Field | Type | Description |
|---|---|---|
id | ID! | Unique identifier for the audit entry |
partner | Partner | The partner associated with the audit entry (if relevant) |
employer | Employer | The employer associated with the audit entry (if relevant) |
worker | Worker | The worker associated with the audit entry (if relevant) |
auditTimestamp | DateTime! | Timestamp of when the audited event occurred (UTC) |
entityId | ID! | The ID of the entity that was changed |
entityType | String! | Type of entity (e.g., "Worker", "Employer", "PayrollRun") |
parentEntityId | ID | ID of the parent entity, if applicable |
parentEntityType | String | Type of the parent entity, if applicable |
actor | AuditActor! | Who performed the action (see Actor Types below) |
action | String! | High-level action performed (e.g., "CREATE", "UPDATE", "DELETE") |
event | String | Detailed description of what changed, including old and new values |
entity | String! | Full representation of the change |
httpRequest | AuditHttpRequest! | Details about the API request that triggered the change |
Actor Types
The actor field tells you who performed the action. It can be one of three types:
AuditUser (a human user):
| Field | Type | Description |
|---|---|---|
type | AuditActorType! | Always USER |
displayName | String! | Display name of the actor |
securityRole | String! | Role of the user |
userIdentifier | String | Unique identifier of the user |
userEmail | String | Email address of the user |
AuditApiClient (an API client):
| Field | Type | Description |
|---|---|---|
type | AuditActorType! | Always API_CLIENT |
displayName | String! | Display name of the actor |
securityRole | String! | Role of the API client |
apiClient | String! | Name of the API client |
userIdentifier | String | User identifier provided by the API client, if any |
AuditSystem (system-initiated):
| Field | Type | Description |
|---|---|---|
type | AuditActorType! | Always SYSTEM |
displayName | String! | Display name of the actor |
securityRole | String! | Security role |
userIdentifier | String | User identifier, typically empty for system actions |
HTTP Request Details
The httpRequest field tells you where the action originated:
| Field | Type | Description |
|---|---|---|
traceId | String! | Unique API request ID for the change |
requestId | String | Request ID supplied by the partner |
ipAddress | String | IP address that triggered the change |
origin | String | Origin of the request (null for server-to-server) |
requestUrl | String | The original request URL |
Available Filters
| Filter Field | Type | Description |
|---|---|---|
entityType | String | Filter by entity type (e.g., "Worker", "Employer") |
workerId | String | Filter by worker ID |
auditTimestamp | BoundedDateTimeIntervalInput | Filter by date range (see below) |
Date Range Filter
The auditTimestamp filter accepts a bounded date range:
auditTimestamp: {
start: DateTime! # When the interval starts (required)
end: DateTime! # When the interval ends (required)
}Sorting Options
You can sort results using the orderBy parameter:
| Field | Allowed Values |
|---|---|
field | AUDIT_TIMESTAMP, ACTION, PARTNER_ID, EMPLOYER_ID, WORKER_ID |
sort | ASCENDING, DESCENDING |
Default: { field: AUDIT_TIMESTAMP, sort: ASCENDING }
Example Queries
Basic Query: Get Recent Audit Entries for an Employer
query GetAuditEntries($filterBy: AuditEntriesFilterBy, $page: Int, $size: Int) {
auditEntries(filterBy: $filterBy, page: $page, size: $size) {
nodes {
id
auditTimestamp
entityId
entityType
action
event
entity
}
totalPages
}
}Variables:
{
"filterBy": {
"auditTimestamp": {
"start": "2024-11-01T00:00:00Z",
"end": "2024-11-30T23:59:59Z"
}
},
"page": 0,
"size": 25
}Query with Actor Details: See Who Made Changes
query GetAuditEntriesWithActor($filterBy: AuditEntriesFilterBy, $page: Int, $size: Int) {
auditEntries(filterBy: $filterBy, page: $page, size: $size) {
nodes {
id
auditTimestamp
entityId
entityType
action
event
actor {
type
displayName
securityRole
... on AuditUser {
userIdentifier
userEmail
}
... on AuditApiClient {
apiClient
userIdentifier
}
}
}
totalPages
}
}Query for Specific Entity Type: Track Worker Changes
query GetWorkerAuditEntries($filterBy: AuditEntriesFilterBy, $page: Int, $size: Int) {
auditEntries(filterBy: $filterBy, page: $page, size: $size) {
nodes {
id
auditTimestamp
action
event
entity
worker {
id
firstName
lastName
}
actor {
type
displayName
}
}
totalPages
}
}Variables:
{
"filterBy": {
"entityType": "Worker",
"auditTimestamp": {
"start": "2024-11-01T00:00:00Z",
"end": "2024-11-30T23:59:59Z"
}
},
"page": 0,
"size": 25
}Query with Full Request Context
query GetAuditEntriesWithContext($filterBy: AuditEntriesFilterBy, $page: Int, $size: Int) {
auditEntries(filterBy: $filterBy, page: $page, size: $size) {
nodes {
id
auditTimestamp
entityId
entityType
parentEntityId
parentEntityType
action
event
entity
actor {
type
displayName
securityRole
}
httpRequest {
traceId
requestId
ipAddress
requestUrl
}
}
totalPages
}
}Understanding Changes (Old vs New Values)
The event field contains a human-readable description of the change, often including the old and new values. For example:
"Worker.Updated: email changed from '[email protected]' to '[email protected]'"
The entity field contains the full representation of the change in a structured format.
Example Response
{
"data": {
"auditEntries": {
"nodes": [
{
"id": "auditentry_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"auditTimestamp": "2024-11-15T14:32:10Z",
"entityId": "wkr_12345678-90ab-cdef-1234-567890abcdef",
"entityType": "Worker",
"action": "UPDATE",
"event": "Worker.Updated: email changed from '[email protected]' to '[email protected]'",
"entity": "{\"id\":\"wkr_12345678\",\"email\":\"[email protected]\",\"previousEmail\":\"[email protected]\"}",
"actor": {
"type": "API_CLIENT",
"displayName": "partner-api-client",
"securityRole": "PARTNER_ADMIN",
"apiClient": "partner-api-client",
"userIdentifier": "[email protected]"
},
"httpRequest": {
"traceId": "trace_98765432-10fe-dcba",
"requestId": "req_98765432",
"ipAddress": "192.168.1.1",
"requestUrl": "/graphql"
}
}
],
"totalPages": 5
}
}
}Pagination
The auditEntries query uses page-based pagination:
| Parameter | Type | Default | Description |
|---|---|---|---|
page | Int | 0 | Page number (zero-indexed) |
size | Int | 500 | Number of entries per page (max 500) |
The response includes totalPages to help you determine how many pages of results exist.
Example: Paginating Through Results
First page:
{
"filterBy": { "entityType": "PayrollRun" },
"page": 0,
"size": 25
}Second page:
{
"filterBy": { "entityType": "PayrollRun" },
"page": 1,
"size": 25
}Continue incrementing page until you reach totalPages - 1.
Common Use Cases
1. Track All Changes to a Specific Worker
{
"filterBy": {
"workerId": "wkr_12345678-90ab-cdef-1234-567890abcdef"
}
}2. Find All Changes in a Date Range
{
"filterBy": {
"auditTimestamp": {
"start": "2024-11-01T00:00:00Z",
"end": "2024-11-30T23:59:59Z"
}
}
}3. Track Payroll Run Changes
{
"filterBy": {
"entityType": "PayrollRun"
}
}4. Track Worker Changes in a Date Range
{
"filterBy": {
"workerId": "wkr_12345678-90ab-cdef-1234-567890abcdef",
"auditTimestamp": {
"start": "2024-11-01T00:00:00Z",
"end": "2024-11-30T23:59:59Z"
}
}
}Audit Coverage
This section describes which actions generate audit entries and which do not.
Currently Audited Entities
The following entity types and actions will generate audit entries:
| Module | Entity | Actions |
|---|---|---|
| Money Movement | Employer bank account | CREATE, UPDATE, DELETE |
| Worker bank account | CREATE, UPDATE, DELETE | |
| Employer money movement policy | CREATE, UPDATE | |
| Pay distribution | CREATE, UPDATE | |
| Profile | Employer taxes setup | CREATE, UPDATE, DELETE |
| Worker taxes setup | CREATE, UPDATE, DELETE, OVERRIDE | |
| Worker address | CREATE, UPDATE, TERMINATE | |
| Worker contract | CREATE, UPDATE, DELETE | |
| Worker work location | ADD, UPDATE, REMOVE | |
| Employer address | CREATE, UPDATE, DELETE | |
| Payroll | Payroll run | RUN, CONFIRM, CANCEL, DELETE, UPDATE, CONVERT_TO_MANUAL_DISBURSEMENT |
| Worker payroll run | CREATE | |
| Payroll run workers list | INCLUDE, EXCLUDE | |
| Worker payroll element | UPDATE | |
| Worker pay distribution | UPDATE | |
| Partner payroll settings | CREATE, UPDATE, DELETE | |
| Accounting | Partner accounting settings | CREATE, UPDATE, DELETE |
| Transmission | RTS transmission requirement eligibility | EVALUATE |
Not Currently Audited
The following changes do not generate audit entries:
- Worker primary data: firstName, lastName, displayName, email, employerSpecifiedIdentifier, partnerExternalId
- Employer primary data: name, displayName, legal name
- Worker personal information: dateOfBirth, pronouns, gender
Why Some Changes Don't Appear in the Audit Log
Salsa uses an explicit audit logging system where only specific entities and actions are configured for auditing. If you make a change that doesn't appear in the audit log (such as updating a worker's name), it's because that particular entity or action is not currently included in audit coverage.
This approach:
- Keeps audit logs focused on high-value compliance and financial data
- Reduces noise from frequent, low-risk changes
- Optimizes query performance for compliance reporting
If you require audit coverage for additional entities or actions, please contact Salsa support to discuss your requirements.
Updated about 15 hours ago
