Audit Log Integration Guide

Overview

Axle can deliver an audit log of your organization's activity on the Axle platform to your own security tooling, such as a SIEM. The log records who signed in and out, what your users did in the Axle web app, every call made with your API keys, every tool your team's AI assistants called through the Axle MCP server, and every change made to your configuration and alerts.

DetailValue
FormatNewline-delimited JSON, UTF-8, one record per line and one event per record
ScopeYour organization only
CoverageSign-ins and sign-outs, web app activity, public API calls, MCP tool calls, configuration and alert changes
TimestampsRFC 3339, UTC
AvailabilityOn request. Contact your Axle representative to enable it

Getting Started

The audit log is enabled for each organization by the Axle team. There is no setting to turn it on yourself.

To get started, contact your Axle account representative. They will work with your security team to agree on where the log is delivered and to confirm that the first events arrive.

Have the following ready:

  • The tool that will receive the log, for example Splunk.
  • A technical contact on your security team.
  • Whether you need the log for your production organization, a test organization, or both.

What's Recorded

Each record describes one event. The event_type field says which kind it is.

Event typeRecorded when
EVENT_TYPE_LOGIN_SUCCEEDEDA user signs in to the Axle web app, by emailed code or by single sign-on
EVENT_TYPE_LOGIN_FAILEDA sign-in attempt with an emailed code fails for a user in your organization
EVENT_TYPE_LOGOUTA user signs out of the Axle web app
EVENT_TYPE_PORTAL_REQUESTThe Axle web app performs an action on a user's behalf, such as loading an investigation, inviting a user or saving a setting
EVENT_TYPE_API_REQUESTA request is made to the Axle API, either with one of your API keys or by the Axle web app on a user's behalf
EVENT_TYPE_CONFIG_CHANGEDA setting, webhook, API key or alert is changed. See Configuration and alert changes
EVENT_TYPE_MCP_TOOL_CALLAn AI assistant connected through the Axle MCP server calls a tool

Some actions produce more than one event. For example, setting an alert's disposition from an AI assistant records an EVENT_TYPE_MCP_TOOL_CALL for the tool call and an EVENT_TYPE_CONFIG_CHANGED for the change it made.

What's not recorded

The log records that something happened, who did it and where from. It doesn't copy your data:

  • API requests record the method and path only. Query strings and request and response bodies are never recorded.
  • MCP tool calls record the tool name only, not the arguments the assistant sent or the data it received.
  • Changes made by AI assistants record identifiers and values like a disposition or a flag color. Note text, feedback reasoning, rerun reasons, support ticket text and uploaded entity details (names, dates of birth, emails, phone numbers) are never recorded.
  • Secrets are never recorded. That includes API keys, webhook signing secrets, session tokens and webhook URLs, which can contain credentials.
  • Failed sign-ins for unknown email addresses aren't recorded, because they don't belong to any organization.
  • Activity by Axle personnel isn't included in your log.

Record Format

Delivery envelope

Each record is a delivery envelope with the event inside it, at jsonPayload.customer_audit_event. Point your field extractions there, for example jsonPayload.customer_audit_event.actor.email.

{
  "jsonPayload": {
    "customer_audit_event": {
      "event_id": "00000000-0000-4000-8000-000000000001",
      "event_type": "EVENT_TYPE_API_REQUEST"
    },
    "message": "customer audit event"
  },
  "insertId": "73dryk2dibo3701s",
  "timestamp": "2026-10-20T17:04:05.125Z"
}

The envelope has more fields than this example shows. They describe how Axle's systems delivered the record and aren't part of the audit log: ignore them, and don't depend on their names or values, which can change without notice. jsonPayload.message is always customer audit event. Use occurred_at inside the event, not the envelope's timestamp, as the time the event happened.

The rest of this guide shows only the contents of jsonPayload.

The event

Here is a public API call made with an API key:

{
  "customer_audit_event": {
    "event_id": "00000000-0000-4000-8000-000000000001",
    "event_type": "EVENT_TYPE_API_REQUEST",
    "org_id": "c1aeec53-6137-4f08-ba2d-616a4d8311ae",
    "actor": {
      "type": "ACTOR_TYPE_API_KEY",
      "id": "5e2f9a14-8c3b-4d7e-a1f0-6b9c2d4e8a37"
    },
    "outcome": "OUTCOME_SUCCESS",
    "occurred_at": "2026-10-20T17:04:05.123Z",
    "source_service": "api-service",
    "client_ip": "203.0.113.7",
    "api_request": {
      "method": "POST",
      "path": "/api/v1/alerts",
      "status_code": 201,
      "duration_ms": 184
    }
  }
}

Empty fields are left out. A field with no value is left out of the record rather than sent as an empty string or zero. For example, a sign-out has no detail object. Treat a missing field as empty.

Common fields

Every event has these fields.

