- The Log of the Organization, every write to any of its Entities and to the data the Organization shares, filtered by Entity if you like:
GET /api/organizations/:organizationId/audit-trail. - The Actividad of one record, its own history:
GET /api/entities/:entityId/audit-trail.
books read in the Organization. Both return the same page shape.
The Log moved from the Entity to the Organization.
GET /api/entities/:entityId/audit-trail now requires tableName and rowId. To list every write of an Entity, call the Organization route with entityIds.List the Organization Log
GET /api/organizations/:organizationId/audit-trail
Returns a paginated page of the Organization’s audit envelopes, plus the named resources needed to render them without extra lookups. Writes that belong to no Organization never appear.
With no filter, the page lists every envelope of the Organization. That includes the envelopes of Organization routes that name no Entity, such as a Partner merge or a Dimension change. Those have entityId set to null, and the app labels them Empresa.
Query params
How the Entity filter matches
Send
entityIds, includeOrganizationEnvelopes, or both, to narrow the Log:
- An envelope matches an Entity when it names that Entity, or when it changes a row of that Entity. For example, a Partner merge names no Entity, but it shows under each Entity whose rows it changed.
- Inside a matched envelope, the changes to rows of Entities you didn’t select are hidden. Changes to rows the whole Organization shares, such as a Partner, always show.
- A row that moved between two Entities shows under both.
- With
includeOrganizationEnvelopes=true, the envelopes that name no Entity also match.
entityIds answers 404 with ENTITY_NOT_FOUND_ERROR.
List the history of one record
GET /api/entities/:entityId/audit-trail
Returns the audit envelopes that changed one row of the Entity, the same history the Actividad tab of a record shows in the app. An envelope never shows a change to another Entity’s rows.
Query params
Accepted
tableName values
The trail records changes to the tables of the books and the records around them, for example ledger_entry, ledger_entry_line, invoice, invoice_attachment, attachment, partner, partner_alias, partner_bank_details, entity_partner, bank_movement, bank_movement_attachment, bank_account, reconciliation_allocation, fixed_asset, fixed_asset_class, fixed_asset_depreciation_entry, intercompany_entry, expense_claim, and task. Any string is accepted; one that names no audited row matches nothing.
Some parents also pull in their child rows: tableName=ledger_entry returns changes to that entry and to its ledger_entry_line rows; tableName=invoice returns changes to that invoice and to its invoice_attachment links; tableName=bank_movement returns changes to that movement and to its bank_movement_attachment links; tableName=partner returns changes to that Partner, its partner_alias rows, its entity_partner links, and the Partners merged into it. The invoice and bank movement histories also carry the attachment rows of the files linked in the same request. For tableName=partner_bank_details, pass the Partner’s id as rowId. For an Expense Rendition, tableName=invoice also returns the history of the Expense Claim it came from: who submitted it and who approved it.
Response
Both routes answer200 with this page:
Each envelope:
Each change:
Keys inside
before, after, and rowPrimaryKey are the stored column names in snake_case (for example entry_date, partner_id), not the camelCase names used elsewhere in the API.
namedResources carries the display facts of exactly the resources the page’s envelopes point at, so a feed can render names without further lookups:
A resource that no longer exists is absent from these lists; treat an id you cannot resolve as unknown.
What the trail captures
The audit trail is row-level and automatic: every write is recorded by the database itself, so no endpoint can skip it. Every mutating request produces one Audit Envelope grouping its Audit Changes:- Actor:
actorUserIdplus the name and role the authenticated user had at the write. A deleted user keeps that name and role in the trail, and the Log shows (eliminado) after their name. - Credential type:
sessionfor browser sessions,api_keyfor API key requests,systemfor changes made by Sintropix itself - Declared actor: the value of the
x-audit-actorheader on API-key mutations (stored as a claim, not a verified identity). Changes Erwin makes while a person chats with him in the app carryerwin, with that person as the actor. A Source Feed sync that writes the Standing or Tax Period of a landed DTE carriessource-feed, credited to the system. - Declared reason: the value of the
x-audit-reasonheader (trimmed, up to 500 characters) explaining why the change was made; required on API-key mutations, optional on browser sessions - Declared trigger: the value of the optional
x-audit-triggerheader (stored as a claim), naming what started the agent turn behind the write. Every write Erwin makes carries the trigger of his turn:schedulewhen a schedule started it, orslack,app,chat, orterminalwhen a person’s message there started it. An envelope whosedeclaredActorstarts witherwinand whosedeclaredTriggerisscheduleis a change Erwin made on his own - Request id: a server-generated unique id grouping all changes in one request
- Route and HTTP method: the endpoint that produced the mutation, or the scheduled job that made it
- Entity id: the entity scope the change occurred within
- Diff: for inserts and deletes, the full row image; for updates, only the columns that moved with before and after values
Scheduled jobs
Some changes are made by Sintropix on a schedule, with no request behind them. Their envelopes carrycredentialType: "system", and route and method name the job instead of an endpoint:
A sync you start on demand keeps the route and method of that request.

