Help Center
SIEM Integration

SIEM Integration

PurpletGo forwards every audit log event to your SIEM in real time, as it is written, plus three revocation and status events with extra detail. Six target types are supported out of the box: Splunk (HTTP Event Collector), Datadog (Log Intake), Elasticsearch (single-document index API), Sumo Logic (HTTP Source), New Relic (Log API), and a generic HMAC-signed webhook for anything else. Splunk and generic targets can take events as JSON or as CEF (Common Event Format).

SIEM export is available on the Enterprise plan. Admins and Super Admins can manage targets (members with a custom role need the Manage organisation settings permission).

Why forward events to a SIEM

Offboarding is a high-risk period for data exfiltration and access abuse. Forwarding PurpletGo events to your SIEM lets security teams:

  • Correlate offboarding activity with access log anomalies in real time
  • Maintain an independent copy of offboarding-related events for compliance audits
  • Detect and alert on unusual patterns around access revocation and role changes

Configuring a SIEM target

Navigate to Settings → SIEM Export (a separate settings tab from Webhooks) and click Add Target. Every target needs a name, a type, and an endpoint_url the target's own auth token is sent to - the URL can't point at a loopback, link-local or private-network address, since PurpletGo will be making outbound requests to it on every matching event. The address is checked again each time PurpletGo sends to it, and redirects are never followed: the endpoint must accept the event itself.

When you edit a target, the stored token is never shown. Leave the token field blank to keep it, or enter a new one to replace it.

Get your HEC endpoint and token