FieldTypeDescription
event_idstring (UUID)Unique to the event. Use it to remove duplicates if a record is delivered more than once
event_typestringThe kind of event. See What's Recorded
org_idstring (UUID)Your Axle organization ID
actorobjectWho performed the action. See Actor
outcomestringWhether the action succeeded. See Outcome
occurred_atstring (RFC 3339)When the event happened, in UTC. The number of fractional-second digits varies, up to nanoseconds
source_servicestringThe Axle service that recorded the event: api-service or portal-api
client_ipstringThe IP address the request came from, when known

Each event type also carries one detail object, described in Event Details.

Actor

FieldTypeDescription
typestringACTOR_TYPE_USER, ACTOR_TYPE_API_KEY or ACTOR_TYPE_OAUTH_CLIENT
emailstringThe user's email address. Set for users and OAuth clients
idstring (UUID)The API key's ID. Set for API keys only
  • ACTOR_TYPE_USER is a person using the Axle web app, including the in-app assistant.
  • ACTOR_TYPE_API_KEY is a request authenticated with one of your API keys. It is attributed to the key, not to the person who created it.
  • ACTOR_TYPE_OAUTH_CLIENT is an application acting for a user, such as an AI assistant connected through the Axle MCP server. email is the user it acts for.

Outcome

ValueMeaning
OUTCOME_SUCCESSThe action completed
OUTCOME_DENIEDThe action was refused, for example for missing permissions, invalid input or a wrong sign-in code. For API requests, any 4xx status
OUTCOME_ERRORThe action failed because of a problem on Axle's side or with a service Axle depends on. For API requests, any 5xx status

OUTCOME_DENIED can point to misuse. OUTCOME_ERROR usually doesn't, so an Axle outage won't look like an attack in your log.

Client IP

client_ip is the address that connected to Axle's network edge. Addresses a client claims for itself in request headers such as X-Forwarded-For or X-Real-IP are ignored, so the value can't be spoofed that way. If the client connects through a proxy or VPN, the address is the proxy's.


Event Details

Sign-in and sign-out

EVENT_TYPE_LOGIN_SUCCEEDED and EVENT_TYPE_LOGIN_FAILED carry a login object. EVENT_TYPE_LOGOUT carries no detail object.

FieldTypeDescription
methodstringpasswordless (a code sent by email) or oidc (single sign-on)
failure_reasonstringFailed sign-ins only. invalid_code for a wrong or expired code, auth_provider_error when Axle's sign-in provider couldn't be reached, or the provider's own reason, such as a rate limit

Sign-ins are recorded against the user's home organization.

{
  "customer_audit_event": {
    "event_id": "00000000-0000-4000-8000-000000000005",
    "event_type": "EVENT_TYPE_LOGIN_FAILED",
    "org_id": "c1aeec53-6137-4f08-ba2d-616a4d8311ae",
    "actor": { "type": "ACTOR_TYPE_USER", "email": "[email protected]" },
    "outcome": "OUTCOME_DENIED",
    "occurred_at": "2026-10-20T17:04:05.123Z",
    "source_service": "portal-api",
    "client_ip": "203.0.113.7",
    "login": { "method": "passwordless", "failure_reason": "invalid_code" }
  }
}

Web app activity

EVENT_TYPE_PORTAL_REQUEST carries a portal_request object.

FieldTypeDescription
procedurestringThe operation the web app called, for example /hikari.portal.v1.PortalService/InviteUser
codestringThe result: ok, or an error such as permission_denied or invalid_argument
duration_msintegerHow long Axle took to handle the request, in milliseconds

The web app also calls the Axle API, which appears as EVENT_TYPE_API_REQUEST with an ACTOR_TYPE_USER actor. Moving between pages isn't recorded on its own, but the data each page loads is.

API requests

EVENT_TYPE_API_REQUEST carries an api_request object.

FieldTypeDescription
methodstringThe HTTP method, for example GET or POST
pathstringThe URL path, without the query string
status_codeintegerThe HTTP status Axle returned
duration_msintegerHow long Axle took to handle the request, in milliseconds

Requests rejected before they are authenticated, such as a request with an invalid API key, can't be attributed to an organization, so they aren't recorded.

MCP tool calls

EVENT_TYPE_MCP_TOOL_CALL carries an mcp_tool_call object.

FieldTypeDescription
toolstringThe tool that was called, for example get_alert. See Available Tools
client_idstringThe ID of the AI assistant application that made the call, assigned when it connected
duration_msintegerHow long the tool took, in milliseconds

outcome is OUTCOME_DENIED when the tool refused the call, for example for a missing permission, and OUTCOME_ERROR when it failed unexpectedly.

