Audit Log Endpoints
Audit logs provide an append-only record of the actions performed within your VeraID organization. Logs are stored in an ordinary PostgreSQL table, indexed by organization, actor, action and identity over time.
Audit Log Fields
Every audit log entry contains the following fields:
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier for the log entry |
organizationId | string | The organization the entry belongs to |
actorType | string | Type of actor: USER, IDENTITY, SYSTEM |
actorId | string | Identifier of the actor |
actorName | string | Display name of the actor |
action | string | The action that was performed |
resourceType | string | Type of resource affected (e.g., identity, credential, policy) |
resourceId | string | Identifier of the affected resource |
resourceName | string | Display name of the affected resource |
outcome | string | Result of the action: SUCCESS, FAILURE, DENIED |
errorCode | string | Machine-readable error code, when the action failed |
errorMessage | string | Why the action failed or was denied |
ipAddress | string | Source IP address of the request |
userAgent | string | User agent string of the client |
geoLocation | object | { country, region, city } of the source address, when known |
durationMs | number | Request duration in milliseconds, when recorded |
identityId | string | The identity the entry concerns, when there is one |
identity | object | { id, name, type } of that identity, or null |
metadata | object | Additional context specific to the action |
timestamp | string | ISO 8601 timestamp of when the action occurred |
Query Audit Logs
Retrieve audit logs with filters for actor, action, resource, outcome, and time range.
GET /api/v1/audit-logsQuery Parameters
| Parameter | Type | Description |
|---|---|---|
actorType | string | Filter by actor type: USER, IDENTITY, SYSTEM |
actorId | string | Filter by specific actor ID |
actorSearch | string | Case-insensitive substring match on actor ID or actor name |
action | string | Filter by an exact action (e.g., identity.create, credential.verify), or by prefix with a trailing .*. The prefix is the text before .*, with no dot boundary: credential.* matches every action beginning credential, and identity.* also matches identity_group.*. See Actions |
actions | string | Filter by any of several exact actions; repeat the parameter (actions=credential.create&actions=credential.revoke). Takes precedence over action |
resourceType | string | Filter by resource type (e.g., identity, credential, policy) |
resourceId | string | Filter by specific resource ID |
outcome | string | Filter by outcome: SUCCESS, FAILURE, DENIED |
ipAddress | string | Filter by exact source IP address |
startDate | string | Start of time range, an ISO 8601 date-time in UTC (e.g., 2026-03-18T00:00:00Z) |
endDate | string | End of time range, an ISO 8601 date-time in UTC |
page | number | Page number (default: 1) |
limit | number | Items per page (default: 50, max: 100) |
Example Request
curl -X GET "https://app.veraid.io/api/v1/audit-logs?actorType=IDENTITY&action=credential.verify&outcome=SUCCESS&startDate=2026-03-18T00:00:00Z&endDate=2026-03-19T23:59:59Z&limit=50" \ -H "Cookie: veraid-session=<your session cookie>"Example Response
{ "data": [ { "id": "8c0e7f2a-4b1d-4c55-9d2e-0f6a1b3c5d7e", "organizationId": "org_abc", "timestamp": "2026-03-19T09:15:00Z", "actorType": "IDENTITY", "actorId": "id_xyz789", "actorName": null, "action": "credential.verify", "resourceType": "credential", "resourceId": "cred_def456", "resourceName": "Production API Key", "outcome": "SUCCESS", "errorCode": null, "errorMessage": null, "ipAddress": "10.0.1.50", "userAgent": null, "geoLocation": null, "metadata": {}, "durationMs": null, "identityId": "id_xyz789", "identity": { "id": "id_xyz789", "name": "aws-deploy-prod", "type": "SERVICE_ACCOUNT" } } ], "total": 1847, "page": 1, "limit": 50, "totalPages": 37}A credential.verify entry is written each time a stored credential is presented to authenticate. A wrong secret on an otherwise usable credential is recorded with outcome: "FAILURE". Any attempt on a credential refused for its state (revoked, expired, over its usage limit, identity not active, IP not allowed) is recorded as DENIED, whether or not the secret was right, because those checks run first. Either way the reason is in errorMessage. A key that matches no stored credential (unknown prefix or malformed) leaves no entry.
Filtering by Denied Access
To find all denied access attempts:
curl -X GET "https://app.veraid.io/api/v1/audit-logs?outcome=DENIED&startDate=2026-03-01T00:00:00Z" \ -H "Cookie: veraid-session=<your session cookie>"Denials come mostly from policy enforcement, which records every decision it makes as policy.evaluate.<action>:
{ "data": [ { "id": "1f4b9c7e-2d3a-4e8f-b6c1-9a0d2e3f4a5b", "timestamp": "2026-03-15T22:45:00Z", "actorType": "IDENTITY", "actorId": "id_legacy01", "action": "policy.evaluate.credential.read", "resourceType": "credential", "resourceId": null, "outcome": "DENIED", "errorMessage": "No matching policy found - default deny", "ipAddress": "203.0.113.42", "userAgent": "curl/8.1.2", "identityId": "id_legacy01", "metadata": { "policyAction": "credential.read", "refusedBy": { "id": "pol_abc123", "name": "Production Secrets - Office IPs Only", "condition": "ip_range", "reason": "IP 203.0.113.42 not in allowed ranges" }, "conditions": [ { "type": "ip_range", "passed": false, "reason": "IP 203.0.113.42 not in allowed ranges" } ], "credentialId": "cred_legacy01", "scopes": ["credentials:read"] } } ]}Filtering by System Actions
System-initiated actions include credential expiry, scheduled job runs, audit retention and rotation schedule deactivation:
curl -X GET "https://app.veraid.io/api/v1/audit-logs?actorType=SYSTEM&limit=10" \ -H "Cookie: veraid-session=<your session cookie>"{ "data": [ { "id": "6a2d8e1f-7c4b-4f3a-9e5d-1b2c3d4e5f60", "timestamp": "2026-03-19T02:00:00Z", "actorType": "SYSTEM", "actorId": "credential-expiration-job", "actorName": "Credential Expiration Job", "action": "credential.expired", "resourceType": "credential", "resourceId": "cred_exp001", "resourceName": "Analytics API Key", "outcome": "SUCCESS", "identityId": "id_gcp_analytics", "metadata": { "jobId": "job_123", "expiredAt": "2026-03-19T00:00:00.000Z", "credentialType": "API_KEY", "identityName": "gcp-analytics-prod" } } ]}Export Audit Logs
Export audit logs in bulk for compliance reporting, archival, or analysis in external tools.
GET /api/v1/audit-logs/exportQuery Parameters
Every parameter is optional.
| Parameter | Type | Description |
|---|---|---|
format | string | json (default) or csv |
startDate | string | Start of the time range (ISO 8601) |
endDate | string | End of the time range (ISO 8601) |
actorType | string | USER, IDENTITY or SYSTEM |
actorId | string | Entries by this actor |
action | string | Entries with exactly this action. Unlike the list endpoint, a trailing .* prefix is not supported here |
resourceType | string | Entries for this resource type |
outcome | string | SUCCESS, FAILURE or DENIED |
Example Request
curl -X GET "https://app.veraid.io/api/v1/audit-logs/export?format=json&startDate=2026-03-01T00:00:00Z&endDate=2026-03-19T23:59:59Z" \ -H "Cookie: veraid-session=<your session cookie>" \ -o audit-logs-march.jsonThe JSON export is an array of audit log entries with every field listed under Audit Log Fields, except identity, which only the list endpoint adds (identityId is included).
CSV Export
curl -X GET "https://app.veraid.io/api/v1/audit-logs/export?format=csv&startDate=2026-03-01T00:00:00Z&endDate=2026-03-19T23:59:59Z" \ -H "Cookie: veraid-session=<your session cookie>" \ -o audit-logs-march.csvThe CSV export has these columns. Every value in the data rows is quoted, with embedded quotes doubled:
timestamp,actorType,actorId,actorName,action,resourceType,resourceId,resourceName,outcome,ipAddress,errorMessageThe CSV leaves out metadata, userAgent, geoLocation and the other fields; use the JSON export when you need them.
Actions
The action values VeraID writes. The action filter matches them exactly (or by prefix with .*), so use them as written: most are resource.verb in the present tense (credential.create, not credential.created), but connector, Sectora and governance entries use their own forms. Entries shown with <...> are built at run time; the possible values are listed beside them.
Identities
| Action | Description |
|---|---|
identity.create | An identity was created |
identity.update | An identity’s configuration was modified |
identity.suspend | An identity was suspended |
identity.activate | A suspended identity was reactivated |
identity.revoke | An identity was revoked |
identity.delete | An identity was deleted |
identity.create_from_nhi | An identity was created from a discovered non-human identity |
nhi.link | A discovered non-human identity was linked to an existing identity |
identity.import.create / identity.import.update | An import created or updated an identity |
identity_group.create / identity_group.update / identity_group.delete | An identity group was created, modified or deleted |
identity_group.add_member / identity_group.remove_member | An identity was added to or removed from a group |
Credentials
| Action | Description |
|---|---|
credential.create | A credential was issued |
credential.verify | A stored credential was presented to authenticate: SUCCESS, FAILURE (wrong secret on a usable credential) or DENIED (refused for its state, checked before the secret) |
credential.revoke | A credential was revoked |
credential.expired | The expiration job found a credential past its expiry (actor SYSTEM) |
credential.fetch | A credential’s secret was fetched with an organization API key |
credential.emergency_rotate | A credential was rotated as an emergency |
credential.emergency_revoke | A credential was revoked through the emergency-rotation endpoint |
credential.rotation_started | A scheduled or manual rotation began |
credential.rotation_completed | A rotation finished |
credential.rotation_failed | A rotation failed |
credential.rotation_rollback | A rotation was rolled back to the previous secret |
credential.sync_success / credential.sync_failed | A credential was pushed, or failed to push, to a sync target |
credential.vault_store / credential.vault_read / credential.vault_revoke | A secret in an AI agent’s vault was stored, read by the agent, or revoked |
rotation_schedule.create / rotation_schedule.update / rotation_schedule.delete | A rotation schedule was created, modified or deleted |
rotation_schedule.deactivate | A rotation schedule was switched off automatically because its credential cannot be rotated by a schedule, such as a temporary credential or a vault secret (actor SYSTEM) |
sync_target.create / sync_target.delete | A credential sync target was added or removed |
Policies
| Action | Description |
|---|---|
policy.create | A policy was created |
policy.update | A policy was modified |
policy.enable / policy.disable | A policy was switched on or off |
policy.delete | A policy was deleted |
policy.created_from_template | A policy was created from a template |
policy.framework_bundle_applied | A compliance framework’s policy bundle was applied |
policy.import.create / policy.import.update | An import created or updated a policy |
policy.evaluate.<action> | Policy enforcement decided a request. outcome is SUCCESS (allowed) or DENIED; metadata carries the matched policy, or on a denial the ALLOW policy whose condition failed (refusedBy) |
policy.bypass.<action> | A request skipped evaluation because a configured bypass condition was met. Today that is a dashboard user (actor USER) on GET or POST /api/v1/credentials |
policy.skip.<action> | Enforcement was switched off for the route or HTTP method; actor SYSTEM. No current route is configured this way, so this is not written today |
<action> is the enforced operation. Today enforcement covers credential.read and credential.create (GET and POST /api/v1/credentials) and identity.read, identity.update and identity.delete (/api/v1/identities/{id}), so for example policy.evaluate.credential.read.
Webhooks
| Action | Description |
|---|---|
webhook.create / webhook.update / webhook.delete | A webhook was created, modified or deleted |
webhook.secret_regenerated | A webhook’s signing secret was regenerated |
webhook.test | A test delivery was sent |
webhook.import.create / webhook.import.update | An import created or updated a webhook |
Alerts and incidents
| Action | Description |
|---|---|
alert.acknowledge / alert.resolve / alert.dismiss | An alert was acknowledged, resolved or dismissed |
incident.created | An incident was opened in a connected incident tool |
incident_integration.configured / incident_integration.deleted | An incident-tool integration was configured or removed |
Just-in-time access
| Action | Description |
|---|---|
jit.request.created | A JIT access request was submitted |
jit.request.auto_approved | A request was approved automatically by an approval policy |
jit.request.approved / jit.request.rejected / jit.request.cancelled | A request was approved, rejected or cancelled |
jit.request.reviewed_via_<platform> | A request was decided from Slack or Teams (<platform> is slack or teams) |
jit.credential.revealed / jit.credential.reveal_denied | A JIT credential was revealed, or a reveal was refused |
jit.approval_policy.created / jit.approval_policy.updated / jit.approval_policy.deleted | A JIT approval policy was created, modified or deleted |
AI agents
| Action | Description |
|---|---|
agent.register / agent.update / agent.approve | An agent was registered, modified or approved |
agent.suspend / agent.reactivate / agent.terminate / agent.expired | An agent’s lifecycle changed |
agent.discovered | An unregistered agent was discovered |
discovery.<resolution> | A discovered agent was resolved: discovery.register, discovery.block, discovery.ignore or discovery.link |
agent.api_key_generated / agent.api_key_revoked | An agent API key was issued or revoked |
agent_policy.create / agent_policy.update / agent_policy.delete / agent_policy.reorder | An agent policy was created, modified, deleted or reordered |
agent_policy.enable / agent_policy.disable | An agent policy was switched on or off |
agent_approval.request_created | An agent action was held for human approval |
agent_approval.approved / agent_approval.denied | A held action was decided |
agent_approval.cancelled / agent_approval.expired | A held action was cancelled or timed out |
gateway.<decision> | The agent gateway decided an action: gateway.allow, gateway.challenge, gateway.block, gateway.throttle or gateway.alert |
gateway.session_ended | An agent gateway session ended |
ai.usage_recorded | AI spend was recorded |
ai.budget_warning / ai.budget_blocked | A budget check warned or refused |
ai.budget_reset | An admin reset an AI budget |
ai.prompt_injection_check | A prompt was checked for injection |
ai.<call> | An AI call was logged through AI monitoring: ai.completion, ai.chat, ai.embedding, ai.image, ai.audio or ai.custom |
quota.warning / quota.exceeded | A usage quota check warned or refused |
mcp.server.registered / mcp.server.verified / mcp.server.blocked | An MCP server was registered, verified or blocked |
ai_platform.integration.create | An AI platform integration was added |
ai_platform.agent.offboard / ai_platform.credential.rotate | An AI platform agent was offboarded, or its credential rotated |
ai_platform.<activityType> | Usage synced from an AI platform, e.g. ai_platform.code_suggestions, ai_platform.conversations |
LLM_PROVIDER_CONFIGURED | An LLM provider was configured |
FRAMEWORK_INTEGRATION_CREATED / FRAMEWORK_INTEGRATION_UPDATED / FRAMEWORK_INTEGRATION_DEACTIVATED | An AI framework integration was added, changed or deactivated |
Cloud and CI/CD connectors
| Action | Description |
|---|---|
aws.access_key_created / aws.access_key_rotated / aws.access_key_revoked | An AWS IAM access key was created, rotated or revoked |
gcp.service_account_key_created / gcp.service_account_key_rotated / gcp.service_account_key_revoked | A GCP service account key was created, rotated or revoked |
azure.client_secret_created / azure.client_secret_rotated / azure.client_secret_revoked | An Azure client secret was created, rotated or revoked |
azure.service_principal_disabled / azure.service_principal_permissions_revoked | An Azure service principal was disabled, or its permissions revoked |
kubernetes.token_created / kubernetes.token_secret_created / kubernetes.token_rotated / kubernetes.token_revoked | A Kubernetes service account token changed |
github_actions.secret_created / github_actions.secret_deleted | A GitHub Actions secret was written or deleted |
gitlab_ci.variable_created / gitlab_ci.variable_updated / gitlab_ci.variable_deleted | A GitLab CI variable changed |
circleci.context_created / circleci.context_deleted / circleci.env_var_created / circleci.env_var_deleted | A CircleCI context or environment variable changed |
jenkins.credential_created / jenkins.credential_deleted | A Jenkins credential was written or deleted |
aws.sync_completed, gcp.sync_completed, azure.sync_completed, azure.service_principals_sync_completed, kubernetes.sync_completed, github_actions.sync_completed, gitlab_ci.sync_completed, circleci.sync_completed, jenkins.sync_completed | A user-started connector sync finished (actor USER). Only the CI/CD connectors (GitHub Actions, GitLab CI, CircleCI, Jenkins) record a failed sync, as FAILURE; the cloud connectors write a row only on success |
discovery.scan_started / discovery.scan_completed / discovery.scan_failed | A discovery scan started, finished or failed |
integration_credential.configure / integration_credential.delete | A connector’s stored credentials were set or removed |
integration.<platform>.account_linked / integration.<platform>.account_unlinked | A user linked or unlinked a Slack or Teams account |
Secret scanning (Sectora)
| Action | Description |
|---|---|
secret.leaked | A leaked secret was reported |
secret.remediated | A leaked secret was remediated |
credential.revoked | A credential was revoked automatically because it was found leaked (actor SYSTEM) |
scan.completed / scan.failed | A Sectora scan finished or failed |
oauth.risky_app | A risky OAuth app was reported |
Governance and lifecycle
| Action | Description |
|---|---|
ATTESTATION_CAMPAIGN_CREATED / ATTESTATION_CAMPAIGN_LAUNCHED | An attestation campaign was created or launched |
ATTESTATION_DECISION_SUBMITTED / ATTESTATION_ITEMS_ESCALATED | An attestation decision was submitted, or overdue items were escalated |
IDENTITY_REVOKED_VIA_ATTESTATION | An identity was revoked by an attestation decision |
IDENTITY_AUTO_DISABLED | A lifecycle rule disabled an inactive identity |
IDENTITY_OWNERSHIP_TRANSFERRED / BULK_OWNER_ASSIGNMENT | Identity ownership was transferred or assigned in bulk |
OFFBOARDING_EXECUTED | An owner’s offboarding plan was executed |
OFFBOARDING_<step> | One step of an offboarding plan: OFFBOARDING_TRANSFER, OFFBOARDING_REVOKE or OFFBOARDING_DISABLE |
CORRELATION_GROUP_CREATED / CORRELATION_GROUP_SUSPENDED | A cross-platform identity correlation group was created or suspended |
OAUTH_APP_REVIEWED / OAUTH_APP_REVOKED | A third-party OAuth app was reviewed or revoked |
CLOUDVERA_ANOMALY_DETECTED / CLOUDVERA_COST_SPIKE / CLOUDVERA_GEO_ANOMALY | CloudVera reported an anomaly |
Organization, team and account
| Action | Description |
|---|---|
organization.created | An MSP created a client organization |
organization.member.role_updated / organization.member.removed | A member’s role was changed, or the member removed |
team.created / team.updated / team.deleted | A team was created, modified or deleted |
team.member.added / team.member.removed / team.member.role_updated | Team membership changed |
team.invitation.sent / team.invitation.accepted / team.invitation.cancelled | A team invitation was sent, accepted or cancelled |
mfa.enabled / mfa.disabled / mfa.admin_force_disabled | MFA was turned on or off, or an admin turned it off for a user |
mfa.backup_code_used / mfa.backup_codes_regenerated | A backup code was used, or the codes regenerated |
mfa.account_locked | An account was locked after repeated MFA failures |
user.mfa_verified / user.mfa_failed | A session MFA check passed or failed |
user.email_change.requested / user.email_change.completed | A user asked to change their email address, or confirmed the change |
System
| Action | Description |
|---|---|
job.<name>.completed / job.<name>.failed | A scheduled job ran for the organization |
job.credential-expiration.summary | The credential expiration job’s summary for the organization |
audit.retention.cleanup | The retention job deleted audit entries past the organization’s retention period |
audit_log.export | An audit report was exported |
Alerts, credential.used and policy.violated are not audit actions. alert.triggered and policy.violated are webhook events, and a credential’s use is recorded as credential.verify.
Retention
A job runs nightly at 02:00 UTC and deletes audit entries older than the organization’s retention period:
| Plan | Retention Period |
|---|---|
| Free, Team, or no plan set | 90 days |
| Business | 1 year |
| Enterprise | 10 years |
VeraID can set a different period for your organization on request (contact support), down to a minimum of 7 days. When a run deletes entries from your organization, it records an audit.retention.cleanup entry (actor SYSTEM) in your log. Entries are otherwise removed only when the organization itself is deleted.
Deleted entries cannot be recovered through the API. A file you export is yours and is not touched by retention, so export regularly if your compliance requirements need history beyond your retention period.