1Security
Guides

SIEM Integration

Forward 1Security audit logs, monitoring alerts, and security alerts into Splunk, Microsoft Sentinel, QRadar, Elastic, or any SIEM that can poll a REST endpoint.

This guide covers wiring 1Security into a SIEM end to end: what to forward, the polling loop that keeps the feed complete, and how to connect it to the common platforms. The API contract itself - every endpoint, parameter, and field - is in the API reference.

The model is pull-based. Your SIEM polls on a schedule and stores a watermark, so each poll fetches only what is new. No inbound connectivity to your network is required.

Before you start

You need an API key with the scopes for the feeds you plan to forward. Create it in the dashboard under Settings → API Keys (admin only) and copy the 1sec_live_… secret - it is shown once.

Confirm it works before building anything around it:

curl -H "Authorization: Bearer $ONESEC_API_KEY" \
  https://api.1security.ai/api/v1/ping

The response echoes the tenant and the scopes the key carries. If a scope you expected is missing, fix it now rather than debugging a 403 from inside a connector.

1. Decide what to forward

The three feeds answer different questions, and they have very different volumes. Most teams start with the two alert feeds and add logs once the mapping is settled.

FeedVolumeForward it when
/security-alertsLowAlways. These are Defender / Sentinel detections, already enriched with the users, groups, and apps they touch.
/monitoring-alertsLowAlways. This is what your own 1Security policies detected, and it exists nowhere else.
/logsHigh - the full activity feedYou want M365 activity in the SIEM with permission, device, and location context attached.

On a busy tenant /logs is the feed that drives SIEM licence cost. Filter at the API rather than after ingest: severity=high,critical or a specific action list keeps the volume proportional to what your detections actually use. You can always widen it later.

2. The polling loop

Poll a closed time window and move the watermark only after the window has drained completely.

Closing the window is what makes this reliable. An open-ended query keeps growing while you page through it - new events land at the head of the ordering and shift rows between requests. A window with both ends bound is a fixed set: it cannot change while you read it.

Window by ingestion time

For /logs, use discoveredFrom and discoveredTo, not from and to. discoveredAt is when 1Security ingested the event; occurredAt is when it happened in M365. Microsoft can surface events hours after the fact, and only ingestion time is monotonic - so only ingestion time guarantees you never miss a late arrival.

For the alert feeds, from and to window on when the alert was raised.

Leave a short lag

End the window a minute or two behind the current clock rather than at "now". Events are still committing at the boundary, and a small lag keeps one from landing just after you read past it.

Sort ascending and drain

Add sort=discoveredAtAsc on /logs. That ordering is tie-broken by event id, so every row has exactly one position in the page sequence. Follow pagination.nextCursor with ?cursor= until hasMore is false.

Advance only on success

Move the watermark to the end of the window you just drained, and only after every page succeeded. If any page fails, keep the old watermark and retry the whole window - re-reading is cheap, and id dedupe absorbs the overlap.

A complete poller, small enough to read in one sitting:

#!/usr/bin/env bash
set -euo pipefail

STATE_FILE=/var/lib/1security/watermark
LAG_SECONDS=120   # stay slightly behind now, so nothing commits past the edge

SINCE=$(cat "$STATE_FILE" 2>/dev/null || date -u -d '-1 hour' +%FT%TZ)
UNTIL=$(date -u -d "-${LAG_SECONDS} seconds" +%FT%TZ)

BASE="https://api.1security.ai/api/v1/logs"
QUERY="discoveredFrom=$SINCE&discoveredTo=$UNTIL&sort=discoveredAtAsc&limit=1000"
CURSOR=""

while :; do
  URL="$BASE?$QUERY"
  [ -n "$CURSOR" ] && URL="$URL&cursor=$CURSOR"

  RESP=$(curl -sS --fail-with-body \
    -H "Authorization: Bearer $ONESEC_API_KEY" "$URL")

  echo "$RESP" | jq -c '.data[]' >> /var/log/1security-logs.ndjson

  CURSOR=$(echo "$RESP" | jq -r '.pagination.nextCursor // empty')
  [ -z "$CURSOR" ] && break
