Audit
Read tenant audit records and the resource details attached to each event
Set variables to auto-fill all examples and run requests in-browser.
Audit in the Console records tenant activity. Use these endpoints through the main API at https://api.laserdata.cloud for programmatic access. Records are appended without changing earlier entries.
The audit log and its event types require audit:read. Deployment activity can also be read with deployment:activity:read, for the environments where the caller holds it.
Event Types
List Audit Event Types
GET/audit/typesList all supported audit event type identifiers.
curl https://api.laserdata.cloud/audit/types \
-H "ld-api-key: YOUR_API_KEY"Audit Log
Query Tenant Audit Log
GET/audit/tenants/{tenant_id}Query the full audit log for a tenant, with filtering and pagination.
curl "https://api.laserdata.cloud/audit/tenants/{tenant_id}?page=1&results=10" \
-H "ld-api-key: YOUR_API_KEY"{
"items": [
{
"type": "deployment_created",
"name": "Deployment Created",
"author": { "id": 608123456789012345, "name": "Jane Smith" },
"api_key": { "id": 67890, "name": "ci-deploy-key" },
"user": null,
"division": { "id": 615380456123456790, "name": "Platform Engineering" },
"environment": { "id": 615380456123456791, "name": "production" },
"deployment": { "id": 611298765432109056, "name": "events-prod" },
"data": {
"cloud": "aws",
"area": "us",
"region": "us-east-1",
"variant": "managed",
"tier": "large",
"cluster_kind": "standalone",
"public_ip": "static",
"storage_type": "network_balanced",
"storage_size": 500,
"target_network_tput": 10000,
"encrypted": true,
"protected": true,
"retention": { "telemetry": { "logs_days": 90, "metrics_days": 90, "heartbeats_days": 90 } },
"code": "abc123",
"name": "events-prod",
"domain": "events-prod-abc123.laserdata.cloud",
"nodes": [
{
"id": 610809900976570889,
"name": "node-1",
"image_id": "ami-0abc123",
"variant": "ubuntu_x64",
"storage_type": "network_balanced"
}
]
},
"correlation_id": "8f4a2b6c9d1e4f3a8b5c7d9e0f1a2b3c",
"timestamp": "2025-01-15T10:30:00Z"
}
],
"page": 1,
"total_results": 1,
"total_pages": 1
}Entries use the SDK's TenantAuditInfo structure:
| Field | Description |
|---|---|
type | Event type slug (e.g. deployment_created, member_invited, access_rule_added) |
name | Human-readable label for the event type |
author | The human who triggered the action. {id, name} or null for system events. Always set when an interactive session or an API key is involved (the user that owns the key). |
api_key | The API key that authored the call when the action came from automation. Omitted for actions taken from an interactive Console session. {id, name}. Lets you tell direct user activity apart from key-driven activity for SOC 2 / ISO machine-identity tracking. |
user | The user the action was performed on (member operations, role assignments). null when not applicable |
division / environment / deployment | Resource scope. Each is {id, name} or null depending on what the event touches |
data | Event-type-specific payload. Shape varies per event (see below). Can be null for events without an extra payload |
correlation_id | UUID linking this event to others triggered by the same request or workflow. null if untracked |
timestamp | ISO 8601 time when the event was recorded |
data contains event-specific details:
deployment_createdrecords{cloud, area, region, variant, tier, cluster_kind, public_ip, storage_type, storage_size, target_network_tput?, encrypted, protected, retention, code, name, domain?, nodes[]}. Each node includesid, name, image_id, variant, storage_type.deployment_upgradedrecords{from_tier, to_tier, from_storage, to_storage}.deployment_data_access_updatedrecords{data_access_enabled, previous_data_access_enabled}.deployment_metadata_sync_updatedrecords{metadata_sync_enabled, previous_metadata_sync_enabled, metadata_purged}.deployment_renamedrecords{name, previous_name}.deployment_movedrecords{environment_id, previous_environment_id}under the environment the deployment moved to.deployment_deletedrecords{name, code, reason?}.access_rule_addedandaccess_rule_deletedrecord{cidrs, description?, rules}, including protocol toggles.member_invitedrecords{email, roles}.api_key_createdandapi_key_deletedrecord{name, role_id, division_id?}.config_activatedrecords{config_id, kind, name, version}.connector_activatedandconnector_deletedrecord{connector_type, connector_key, instance_key, instance_id, version}.connector_typeissourceorsink.connector_keyidentifies the catalog plugin, andinstance_keyis its deployment-specific hyphenated name.instance_idis numeric, andversionis the plugin SemVer. The owningdeployment,environment, anddivisionappear in the top-level scope fields.
Use /audit/types to retrieve the complete event-type list for your tenant.
| Query Parameter | Description |
|---|---|
page | Page number |
results | Items per page (max 100) |
from | Start time (ISO 8601) |
to | End time (ISO 8601) |
user | Filter by subject user id |
author | Filter by acting user id |
api_key | Filter by API key id (only events authored via that key) |
division | Filter by division id |
environment | Filter by environment id |
deployment | Filter by deployment id |
types | Comma-separated list of event types to include |
correlation_id | Find all events sharing a correlation UUID |
Deployment Activity
Query Deployment Activity
GET/audit/tenants/{tenant_id}/activitiesQuery the changes applied inside the tenant's deployments: streams, topics, partition counts, consumer groups, Iggy users, and personal access tokens.
curl "https://api.laserdata.cloud/audit/tenants/{tenant_id}/activities?division={division_id}&page=1&results=20" \
-H "ld-api-key: YOUR_API_KEY"{
"items": [
{
"id": 4405,
"division": { "id": 4402, "name": "Platform Engineering" },
"environment": { "id": 4403, "name": "production" },
"deployment": { "id": 4404, "name": "events-prod" },
"kind": "change",
"source": {
"kind": "iggy",
"log_id": "0000000000000000000000000000002a",
"op": 128
},
"resource": "topic",
"action": "partitions_changed",
"requested_op": 127,
"actor": { "id": 3, "name": "orders-service" },
"stream_id": 3,
"topic_id": 2,
"resource_name": "telemetry",
"details": { "partitions_count": 12, "previous_partitions_count": 8 },
"timestamp": "2026-10-13T10:00:00.000000Z",
"received_at": "2026-10-13T10:00:01.250000Z"
}
],
"page": 1,
"total_results": 1,
"total_pages": 1
}Deployment activity includes applied Iggy changes, retained AGDX authorization events, and the AGDX changes the managed backend recorded in its audit log. Metadata sync supplies these records. An initial sync or a rebuilt baseline creates no synthetic resource-created entries. The managed backend writes its audit log as a new log in the deployment's ops stream, and Warden reads it from its start, so the changes made through the managed backend appear with their actor and time. Changes made before the deployment ran a managed backend that writes this log are not in it. Entries are kept for the life of the organization, like audit records, and so are the Iggy usernames that name their actors. Deleting a deployment's synced metadata through Update Metadata Sync, or deleting the deployment, does not remove them.
Callers with audit:read see every entry of the tenant. Other callers must pass division and see only the environments in it where they hold deployment:activity:read. The built-in developer role has it, viewer does not. Members read back as far as their plan's audit retention allows.
| Field | Description |
|---|---|
id | Entry id. Entries with the same timestamp are ordered by it |
division / environment / deployment | {id, name} of the scope when the change was applied. A later move or rename does not change it |
kind | change for a recorded event, gap for incomplete coverage, or skipped for an entry that could not be stored |
source | Tagged source evidence. Its kind is iggy, agdx_authorization, or plane_audit. See the source shapes below |
resource | stream, topic, consumer_group, user, personal_access_token, managed_role, role_binding, filter, filter_binding, projection, fork, or schema. Absent when an entry has no single resource |
action | created, updated, deleted, partitions_changed, password_changed, permissions_updated, defined, or bindings_updated |
requested_op | For a delete or partition change that Iggy completed later, the operation that requested it |
actor | {id, name} of the Iggy user that made the change, with the newest username the audit service knew when it stored the entry. A later user incarnation corrects an earlier attribution to a reused id. On filter, filter binding, projection, schema, and fork entries it is the Iggy user whose request the managed backend applied. The root user is id 0. Absent when no actor is recorded, such as Iggy expiring a token, the managed backend deleting a fork on its own, or Iggy removing a deleted stream's bindings. This is an Iggy user, not a Console member. name is null until the user's name reaches the audit service, usually within a minute |
agent | On filter, filter binding, projection, schema, and fork entries, the agent id the client's connection declared when it made the change over the binary protocol, as a Laser SDK agent declares itself. A claim the client makes, which nothing verifies. Absent for changes made over HTTP and for every other entry |
member | {id, name} of the Console member who made a filter, filter binding, projection, schema, or fork change from the Console's data view, which writes as one shared Iggy user named in actor. name is the member's email when the audit service knows it, else null. Absent for every other change, including native Iggy changes made from the Console |
user | {id, name} of the Iggy user that a user entry changed, or of the token owner in a personal_access_token entry |
stream_id, topic_id | Iggy stream and topic ids. A filter binding entry carries both. Use the activity entry id as the row identity |
resource_id / resource_created_at / resource_name | Native Iggy resource id, its creation time when known, and its name. The existing numeric id retains its meaning. User ids and names also appear in user. On AGDX entries resource_name is present only for a filter, a projection, a schema, or a filter binding's consumer group, whose names differ from their keys. A filter's name is the one its caller gave it, also for the filter a consumer group policy creates and for every later change to it. A dropped projection or schema keeps the name it had |
resource_key | AGDX resource identity, such as a role name, a role binding's user id, a filter or schema id, a filter binding's stream_id:stream_created_at:topic_id:topic_created_at:group_id, or a projection or fork identifier. A filter binding key carries the stream's and topic's creation times in microseconds since the Unix epoch, so a group recreated with reused ids gets a new key. A projection binding entry is keyed by its projection, or by index:<name> when the binding names only an index. Absent on native Iggy entries |
details | What changed. See below |
timestamp | Recorded event time, in RFC 3339. On filter, filter binding, projection, schema, and fork entries it is when the managed backend applied the change |
received_at | When the audit service stored the entry |
details holds only what applies: previous_name after a rename, partitions_count and previous_partitions_count, removed_partition_ids, changed_options with the names of the options an update changed, a user's or a filter revision's status (active or inactive), reason (updated or resource_deleted for permissions, deleted or expired for tokens), a token's expiry, a gap's from and to, and a skipped entry's skipped_kind and skipped_reason. Previous values appear only when they are known to be exact. A change replayed during a rebuild can come without them, because the rebuild may have read the resource after that change. Configuring a group's filter again under a new name records a filter updated entry with changed_fields set to ["name"] and the old name in previous_name. AGDX details can also include changed_fields, bound role names in roles, a missing revision range in from_revision and to_revision or the filter revision a change concerns in to_revision alone, the filter a binding uses in filter_id, a projection or schema version, the names of the stream and topic a projection binding reads or a filter binding's group belongs to in source_stream and source_topic, a fork's parent, and the kind of a projection (row or graph) or a fork (severed or continuous) in resource_kind, which is unrecognized for a kind Warden does not know. An AGDX gap carries its cause as a code in gap_reason, and its source.kind says which history it belongs to. Authorization gaps use baseline_missing, history_changed, history_behind, events_evicted, incomplete, forbidden, unsupported, too_large, or unreadable. plane_audit gaps use history_changed when the ops stream or its audit topic was recreated, events_evicted when retention removed records from the log before they were read, and forbidden, unreadable, incomplete, or too_large when a read failed. A plane_audit record that cannot be decoded becomes a skipped entry, and the records after it still apply. Entries never carry passwords, token values, permission sets, option values, filter policies, projection definitions, schema bodies, key-value values, or messages.
The source shapes are:
source.kind | Fields | Coverage |
|---|---|---|
iggy | log_id as 32 hex digits, op | Position of an applied Iggy metadata record |
agdx_authorization | metadata_log_id as 32 hex digits, revision | Retained role and binding events. The metadata identity is collection-time reset evidence, not the event's historical log position |
plane_audit | log_id as 32 hex digits, offset | Applied filter, filter binding, projection, schema, and fork changes from the managed backend's audit log on the deployment's ops stream, _agdx. log_id identifies that log and changes when the ops stream or its audit topic is recreated, and offset is the record's position in it |
Use the entry id to identify a row. Authorization history retains a bounded set of events, so older changes can be unavailable. The managed backend's audit log does not expire by default. If its retention is changed and records are removed before Warden reads them, activity shows an events_evicted gap. Recreating the ops stream or its audit topic loses the records the log held, reported as one history_changed gap. A change the managed backend refused is not activity. Gap entries report known coverage loss.
| Query Parameter | Description |
|---|---|
page | Page number |
results | Items per page (max 100) |
from | Inclusive start time (RFC 3339) |
to | Exclusive end time (RFC 3339) |
division | Filter by division id. Required without audit:read |
environment | Filter by environment id |
deployment | Filter by deployment id |
kind | change, gap, or skipped |
resource | Filter by resource |
action | Filter by action |
Entries come newest first. A member who needs a division filter but omits division gets 400 with a validation error naming it. A caller without access to the requested division or environment gets 403.