Audit logs overview
The audit log is the workspace's tamper-evident record of who did what, from where, and whether it worked. It is the endpoint you reach for during a compliance review, an access certification, or a security investigation — and the one you point a SIEM or warehouse at for continuous export.
Every entry names an actor (who), a target (what they acted on), an event (what they did), an outcome (whether it succeeded), and a source (which surface the request came through). Where the event changed something, old_value and new_value carry the before and after.
Audit logs are read-only. There is no way to write, edit, or delete an entry through the API.
The audit log object
Attributes
idstring (uuid)Unique identifier for this audit log record. This is the id you pass to Get an audit log.
event_idstring (uuid)Identifier of the event the record describes, distinct from
id. Use it as the idempotency key when you ingest entries into another system so a re-read never double-counts.sequence_numberintegerAn ordering number assigned to the entry as it was written. Useful as a stable tiebreaker when two entries share the same
created_at.event_namestringThe specific event, for example
member.role_updated. Filterable — this is the field to pin when you know exactly which action you are hunting for.categorystringThe family the event belongs to. One of
auth,member,role,settings,integration,webhook,security, orinstance. Filter oncategorywhen you want a whole class of activity rather than one event name.outcomestringWhether the attempt succeeded. One of
successorfailure. Failed attempts are recorded, which is what makes this useful for detecting probing.sourcestringThe surface the request came through. One of
platform,api,graphql,auth, orsystem.apimarks calls made with a token like yours;systemmarks actions Plane took on its own.actor_typestringWhat kind of principal acted. One of
user,api_token,system, oranonymous.actor_idstring (uuid)The acting user. Nullable —
systemandanonymousactors have no id. It matchesmember_idon the member rosters.actor_display_name,actor_emailstringThe actor's name and email captured at the time of the event. They are snapshots: a later rename or email change does not rewrite past entries.
target_typestringThe kind of thing that was acted on, for example
workspace_member.target_idstringIdentifier of the thing that was acted on.
target_display_namestringA human-readable label for the target, captured at the time of the event.
old_value,new_valueanyThe state before and after the change. Both are nullable — an event that changes nothing, such as a sign-in, carries
nullon both sides.reasonstringA short explanation recorded alongside the event. Most informative on
outcome: failureentries.metadataanyAdditional structured context. The shape varies by
event_name, so read it defensively rather than typing it strictly.ip_addressstringThe client IP the request came from. Nullable —
systemevents have none.user_agentstringThe client's user agent string.
workspace_idstring (uuid)The workspace the event belongs to.
project_idstring (uuid)The project the event is scoped to, when it is scoped to one.
created_atstring (date-time)When the event was recorded. This is the field the date-range filters work on.
{
"id": "5c7f1a08-2b64-4d39-9e17-0a3b8c6d2f41",
"event_id": "e0b41d97-6c23-4a8f-b512-9d7a0e3c5f68",
"sequence_number": 48213,
"event_name": "member.role_updated",
"category": "role",
"outcome": "success",
"source": "platform",
"actor_type": "user",
"actor_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
"actor_display_name": "Priya Raghavan",
"actor_email": "priya@example.com",
"target_type": "workspace_member",
"target_id": "3e8a5d17-9c40-4b2f-81d6-4a7f2b9e0c53",
"target_display_name": "Devansh Kapoor",
"old_value": { "role": "member" },
"new_value": { "role": "owner" },
"reason": "",
"metadata": { "workspace_slug": "my-team" },
"ip_address": "203.0.113.42",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36",
"workspace_id": "d84c6f21-7a30-4e59-b6c8-1f9d5a2e7043",
"project_id": null,
"created_at": "2026-01-14T09:22:41.478363Z"
}{
"id": "9a2c4e76-1f58-4b03-8d69-5e0a7c3b1d24",
"event_id": "b7f3da41-8c05-4e92-a37d-2b6f1c9e5804",
"sequence_number": 48197,
"event_name": "auth.sign_in",
"category": "auth",
"outcome": "failure",
"source": "auth",
"actor_type": "anonymous",
"actor_id": null,
"actor_display_name": "",
"actor_email": "devansh@example.com",
"target_type": "user",
"target_id": "7f2b9e04-6c1d-4a58-9e3b-0d4c8a2f6b71",
"target_display_name": "Devansh Kapoor",
"old_value": null,
"new_value": null,
"reason": "invalid_credentials",
"metadata": { "attempt": 3 },
"ip_address": "198.51.100.7",
"user_agent": "curl/8.6.0",
"workspace_id": "d84c6f21-7a30-4e59-b6c8-1f9d5a2e7043",
"project_id": null,
"created_at": "2026-01-14T08:57:03.220914Z"
}Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v2/workspaces/{slug}/audit-logs/ | List audit logs |
GET | /api/v2/workspaces/{slug}/audit-logs/{pk}/ | Get one audit log |
Both require the workspaces.audit_logs:read scope. There is no POST, PATCH, or DELETE — entries are written by Plane and are not editable by any caller.
Querying for an investigation
The list endpoint takes the filters an investigation actually needs. They combine with AND:
| Question | Query |
|---|---|
| What happened in this window? | ?created_after=2026-01-01T00:00:00Z&created_before=2026-02-01T00:00:00Z |
| What did this person do? | ?actor_id=16c61a3a-512a-48ac-b0be-b6b46fe6f430 |
| Every permission change this quarter | ?category=role&created_after=2026-01-01T00:00:00Z |
| Failed attempts only | ?outcome=failure |
| Everything touching one object | ?target_type=workspace_member&target_id=3e8a5d17-9c40-4b2f-81d6-4a7f2b9e0c53 |
| Activity from one address | ?ip_address=198.51.100.7 |
| One specific action | ?event_name=member.role_updated |
For a full export, add ?paginate=cursor and walk next_cursor — that skips the COUNT(*) on every page and stays stable as new entries arrive. Details on List audit logs.
Reading an entry
- Snapshots, not joins.
actor_display_name,actor_email, andtarget_display_nameare recorded at event time. That is what makes the log evidential — the entry still names the person as they were, even after a rename or an offboarding. - Failures are first-class.
outcome: failureentries are exactly what a security review is looking for. A burst of them from oneip_addresswithcategory: authis the shape of a credential-stuffing attempt. old_valueandnew_valueare free-form. They describe the change for thatevent_nameand are not a fixed schema. Render them, diff them, but do not require particular keys.sourceseparates humans from tokens.platformis the Plane app,apiis a REST client,systemis Plane acting by itself. Combiningsource: apiwithactor_type: api_tokenisolates automation.
Correlate a 409 with a settings change
If clients suddenly start getting 409 work_item_types_managed_at_workspace or work_item_types_managed_at_project, someone toggled the work item type mode. Query ?category=settings around the time the failures started to find the change and the actor behind it. See Work item type modes and Update workspace features.
Related
- List audit logs
- Get an audit log
- Members overview — resolve
actor_idto a person - Pagination — cursor traversal for exports

