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/pingThe 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.
| Feed | Volume | Forward it when |
|---|---|---|
/security-alerts | Low | Always. These are Defender / Sentinel detections, already enriched with the users, groups, and apps they touch. |
/monitoring-alerts | Low | Always. This is what your own 1Security policies detected, and it exists nowhere else. |
/logs | High - the full activity feed | You 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=1000and 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.nextCursorinto thecursorquery parameter; stop whenhasMoreisfalse. - 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), orfirstActivityDateTime(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 time | occurredAt | lastScan | firstActivityDateTime |
| Ingest time | discoveredAt | - | - |
| Dedup key | id | id | id |
| Severity | severity | severity | severity |
| Actor | actorName, actorId, actorIp | assignedUser | actorDisplayName |
| Resource | resourceName, resourceType | resources, resourceType | users, groups, apps |
| Rule / title | action | name | title |
| Status | - | status, isResolved | status, 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 theTandZ(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
NIS2
Meet NIS2's 24-hour and 72-hour incident reporting deadlines with three years of forensic history, live risk visibility, and evidence for every Article 21 measure - on standard Microsoft 365 licenses.
API Reference
The read-only REST API for pulling 1Security audit logs, monitoring alerts, and security alerts into a SOC, MSSP, or SIEM.