User Profile Histories
Papershift exposes a single audit timeline for an employee’s personnel file. It
merges field edits (profile_change) and read-access attempts (profile_view)
into one list ordered by time (via a server-side UNION ALL). Prefer this
endpoint for History UIs that need correct pagination across both event types.
Valid Attributes
Section titled “Valid Attributes”| Attribute | Description | Specifics |
|---|---|---|
| entry_type | Which source table the row comes from. | profile_change or profile_view |
| user_id | The ID of the user whose file the event concerns. | |
| actor_id | The ID of the user who performed the action. | |
| actor_email | The email of the actor at that time. | Denormalized, does not change |
| created_at | When the event was recorded. | |
| field_group | Field group for a change. | Present when entry_type is profile_change, otherwise null |
| field_name | Field name for a change. | Present when entry_type is profile_change, otherwise null |
| value | Before/after values for a change. | Present when entry_type is profile_change, otherwise null |
| action_type | Kind of change: updated, uploaded or deleted. |
Present when entry_type is profile_change, otherwise null |
| area | Personnel file area for a view. | Present when entry_type is profile_view, otherwise null |
| field_count | How many fields were involved in a view. | Present when entry_type is profile_view, otherwise null |
| access_denied | Whether a view attempt was refused. | Present when entry_type is profile_view, otherwise null |
Relationships
| Relationship | Description |
|---|---|
| user | The user whose file the event concerns |
| actor | The user who performed the action (if still resolvable) |
Example response:
{ "data": [ { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "type": "profile_history", "attributes": { "entry_type": "profile_view", "user_id": "b7f8d3a9-6c5e-4e5c-9d8f-7b6c96d4e3c2", "actor_id": "c2d3e4f5-6789-0abc-def1-234567890abc", "actor_email": "jane.doe@example.com", "area": "master_data", "field_count": 28, "access_denied": false, "field_group": null, "field_name": null, "value": null, "action_type": null, "created_at": "2026-01-15T10:00:00.000Z" } }, { ... } ]}This endpoint returns the merged profile history for a user. Results are not
sorted by default; use sort=-created_at to get the most recent events first.
HTTP Request
Section titled “HTTP Request”GET /api/v1/users/:user_id/profile_histories
URL Parameters
Section titled “URL Parameters”| Parameter | Description |
|---|---|
| user_id | The ID of the user whose profile history to return. |
Filtering
Section titled “Filtering”In addition to the standard filter syntax, this endpoint supports filtering by actor, entry type, change-specific fields, view-specific fields, and a date range:
Filter by actor IDs:
GET /api/v1/users/:user_id/profile_histories?filter[actor_id]=in:actor-id-1,actor-id-2
Filter by entry type:
GET /api/v1/users/:user_id/profile_histories?filter[entry_type]=eq:profile_view
Filter by action type (changes only; views have
nulland are excluded):GET /api/v1/users/:user_id/profile_histories?filter[action_type]=in:uploaded,deleted
Filter by field name (changes only; views have
nulland are excluded):GET /api/v1/users/:user_id/profile_histories?filter[field_name]=eq:City
Filter by field group (changes only):
GET /api/v1/users/:user_id/profile_histories?filter[field_group]=eq:Address
Filter by area (views only):
GET /api/v1/users/:user_id/profile_histories?filter[area]=eq:master_data
Filter by access denied (views only):
GET /api/v1/users/:user_id/profile_histories?filter[access_denied]=eq:false
Filter by a date range (combine both bounds as needed):
GET /api/v1/users/:user_id/profile_histories?filter[created_at_gteq]=2026-01-01&filter[created_at_lteq]=2026-01-31
This endpoint’s results are paginated, see the pagination section for details.
Authorization uses the same account right as profile changes:
profile_change.read.
A user who holds audit_relevant_data.read on the account (and may read the
user) but not profile_change.read gets a narrower history of another user:
only profile changes about the fields and documents the account marks as audit
relevant at the time of the request, with their full values. Profile views are
never part of it, neither granted nor denied ones and not the user’s own, and
the same applies to any entry that is not about a field or a document. Entries
outside that set are not returned and not counted, and when the account marks
nothing as audit relevant the list is empty.
An entry belongs to the field or document it was recorded for, so renaming a field or document keeps its history, and deleting a field removes its history from this view.