SIEM Integration Guide
Integrate Iden security events into your SIEM platform using the Events API.
Iden captures security-relevant events across your identity governance workflows: logins, access changes, app syncs, account provisioning, and more. The Events API lets you stream these into your SIEM platform (Splunk, OpenSearch, Microsoft Sentinel, Datadog, etc.) for centralized monitoring and incident response.
Rate Limit
The Events API is limited to 60 requests per minute per API key. Exceeding this returns 429 Too Many Requests with a Retry-After header. At the recommended polling interval of 30–60 seconds, you'll use 1–2 requests per minute, well within the limit. See Rate Limiting for details.
Quick Start
1. Get your API key
Go to Settings → API Keys in your Iden dashboard (app.idenhq.com/api-keys or app.in.idenhq.com/api-keys depending on your data residency region). Create a key and note your organization slug (visible on the same page).
2. Fetch your first events
curl -H "Authorization: Api-Key YOUR_KEY" \
"https://developer.idenhq.com/org/{your-slug}/api/events/?limit=5"3. Set up incremental polling
Use cursor-based pagination to poll for new events without missing any or receiving duplicates.
import requests
import time
API_KEY = "YOUR_KEY"
BASE_URL = "https://developer.idenhq.com/org/{your-slug}/api/events/"
cursor = None
while True:
params = {"limit": 200}
if cursor:
params["cursor"] = cursor
resp = requests.get(
BASE_URL,
headers={"Authorization": f"Api-Key {API_KEY}"},
params=params,
)
resp.raise_for_status()
data = resp.json()
for event in data["results"]:
push_to_siem(event) # your SIEM ingestion function
cursor = data.get("next_cursor")
if not data["results"]:
time.sleep(60) # no new events, wait before polling againThe response includes next_cursor and previous_cursor. Pass next_cursor as the cursor parameter in your next request. When results is empty, wait 60 seconds before polling again.
Event Envelope
Every event returned by the API follows the same JSON structure:
{
"event_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event_type": "session.login.succeeded",
"event_version": 1,
"category": "authentication",
"severity": "low",
"occurred_at": "2026-04-08T14:30:00.000Z",
"ingested_at": "2026-04-08T14:30:00.123Z",
"actor": {
"type": "user",
"uuid": "11111111-1111-1111-1111-111111111111",
"ip": "203.0.113.42",
"user_agent": "Mozilla/5.0 ..."
},
"subject": {
"type": "iden_user",
"uuid": "11111111-1111-1111-1111-111111111111"
},
"source": {
"type": "user_action",
"uuid": null
},
"payload": {
"login_method": "google"
}
}Field Reference
| Field | Type | Description |
|---|---|---|
event_id | UUID | Globally unique event identifier |
event_type | string | Dot-notated event type (e.g. session.login.succeeded). See Event Type Catalog for all types. |
event_version | integer | Schema version (currently 1) |
category | string | Computed from event type prefix. See Categories. |
severity | string | Computed severity level. See Severity Mapping. |
occurred_at | ISO 8601 | When the event happened |
ingested_at | ISO 8601 | When Iden recorded the event |
actor | object | Who or what triggered the event |
actor.type | string | user, system, service, or iden_admin |
actor.uuid | UUID | Actor's Iden user UUID. null for system-triggered events. |
actor.ip | string | IP address of the actor (when available) |
actor.user_agent | string | Browser/client user agent (when available) |
subject | object | The entity the event is about |
subject.type | string | iden_user, app_user, app, app_group, task, ticket, or system |
subject.uuid | UUID | UUID of the subject entity |
source | object | What triggered the event |
source.type | string | user_action, system, sync, schedule, api, or task |
payload | object | Event-specific data. See Event Type Catalog for payload fields per event type. |
Pagination
The Events API uses cursor-based pagination for reliable incremental polling. This ensures you never miss events or receive duplicates, even if new events are created while you're paginating.
{
"next_cursor": "cD0yMDI2LTA0LTA4VDE0...",
"previous_cursor": "cD0yMDI2LTA0LTA4VDE0...",
"results": [...]
}| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
cursor | string | - | - | Opaque cursor from a previous response |
limit | integer | 50 | 200 | Number of events per page |
Events are returned in reverse chronological order (newest first). To poll for new events, store the next_cursor from your last successful response and pass it in subsequent requests.
Filtering
Use query parameters to narrow results. All filters can be combined.
By event type (exact)
Filter for a specific event type. See the Event Type Catalog for all available values.
GET /api/events/?event_type=session.login.succeededBy event type prefix
The prefix must end with . (this prevents partial matches).
# All session events (login, logout, expired, blocked)
GET /api/events/?event_type_prefix=session.
# All app sync events
GET /api/events/?event_type_prefix=app.sync.
# All account lifecycle events
GET /api/events/?event_type_prefix=account.
# All access ticket events (created, approved, denied)
GET /api/events/?event_type_prefix=ticket.
# All API key events (created, revoked, used)
GET /api/events/?event_type_prefix=api_key.
# All user lifecycle events
GET /api/events/?event_type_prefix=user.By category
Filter by logical category. Each category maps to one or more event type prefixes. See Categories for the full mapping.
# All authentication events (session.*, warp.*, api_key.*)
GET /api/events/?category=authentication
# All authorization events (account.*, ticket.*)
GET /api/events/?category=authorization
# All application events (app.*)
GET /api/events/?category=application
# All user identity lifecycle events
GET /api/events/?category=user_lifecycleBy severity
Comma-separated list of severity levels. See Severity Mapping for which events map to which level.
# Critical and high only
GET /api/events/?severity=critical,high
# Medium and above
GET /api/events/?severity=critical,high,mediumBy time range
ISO 8601 timestamps.
GET /api/events/?occurred_at__gte=2026-04-01T00:00:00Z&occurred_at__lte=2026-04-08T23:59:59ZBy actor or subject
# Events triggered by a specific user
GET /api/events/?actor_uuid=a1b2c3d4-...
# Events about a specific entity
GET /api/events/?subject_uuid=a1b2c3d4-...
# Events from a specific IP address
GET /api/events/?actor_ip=203.0.113.42Filter Parameters Reference
| Parameter | Type | Example | Description |
|---|---|---|---|
event_type | string | session.login.succeeded | Exact match. See Event Type Catalog. |
event_type_prefix | string | session. | Prefix match (must end with .). |
category | string | authentication | Category filter. See Categories. |
severity | string | critical,high | Comma-separated. See Severity Mapping. |
occurred_at__gte | ISO 8601 | 2026-04-01T00:00:00Z | Events at or after this timestamp |
occurred_at__lte | ISO 8601 | 2026-04-08T23:59:59Z | Events at or before this timestamp |
actor_uuid | UUID | a1b2c3d4-... | Filter by actor UUID |
subject_uuid | UUID | a1b2c3d4-... | Filter by subject UUID |
actor_ip | string | 203.0.113.42 | Filter by actor IP address |
Categories
Events are grouped into categories based on the event type prefix. Use the category filter parameter to query by category.
| Category | Prefixes | Description |
|---|---|---|
authentication | session.*, warp.*, api_key.* | Login, logout, session expiry, IP blocks, browser/API based app connections, and API key usage |
authorization | account.*, ticket.* | Account provisioning, deprovisioning, suspension, access tickets, and group membership changes |
application | app.* | App connections, syncs, disconnections, and configuration changes |
task | task.* | Task lifecycle |
user_lifecycle | user.* | IdenUser lifecycle: creation, profile updates, deactivation, reactivation and deletion |
Severity Mapping
Severity is computed from the event type. Use the severity filter to query by level. Events not listed below default to info.
Critical
| Event Type | Description |
|---|---|
session.ip_blocked | IP address blocked after repeated failed login attempts |
High
| Event Type | Description |
|---|---|
session.login.failed | Failed login attempt |
task.failed | Task failed |
ticket.denied | Access ticket denied |
user.deactivated | IdenUser account deactivated |
account.deprovisioned | User account deprovisioned (access removed) |
Medium
| Event Type | Description |
|---|---|
app.sync.failed | App sync failed |
task.dispatch_blocked | Task blocked from dispatch |
Low
| Event Type | Description |
|---|---|
session.login.succeeded | Successful login |
session.logout | User logged out |
task.completed | Task completed |
user.updated | IdenUser profile updated |
app.created | New app connected |
Info (default)
All other event types.
Event Type Catalog
A complete reference of all event types available through the Events API.
Authentication
Session
| Event Type | Description |
|---|---|
session.login.succeeded | User successfully logged in |
session.login.failed | Failed login attempt |
session.logout | User logged out |
session.ip_blocked | IP address blocked after repeated failed login attempts |
session.expired | Session expired |
Warp
| Event Type | Description |
|---|---|
warp.login.attempted | Browser/API based app login initiated via Warp |
warp.login.failed | Browser/API based app login failed via Warp |
API Keys
| Event Type | Description |
|---|---|
api_key.created | Lighthouse API key created |
api_key.revoked | Lighthouse API key revoked or deleted |
api_key.used | Lighthouse API key used to authenticate a request |
Authorization
Account Lifecycle
| Event Type | Description |
|---|---|
account.provisioned | User account granted access to an app |
account.deprovisioned | User account removed from an app |
account.activated | User account activated in an app (went from invited state to active) |
account.suspended | User account suspended in an app |
account.unsuspended | Suspended user account reactivated |
account.group.added | User account added to an app group |
account.group.removed | User account removed from an app group |
Tickets
| Event Type | Description |
|---|---|
ticket.created | Access request ticket created |
ticket.approved | Access request ticket approved |
ticket.denied | Access request ticket denied |
Application
| Event Type | Description |
|---|---|
app.created | New app connected to Iden |
app.connected | App connection established successfully |
app.disconnected | App disconnected from Iden |
app.sync.started | App sync initiated |
app.sync.completed | App sync completed successfully |
app.sync.failed | App sync failed |
app.sync.paused | App sync paused |
app.connection_request.created | New app connection request submitted |
Task
| Event Type | Description |
|---|---|
task.created | Task created in the system |
task.dispatched | Task dispatched to a runner |
task.completed | Task completed successfully |
task.failed | Task failed |
task.retried | Task retried after failure |
task.preempted | Task preempted by a higher-priority task |
task.cancelled | Task cancelled |
task.dispatch_blocked | Task blocked from dispatch due to a conflict |
Identity
| Event Type | Description |
|---|---|
user.created | IdenUser created in the system |
user.updated | IdenUser profile updated (domain type or manager changed) |
user.deactivated | IdenUser account deactivated |
user.reactivated | IdenUser account reactivated |
user.deleted | IdenUser hard-deleted from the system |
user.identity_type.changed | IdenUser identity type changed (e.g. human → service_account) |
Rate Limiting
The Events API is rate-limited to 60 requests per minute per API key. A global rate limit of 300 requests per minute per IP also applies across all Lighthouse endpoints.
When you exceed the limit, the API returns 429 Too Many Requests with a Retry-After header indicating how many seconds to wait.
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Content-Type: application/json
{"detail": "Request was throttled. Expected available in 42 seconds."}At a recommended polling interval of 30–60 seconds with limit=200, you will use 1–2 requests per minute, well within the limit.
SIEM Platform Examples
These examples use the incremental polling pattern from Quick Start.
OpenSearch / Elasticsearch
Index each event by event_id to ensure idempotent ingestion. Use monthly indices for lifecycle management.
from opensearchpy import OpenSearch
client = OpenSearch(["https://your-cluster:9200"])
for event in events:
index = f"iden-events-{event['occurred_at'][:7]}" # e.g. iden-events-2026-04
client.index(
index=index,
id=event["event_id"], # idempotent; re-ingesting the same event is a no-op
body=event,
)Splunk (HEC)
Use the HTTP Event Collector with event_id as a unique identifier and occurred_at as the event time.
import requests
HEC_URL = "https://your-splunk:8088/services/collector/event"
HEC_TOKEN = "your-hec-token"
for event in events:
requests.post(
HEC_URL,
headers={"Authorization": f"Splunk {HEC_TOKEN}"},
json={
"time": event["occurred_at"],
"sourcetype": "iden:siem:event",
"event": event,
},
)Microsoft Sentinel
Use an Azure Logic App or Function App to poll the Iden Events API and push events via the Azure Monitor Data Collector API.
Datadog
Use a custom integration script that polls the Events API and sends events via the Datadog Logs API (POST /api/v2/logs).
Best Practices
- Poll every 30–60 seconds with
limit=200for near-real-time ingestion without hitting rate limits. - Always use cursor pagination. Never use time-based offsets, which can miss events or produce duplicates.
- Store your cursor persistently (database, file, etc.) so you can resume after restarts without re-ingesting.
- Use
event_idas the deduplication key in your SIEM. This ensures idempotent ingestion even if you accidentally re-poll the same range. - Filter at the source using query parameters rather than fetching all events and filtering client-side.