{
  "customer_audit_event": {
    "event_id": "00000000-0000-4000-8000-000000000008",
    "event_type": "EVENT_TYPE_MCP_TOOL_CALL",
    "org_id": "c1aeec53-6137-4f08-ba2d-616a4d8311ae",
    "actor": { "type": "ACTOR_TYPE_OAUTH_CLIENT", "email": "[email protected]" },
    "outcome": "OUTCOME_SUCCESS",
    "occurred_at": "2026-10-20T17:04:05.123Z",
    "source_service": "api-service",
    "client_ip": "203.0.113.7",
    "mcp_tool_call": { "tool": "get_alert", "client_id": "mcp-client-0042", "duration_ms": 731 }
  }
}

Configuration and alert changes

EVENT_TYPE_CONFIG_CHANGED carries a config_change object.

FieldTypeDescription
action_typestringWhat kind of change was made. See the table below
setting_namestringWhat was changed
old_valuestringThe value before the change, when it applies
new_valuestringThe value after the change, when it applies

A change that affects several alerts at once, such as a bulk disposition, records one event per alert.

action_typesetting_nameold_value → new_value
config_settingThe setting's name, for example Name Match FuzzinessThe previous and new setting values
api_key_createdapi_key:<key id>→ is_active:True
api_key_deactivatedapi_key:<key id>is_active:True → is_active:False
webhook_createdwebhook:<webhook id>→ is_active:True or is_active:False
webhook_updatedwebhook:<webhook id>→ changed:<fields>, the names of the fields that changed, for example changed:event_types
webhook_toggledwebhook:<webhook id>is_active:True → is_active:False, or the reverse
webhook_secret_rotatedwebhook:secretsecret:rotated → secret:rotated
webhook_deletedwebhook:<webhook id>→ deleted
disposition_updatedalert:<alert id>:dispositionThe previous and new disposition, for example NOT_REVIEWED → ESCALATED. Changes made through the transaction monitoring disposition API record the same values. The disposition narrative is never recorded
disposition_undonealert:<alert id>:dispositionThe disposition that was undone → the one restored. A bulk undo leaves both values empty
flag_feedback_submittedalert:<alert id>:block:<block>:flag:<flag>→ the flag color you submitted, for example green
note_addedalert:<alert id>:block:<block>:note→ the new note's ID
investigation_rerun_requestedalert:<alert id>:investigation→ the new investigation's ID
supplemental_entities_uploadedalert:<alert id>:entities→ the entity IDs you supplied, comma-separated
support_ticket_createdalert:<alert id>:support_ticket, or support_ticket when it isn't about an alertBoth empty

Alert IDs and entity IDs are the IDs you gave Axle when you submitted the alert.

{
  "customer_audit_event": {
    "event_id": "00000000-0000-4000-8000-000000000007",
    "event_type": "EVENT_TYPE_CONFIG_CHANGED",
    "org_id": "c1aeec53-6137-4f08-ba2d-616a4d8311ae",
    "actor": { "type": "ACTOR_TYPE_USER", "email": "[email protected]" },
    "outcome": "OUTCOME_SUCCESS",
    "occurred_at": "2026-10-20T17:04:05.123Z",
    "source_service": "api-service",
    "client_ip": "203.0.113.7",
    "config_change": {
      "action_type": "webhook_toggled",
      "setting_name": "webhook:3f6a2c1e-9b8d-4e7f-a5c4-1d2e3f4a5b6c",
      "old_value": "is_active:True",
      "new_value": "is_active:False"
    }
  }
}

Working with the Log

  • Remove duplicates by event_id. A record can occasionally be delivered more than once. A repeated event_id is the same event.
  • Order by occurred_at. Records aren't guaranteed to arrive in the order the events happened. Configure your SIEM to take each event's time from jsonPayload.customer_audit_event.occurred_at.
  • Expect records in batches. Records are delivered in batches, usually within about an hour of the event. A batch can contain events from earlier periods that arrived late.
  • Expect new values. New event types, action types and fields may be added over time. Ignore values you don't recognize rather than rejecting the record. Existing fields won't be renamed or removed without notice.
  • Expect volume to follow usage. The web app records an event for each action it performs, including the regular refreshes some pages make while open, so an active user can produce many events per minute.

FAQ

Does the log include other organizations' activity?
No. Your log contains only events for your organization.

Can I enable the log, or change what it includes, myself?
No. The log is set up by the Axle team. Contact your Axle representative to enable it, change where it's delivered or ask about its contents.

Why is a user's sign-in missing from my log?
Sign-ins are recorded against the user's home organization. If that is a different Axle organization, the sign-in is recorded there.

Why don't I see failed sign-ins for an email address?
Failed sign-ins are recorded only for email addresses that belong to a user in your organization.

Are changes made by an AI assistant recorded?
Yes, whether they're made in the Axle web app's built-in assistant or through the Axle MCP server. The actor is the user the assistant acted for.

Who do I contact with questions?
Your Axle account representative.


Did this page help you?