In Splunk, create a new HTTP Event Collector (HEC) input. Copy the HEC URL (e.g., https://your-splunk.example.com:8088/services/collector) and the generated token.

Enter details in PurpletGo

Select Splunk as the target type and paste the HEC URL as the endpoint and the token as the auth token. PurpletGo sends Authorization: Splunk <token> and wraps each event as { time, sourcetype: "purpletgo:security", source: "purpletgo", event } - there's no separate index or sourcetype field to configure.

Choose the events and the format

Under Events to stream, keep All events (recommended) or pick Only the events I choose and tick them from the list (see Events below). Under Payload format, choose JSON or CEF: see CEF.

Save and test

Click Save, then use Test to fire a synthetic siem_test event at your endpoint. PurpletGo waits for the answer: the test only reports success if Splunk accepted the event, and otherwise tells you why it failed (for example the HTTP status Splunk returned).

Elasticsearch and Sumo Logic targets follow the same pattern as above - Elasticsearch expects your <index>/_doc URL and an ApiKey auth header; Sumo Logic just posts to your unique HTTP Source collector URL, which is itself the auth mechanism, so no token header is sent. New Relic targets send your Log API endpoint an Api-Key header and a body shaped as [{ message: "PurpletGo event: <type>", attributes: <event payload> }].

Delivery behavior

Every event for every target is queued in PurpletGo's database before it is sent, so a restart or a deploy loses nothing. Each delivery is one request; when the collector refuses it, can't be reached or doesn't answer within 10 seconds, PurpletGo tries again later, waiting about 1 minute, then 2, 4, 8 and so on, doubling each time with some random spread, for 12 retries: at least 68 hours in all. A generic target's X-PurpletGo-Delivery id stays the same on every attempt of a delivery, so your receiver can drop a retry it already processed. Events are delivered in the background, so a SIEM outage never blocks or delays the PurpletGo action itself, and deliveries are not guaranteed to arrive in order: use each event's timestamp (or occurred_at for audit events) to order them.

A delivery is given up on when every retry has failed, or at once when retrying can't help: the endpoint is not a public address, the collector answers with a redirect, or it rejects the payload itself (HTTP 400, 413 or 422). A 401, 403 or 404 is retried, so fixing a wrong token or URL within the retry window still delivers what was waiting.

Each target shows its last delivery time and status, the running delivery count, the last error when the last delivery failed, and how many deliveries were given up. A target can be paused and reactivated without deleting it; while it is paused, or the organization is read-only, nothing is queued for it, and deliveries already queued are dropped when their turn comes.

Batch export replays the audit log of a date range to one target: pick the target and the range, and PurpletGo queues the entries, oldest first, up to 10,000 at a time. When the range holds more, choose Queue More to queue the next 10,000 (the API returns a next_cursor to send back). Queued entries are delivered in the background with the same retries, and the target's counts show how it is going. Entries about a former employee whose data was erased are sent with [erased] in place of their name, email address and other personal details (Data retention).

Events

A target receives every event, or only the ones you choose for it.

Every audit log entry is sent in real time, as soon as it is written, with its audit action as event_type (for example login_failed, offboarding_deleted or siem_target.created) and these fields: audit_id, action, target, details, actor_id, actor_name and occurred_at. The list of actions to choose from is in the target dialog, and from the API at GET /api/siem-targets/events. A target you add starts receiving events within 30 seconds; to fill in anything written in those seconds, use Batch export for that time range.

Three events carry more detail than their audit entry:

EventSent when
access_revokedAfter every revocation run, whether someone clicked Nuke Access or it ran at the end of the last day
revocation_failedAlongside access_revoked, with the same data, when any app in the run failed or needs removing by hand
status_changedAn offboarding moves to another stage, from any source (the app, bulk actions, the API, automation rules or the schedule). Sent once, as this event, not again as its audit entry

These are delivered as high severity: access_revoked, revocation_failed, status_changed, offboarding_deleted, member_removed, audit_log_exported, login_failed and checklist_completed. Everything else (like the siem_test event fired by Test) is delivered as info.

Payload format

Every event carries the same base envelope, regardless of target type:

{
  "event_type": "access_revoked",
  "source": "purpletgo",
  "org_id": "9f2b3c1a-...",
  "timestamp": "2025-03-15T09:42:11.000Z",
  "severity": "high"
}

source is always purpletgo. The fields specific to the event are merged into this same object, and what started the event is in trigger:

EventFields
access_revoked, revocation_failedoffboarding_id, employee_name, revoked_services (the apps in the run), revocation_results (one result per app, including service, outcome, message and vendorStatus: the vendor's HTTP status when it refused, otherwise null), actor_id, trigger (app or schedule)
status_changedoffboarding_id, new_status, previous_status, employee_name, employee_email, exit_date, actor_id, trigger (app, bulk, api, automation or schedule), and bulk: true for a bulk action

How that object gets wrapped depends on the target type - Splunk gets it under an event key with HEC metadata, Datadog gets it JSON-stringified into a message field, and so on, as described above.

CEF

With Payload format set to CEF, Splunk and generic targets get each event as one line of ArcSight Common Event Format instead of JSON. A Splunk target receives it as the HEC event with sourcetype: "cef"; a generic target receives the line as the request body (Content-Type: text/plain), HMAC-signed as above. The other target types always take JSON.

CEF:0|PurpletGo|PurpletGo|1.0|offboarding_deleted|Offboarding deleted|7|rt=1790856000000 act=offboarding_deleted cat=high suser=Ann Admin suid=6c1e... externalId=9e1c... cs1=9f2b... cs1Label=orgId cs2=Jordan Lee cs2Label=target msg=...
CEFFrom
Signature ID, Nameevent_type, and a readable name made from it
Severity7 for a high event, 3 for info
rtWhen it happened (occurred_at, else timestamp), milliseconds since 1970
act, catevent_type, severity
suser, suidactor_name, actor_id
duser, dntdom, duidemployee_name, the domain of employee_email, offboarding_id
externalIdaudit_id for an audit event, else offboarding_id
msgdetails for an audit event; a summary for a revocation or status change
cs1 (orgId), cs2 (target), cs3 (trigger), cs4 (statusChange)org_id; the audit entry's target; what started the event; previous_status -> new_status
cn1 (appsInRun), flexString1 (revocationResults)The number of apps in a revocation run, and the per-app results as JSON
cs5 (origin)batch_export for an event from a batch export

In the header, | and \ are escaped with a backslash; in values, = and \ are, and a line break becomes \n. Fields an event doesn't have are left out. A SIEM that needs every field of an event uses JSON.

Related pages