# Audit log export

Stream your organization's audit trail to your own security tooling. seekrit
ships every new audit event — writes, grants, revocations, token and lease
actions, denied resolves — to an **OTLP/HTTP logs endpoint** as OpenTelemetry
log records, so you can alert, retain, and correlate seekrit activity alongside
the rest of your infrastructure.

![The Audit trail page: rows of append-only events such as token.revoked, env.group_linked, secret.restored, and env.key_granted, each with actor, resource, and detail columns](https://seekrit.dev/screenshots/original/dashboard-audit-trail.webp)

*The same events in the dashboard's audit trail — this is what gets exported, one OTLP log record per row.*

> **Note:** Exported records carry only what's already in your audit log: action, attribution (user or service token), IP, resource ids, and redacted metadata (names and counts). They **never** contain secret values, ciphertext, private keys, passphrases, or token strings.

> **Note:** Audit log export is a **plan feature** (**Audit log export (SIEM)**). Your [plan & billing](/docs/guides/billing) page shows whether your plan includes it; organizations on a plan without it see an upgrade prompt in place of the configuration form.

## How it works

A per-organization background sweep runs **every minute**. For each configured
sink it finds audit rows newer than a stored watermark, POSTs them to your
endpoint as an OTLP `LogsData` payload (`content-type: application/json`), and
advances the watermark **only after your collector returns a 2xx**. Delivery is
therefore **at-least-once**: if your endpoint is briefly unavailable, the same
events re-ship on a later tick rather than being dropped (repeated failures back
off exponentially, up to a few minutes between attempts).

Each event becomes one log record:

- **Body** — the audit action (e.g. `secret.created`, `token.revoked`).
- **Severity** — `WARN` for revocations, deletions, and denied resolves; `INFO`
  otherwise, so you can alert on security-significant events directly.
- **Attributes** — `audit.id`, `audit.action`, `audit.resource_type`,
  `audit.resource_id`, `actor.type`, `actor.id`, `client.address`, and the
  event's redacted metadata as `audit.metadata.*`.
- **Resource** — `service.name=seekrit`, plus `seekrit.org.id` and
  `seekrit.org.slug`.

## Configure a sink

In the dashboard, open your organization → **settings** (admins only), or from
the CLI:

```bash
seekrit log-sink set https://collector.example.com/v1/logs \
  --header "Authorization: Bearer $COLLECTOR_TOKEN"

seekrit log-sink            # endpoint, header names, and delivery health
```

Or against the API directly:

```bash
curl -X PUT https://api.seekrit.dev/v1/orgs/$ORG/log-sink \
  -H "authorization: Bearer $SEEKRIT_TOKEN" \
  -H "content-type: application/json" \
  -d '{
        "endpoint": "https://collector.example.com/v1/logs",
        "headers": { "Authorization": "Bearer <your-collector-token>" },
        "enabled": true
      }'
```

- **Endpoint** — the full OTLP/HTTP logs URL, typically ending in `/v1/logs`.
- **Headers** — sent with every export request; use these for your collector's
  auth (e.g. `Authorization`, or `DD-API-KEY` for Datadog). They are **encrypted
  at rest** and never returned — reads only ever show the header *names*. Omit
  `headers` on a later update to keep the stored value; pass `{}` to clear it
  (`--header` and `--clear-headers` respectively, from the CLI).
- **Enabled** — toggle export off without deleting the configuration.

When first enabled, the watermark starts at the newest existing audit event, so
you receive events from that point forward rather than a backfill of history.

## Test the connection

Send a synthetic event to verify connectivity and auth before you rely on it —
click **Send test event** in the dashboard, or:

```bash
seekrit log-sink test    # exits non-zero on failure, so it works as a health check
```

```bash
curl -X POST https://api.seekrit.dev/v1/orgs/$ORG/log-sink/test \
  -H "authorization: Bearer $SEEKRIT_TOKEN"
# → { "ok": true, "status": 200, "error": null }
```

The dashboard and `seekrit log-sink` both surface the last successful export
time and the last error, so a misconfigured endpoint is easy to spot.

> **Warning:** The header you configure is a credential for **your** collector. Anyone with admin access to the organization can change the endpoint — treat the ability to reconfigure the sink as security-sensitive, and prefer a scoped, rotatable token over a long-lived one.