done

# Reached only if every page succeeded.
echo "$UNTIL" > "$STATE_FILE"

Run it every one to five minutes. Overlapping windows slightly and relying on id dedupe in the SIEM is safer than trying to hit exact boundaries.

3. The first run

Backfilling history is the same loop with a fixed sequence of windows instead of one rolling window. 1Security retains activity for up to three years, so decide how far back your SIEM actually needs before you start.

  • Walk the range in fixed chunks - one to six hours each, depending on tenant size. Each chunk is a closed window, so each is independently restartable.
  • Keep limit=1000 and stay inside the rate limit of 600 requests per minute.
  • Log which chunk you are on. If the backfill dies, you resume at that chunk rather than from the beginning.
  • Run the backfill and the live poll as separate jobs with separate watermarks. Let the live poll start from now, and let the backfill work backwards behind it, so live coverage is never waiting on history.

4. Alerts change after they are raised

Logs are immutable: once ingested, an event never changes. Alerts are not - they get assigned, snoozed, and resolved after they first appear. A watermark-only poll captures the moment an alert was raised and never sees what happened to it afterwards.

If your SOC works alerts inside the SIEM, add a reconciliation sweep next to the incremental poll: on a slower schedule, say hourly, re-fetch alerts raised in the last N days regardless of the watermark and upsert them on id. State changes then land within one sweep.

# Hourly reconciliation - re-read the last 7 days and upsert on id
curl -H "Authorization: Bearer $ONESEC_API_KEY" \
  "https://api.1security.ai/api/v1/monitoring-alerts?from=$(date -u -d '-7 days' +%FT%TZ)&limit=1000"

Size the sweep window to how long an alert typically stays open in your process. isResolved and resolvedAt tell you where each one ended up.

5. Wire it into your SIEM

Use the Codeless Connector Platform, or a Logic App if you want explicit control over the loop.

  • Auth: Authorization: Bearer <key> as a connection secret.
  • Paging: follow pagination.nextCursor into the cursor query parameter; stop when hasMore is false.
  • Destination: post data[] to a custom table in Log Analytics through a Data Collection Endpoint and rule.
  • TimeGenerated: map from occurredAt (logs), lastScan (monitoring alerts), or firstActivityDateTime (security alerts).
  • State: store the window end in the connector's state, and advance it only after a complete drain.

Because 1Security also ingests Defender and Sentinel alerts, forwarding /security-alerts back into Sentinel can duplicate what is already there. Most teams forward /monitoring-alerts and /logs to Sentinel and leave /security-alerts for SIEMs that do not already have that source.

6. Field mapping

Use for/logs/monitoring-alerts/security-alerts
Event timeoccurredAtlastScanfirstActivityDateTime
Ingest timediscoveredAt--
Dedup keyididid
Severityseverityseverityseverity
ActoractorName, actorId, actorIpassignedUseractorDisplayName
ResourceresourceName, resourceTyperesources, resourceTypeusers, groups, apps
Rule / titleactionnametitle
Status-status, isResolvedstatus, classification

Two normalization details worth handling up front:

  • Severity vocabularies differ. Logs and monitoring alerts use info · low · medium · high · critical. Security alerts follow Microsoft's scale: informational · low · medium · high · unknown. Map both into your SIEM's own scale rather than passing the strings through.
  • Timestamps. Logs and security alerts return full ISO-8601 with a Z. Monitoring alerts currently return the same UTC instant without the T and Z (2026-06-05 09:12:44). Parse it as UTC. A future release unifies this on ISO-8601 everywhere.

7. Operating the integration

What is coming

Planned improvements to this integration path, so you can design around them:

  • Webhook push delivery, removing the polling loop for alert feeds.
  • An OpenAPI specification, plus reference connectors for Sentinel and Splunk, so the wiring in section 5 becomes an import rather than a build.
  • Organization-level keys for MSSPs, so one connector covers a whole portfolio of tenants instead of one key per tenant.
  • Bidirectional sync, so resolving an alert in the SIEM resolves it in 1Security.

Next

On this page