Audit log
PerSQL records consequential actions to two append-only audit logs. Together they answer “who changed X?” — whether X is a table, a member’s role, or an API token.
| Log | Scope | What it records | Where to find it |
|---|---|---|---|
| Namespace audit | namespace | Database CRUD, member/role changes, invitations, tokens, settings, billing | Sidebar → Audit log |
| DDL audit | per database | Every schema-changing SQL statement | Database → Migrations tab |
Namespace audit log
Section titled “Namespace audit log”A single append-only feed across the whole namespace, surfaced under Audit log in the sidebar. Visible to owners and admins only.
What gets recorded
Section titled “What gets recorded”| Action | Notes |
|---|---|
database.created / .deleted / .forked | Plus branched, branch_reset, branch_deleted |
namespace.updated | Display-name changes |
namespace.member_role_changed / .member_removed | |
invitation.created / .revoked / .accepted | |
token.created / .revoked | |
endpoint.created / .published / .unpublished / .deleted | |
schedule.created / .deleted | |
policy.created / .updated / .deleted | RLS policies |
billing.checkout_started | Stripe top-up Checkout session opened |
Each row carries:
action— the dotted identifier aboveactorUserId/actorTokenId— who did it (one or the other)actorIp—cf-connecting-ipat the timetargetType/targetId— what was acted onmetadata— JSON blob with action-specific context (slug, role, etc.)createdAt— when PerSQL recorded the row
curl --cookie cookies.txt \ "https://api.persql.com/api/namespaces/acme/audit?limit=200&action=token.created"Query parameters:
limit— up to 500, default 100before— ISO timestamp; pagination cursoraction— exact-match filter on the action key
Response is an array ordered newest-first, with the actor’s
{ id, name, email } joined in for convenience.
Retention
Section titled “Retention”The namespace audit log is append-only and currently retained indefinitely. Reach out if you need an export or a pruning policy.
DDL audit log
Section titled “DDL audit log”The DDL audit log is per-database and records every schema-changing statement against that database. It lives on the Migrations tab next to the diff panel.
What gets recorded
Section titled “What gets recorded”Anything matching the schema-DDL classifier:
CREATE(table, index, view, trigger)ALTERDROPTRUNCATEREINDEXVACUUMATTACH/DETACH
Captured fields:
| Field | Notes |
|---|---|
sqlText | First 4 000 chars |
status | ok or error |
errorMessage | First 500 chars, only on error |
userId | Set if the statement came via cookie auth |
tokenId | Set if the statement came via bearer auth |
createdAt | When PerSQL recorded the row |
Exactly one of userId / tokenId is populated; both being null
means the statement came from internal machinery (e.g. import
applying SQL inside the DO without a per-statement caller).
Sources
Section titled “Sources”The audit log captures DDL from every path:
/api/.../query(console query box)/v1/.../queryand/v1/.../batch(bearer token)/migrations/:id/apply(the Migrations tab)/importand/load-csv(the bulk loaders) — recorded asokonce the underlying transaction succeeds
Retention
Section titled “Retention”- Per-database cap: 1 000 rows.
- Cron prune runs alongside the slow-query prune (~10 % of minute ticks). Older rows fall off as new ones land.
curl --cookie cookies.txt \ "https://api.persql.com/api/namespaces/acme/databases/orders/audit?limit=200"Response is an array of { id, sqlText, status, errorMessage, userId, tokenId, createdAt } ordered newest-first.