Skip to main content

Audit logs workflow

GET /api/audit-logs is the read-only integrator trail for one company. It answers who touched a record, through which channel we can prove, and what changed. Authenticate with x-api-key (company key) or a personal employee key / session. Employee keys need audit.view (Administrador by default). Company keys follow the rest of the public API: full-company access, no RBAC list on the key itself.

Tenant scope

Every row is filtered by audit_logs.company_id on that row (FS-03). The actor email is never used to pick the tenant. Rows with a null company_id (unresolved / pre-remediation) are hidden. internal_impersonation is hidden. A companyId query or body parameter is ignored.

Filters

When the caller has a scoped client role, only Operation and Transaction rows that pass the same visibility rules as GET /api/operations are returned. Other entities are omitted.

What each field is derived from

Action mapping

  • create: INSERT
  • delete: DELETE, or UPDATE that sets deleted_at
  • cancel: status became adjusted from a status other than completed (typical pending cancel)
  • revert: status completed → adjusted
  • update: any other UPDATE
Creating a counterpart operation (public POST /api/operations/{id}/revert) is not a first-class audit action. It shows up as create on the counterpart and, when legs are adjusted, cancel / revert on those transactions.

Operations list and detail

GET /api/operations and GET /api/operations/{id} add:
  • created_by: actor of the Operation INSERT audit row
  • cancelled_by: actor of the latest transaction status change to adjusted
  • channel / channel_detail: same draft lookup as the audit list
Those lookups are batched by the page of operation ids (not N+1). The list still reads BigQuery; the actors come from Postgres.

Mesas actors

opened_by, closed_by, and created_by stay integer employee ids (null for company API-key writes). When the id is present, the response also includes opened_by_actor / closed_by_actor / created_by_actor as { id, name }.

Known gaps

  • Channel is not a column on audit_logs. Dashboard vs personal API key vs company key vs cron cannot be distinguished on historical rows. Those values stay null instead of being guessed.
  • Company x-api-key writes usually have changed_by = null (no audit email on the request).
  • Email is the only stored actor key. It is returned so integrators can map people. It is the business employee email, not an AuthUser password, token, or session field.
  • Rows written before schema 62 may have a null company_id until the hand-run remediation in schema/62_audit_logs_remediate_company_id.sql is applied.

Permission

audit.view is seeded to Administrador only (schema/67_public_audit_permission.sql). Operators do not receive it unless an admin grants it.