Audit trail

Every privileged action against your Gateway org, recorded with who, what, when, and from where

The audit trail is an append-only record of every privileged action performed in your Gateway organization. Use it for compliance reviews, incident investigation, and to answer “who changed this?” questions about routing policies, API keys, members, and security settings.


What gets audited

Mutations to org-scoped resources emit an audit event, as do sign-in attempts and audit-log exports. Ordinary read API calls and inference traffic are not audited; inference is recorded on the request log, which is a separate surface.

ResourceEvents
API keysAPI_KEY_CREATED, API_KEY_UPDATED, API_KEY_DELETED
Management keysMANAGEMENT_KEY_CREATED, MANAGEMENT_KEY_DELETED
Credentials (BYOK)CREDENTIAL_CREATED, CREDENTIAL_UPDATED, CREDENTIAL_DELETED
MembersMEMBER_INVITED, MEMBER_JOINED, MEMBER_ROLE_CHANGED, MEMBER_REMOVED, MEMBER_INVITATION_RESENT, MEMBER_INVITATION_REVOKED
RolesROLE_CREATED, ROLE_UPDATED, ROLE_DELETED
AuthLOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, PASSWORD_RESET
OrganizationORG_CREATED, ORG_SETTINGS_UPDATED, ORG_DEACTIVATED, ORG_REACTIVATED, ORG_DELETED
SSOSSO_PROVIDER_CREATED, SSO_PROVIDER_UPDATED, SSO_PROVIDER_DELETED, SSO_LOGIN_REQUIRED_ON, SSO_LOGIN_REQUIRED_OFF
ProjectsPROJECT_CREATED, PROJECT_UPDATED, PROJECT_DELETED
Project guardrailsPROJECT_PI_SETTINGS_UPDATED, PROJECT_PI_SETTINGS_DELETED, PROJECT_DLP_SETTINGS_UPDATED, PROJECT_DLP_SETTINGS_DELETED
CustomersCUSTOMER_CREATED, CUSTOMER_UPDATED, CUSTOMER_DELETED
Routing policiesROUTING_POLICY_CREATED, ROUTING_POLICY_UPDATED, ROUTING_POLICY_DELETED
Routing rulesROUTING_RULE_CREATED, ROUTING_RULE_UPDATED, ROUTING_RULE_DELETED
Unified routingUNIFIED_ROUTING_CONFIG_CREATED, UNIFIED_ROUTING_CONFIG_UPDATED, UNIFIED_ROUTING_CONFIG_DELETED, UNIFIED_ROUTING_CONFIG_REORDERED
Model aliasesMODEL_ALIAS_CREATED, MODEL_ALIAS_UPDATED, MODEL_ALIAS_DELETED
Routing classifiersROUTING_CLASSIFIER_CREATED, ROUTING_CLASSIFIER_UPDATED, ROUTING_CLASSIFIER_DELETED
Custom routing configsBYOR_CONFIG_CREATED, BYOR_CONFIG_UPDATED, BYOR_CONFIG_DELETED
Custom routing datasetsBYOR_DATASET_CREATED, BYOR_DATASET_UPDATED, BYOR_DATASET_DELETED, BYOR_PROMPTS_IMPORTED, BYOR_DATASET_SOURCE_CREATED, BYOR_DATASET_SOURCE_UPDATED, BYOR_DATASET_SOURCE_DELETED, BYOR_PROMPTS_IMPORTED_FROM_SOURCE
Custom routing benchmarksBYOR_BENCHMARK_CREATED, BYOR_BENCHMARK_UPDATED, BYOR_BENCHMARK_DELETED, BYOR_BENCHMARK_SCORES_UPLOADED, BYOR_BENCHMARK_SCORE_OVERRIDE_SET, BYOR_BENCHMARK_SCORE_OVERRIDE_DELETED, BYOR_EVAL_RUN_TRIGGERED, BYOR_RESULT_OVERRIDDEN, BYOR_RESULT_RESTORED
EvalsEVAL_SUITE_CREATED, EVAL_SUITE_UPDATED, EVAL_SUITE_DELETED, EVAL_CASE_CREATED, EVAL_CASE_UPDATED, EVAL_CASE_DELETED, EVAL_RUN_CANCELLED
ExperimentsEXPERIMENT_SUITE_CREATED, EXPERIMENT_SUITE_UPDATED, EXPERIMENT_SUITE_ARCHIVED, EXPERIMENT_CASE_CREATED, EXPERIMENT_CASE_UPDATED, EXPERIMENT_CASE_DELETED, EXPERIMENT_CASES_IMPORTED, EXPERIMENT_RUN_TRIGGERED, EXPERIMENT_RUN_CANCELLED
Model migrationsMODEL_MIGRATION_CREATED, MODEL_MIGRATION_UPDATED, MODEL_MIGRATION_COMPLETED, MODEL_MIGRATION_ABANDONED
Self-hosted endpointsSELF_HOSTED_ENDPOINT_CREATED, SELF_HOSTED_ENDPOINT_DELETED
Telemetry broadcastBROADCAST_DESTINATION_CREATED, BROADCAST_DESTINATION_UPDATED, BROADCAST_DESTINATION_DELETED
DLPDLP_RULE_CREATED, DLP_RULE_UPDATED, DLP_RULE_DELETED
BlocklistBLOCKLIST_RULE_CREATED, BLOCKLIST_RULE_UPDATED, BLOCKLIST_RULE_DELETED
CompressionCOMPRESSION_SETTING_CREATED, COMPRESSION_SETTING_UPDATED, COMPRESSION_SETTING_DELETED
BillingPAYMENT_METHOD_CREATED, PAYMENT_METHOD_UPDATED, PAYMENT_METHOD_DELETED, BILLING_SETTINGS_UPDATED, CREDITS_PURCHASED, CREDITS_PURCHASE_RETRIED, CREDITS_PURCHASE_BLOCKED, CREDITS_REFUNDED, AUTO_TOPUP_PAUSED, AUTO_TOPUP_RESUMED
Audit trailAUDIT_LOG_EXPORTED

The catalog covers 122 event types, and it grows as features ship. The event-type dropdown in the dashboard is generated from the same list, so treat it as the authoritative set rather than this table: a resource your organization has not turned on still has its events defined, and a resource added after this page was last edited will appear in the dropdown first.

Four of the events record reads rather than mutations: LOGIN_SUCCESS, LOGIN_FAILED, LOGOUT, and AUDIT_LOG_EXPORTED. Everything else is a mutation.


Fields captured on each entry

Each audit row stores a denormalized snapshot of the actor and target so the entry stays interpretable even if the user, role, or organization is later deleted.

FieldDescription
created_atTimestamp the event was recorded (UTC, with timezone)
user_idUUID of the user who performed the action, or null for system-driven events
user_name / user_emailDenormalized at write time. Survive user deletion.
role_nameThe user’s role at the moment of the event. Survives role rename or deletion.
organization_id / organization_nameDenormalized. Survive org deletion.
ip_addressSourced from the CF-Connecting-IP header (Cloudflare) when present; otherwise the request socket IP
urlHTTP request path
methodHTTP method (POST, PATCH, DELETE, PUT)
request_bodyJSONB. For non-auth-adjacent handlers, the validated request body is stored as-is. For auth-adjacent handlers (credentials, SSO, auth, password reset, API keys), this field is null by design. See below.
event_typeOne of the values from the catalog above
event_descriptionHuman-readable summary (verb + entity + identifier, plus a change summary on UPDATE events)

The table is append-only. There is no updated_at column and entries are never modified after they’re written.


Handling of sensitive fields

The audit trail is designed so that secret values (API keys, credential secrets, SSO client secrets, passwords) never reach an audit row in the first place:

  • Auth-adjacent handlers omit the body. Credential, SSO, auth, password reset, and API key handlers pass request_body=None when emitting their audit event. The event records that the action happened (with the entity name in the description) but never persists the request payload.
  • UPDATE handlers diff before mutating. A field-level diff (compute_changes) runs against the pre-mutation instance and the validated request body. Fields that contain secret values are summarized as "changed" rather than rendering 'old' to 'new', so the rendered description in the audit row contains no secret material.
  • Body truncation in descriptions. Each diffed value is truncated to 100 characters in event_description, so long blobs (e.g., raw JSON config) don’t bloat the audit row even when they’re not sensitive.

Non-auth-adjacent UPDATE handlers persist the validated request body to request_body as-is. Treat that column as containing the raw payload, and review your audit feed if you handle especially sensitive non-auth data.


What an UPDATE entry looks like

UPDATE events combine an identifying prefix with a per-field diff. The description shape is:

Updated <entity> <name> with ID <id>. Changed <field>: 'old' to 'new', <field>: 'old' to 'new'

List-valued fields render as added/removed sets:

Updated project Production with ID proj_abc. Changed allowed_models: added gpt-5.2; removed gpt-4o

This makes it possible to scan the audit feed and immediately see what changed in any update, without having to fetch the resource history separately.


Viewing the audit trail in the dashboard

Open Settings → Audit trail in the Merge Gateway dashboard. The page shows a paginated, filterable table of events with:

  • A free-text filter by user
  • Event-type dropdown covering every value in the catalog above
  • Date-range picker
  • CSV export button (the export itself is recorded as an AUDIT_LOG_EXPORTED event so you have a trail of who pulled what)

The CSV export contains: Timestamp, User Name, User Email, Role, IP Address, Event Type, Event Description. Cells starting with =, +, -, @, \t, or \r are prefixed with a single quote to neutralize CSV injection.


Required permission

Listing and exporting the audit trail requires the View audit trail permission on the caller’s role. All four built-in roles (Admin, Developer, Security, Read Only) include this permission. See Roles and permissions for the full permission matrix.


Retention

Audit entries are append-only and persist indefinitely on the org. There is no automatic TTL or archival. Once written, an event is permanent. The dashboard supports arbitrary date ranges if you need to pull long-windowed compliance reports.


FAQ

No. Inference traffic flows through a separate request-log surface (and the Security alerts feed). The audit trail covers administrative actions: settings changes, role assignments, key creation, plus sign-in attempts and audit-log exports.

Use the CSV export from the dashboard and forward it to your SIEM. There is no native webhook stream today.

Entries are denormalized at write time, so user_name, user_email, role_name, organization_name remain populated on the row even after the referenced entity is deleted. The FK columns (user_id, organization_id) are set to null via ON DELETE SET NULL.

No. The table is append-only and write-time only. Events are emitted during the mutation that triggers them and cannot be inserted retroactively.

Failed logins emit LOGIN_FAILED. Most other failed mutations do not write an audit entry because the mutation never began. The audit row commits in the same transaction as the mutation. Check your application logs for failures that didn’t make it past authorization.


Next steps