
# List logs

`GET /v1/logs` · permission `logs:read`

Lists the environment's log records (sign-ins, sessions, tokens, MFA, attack protection and more) with cursor pagination, newest first. Records older than your plan's retention window (Free 7, Startup 14, Business 30, Enterprise 90 days) are never returned.

## Request

| Parameter | In | Required | Description |
|---|---|---|---|
| `limit` | query | no | Page size, 1 to 100. Default 20. |
| `after` | query | no | Opaque cursor from `list_metadata.after` (older records). Exclusive with `before`. |
| `before` | query | no | Opaque cursor from `list_metadata.before` (newer records). Exclusive with `after`. |
| `from` | query | no | RFC 3339 time; records at or after it. Must be inside the retention window. |
| `to` | query | no | RFC 3339 time; records before it. Must be later than `from`. |
| `type` | query | no | Log type prefix such as `authentication.` or `session.created`. Repeat the parameter for up to 20 values; a record that matches any of them is returned. |
| `outcome` | query | no | `success`, `failure`, `denied` or `error`. |
| `user_id`, `org_id`, `application_id`, `connection_id`, `directory_id`, `session_id` | query | no | Exact match on the prefixed id (`usr_`, `org_`, `app_`, `conn_`, `dir_`, `ses_`). |
| `request_id` | query | no | `Idp-Request-Id` of a request (UUID), for example the id shown on a hosted sign-in error page. |
| `correlation_id` | query | no | `Idp-Correlation-Id` of a workflow (UUID). |
| `ip` | query | no | IP address or CIDR block (`203.0.113.0/24`). Requires `audit-events:read_ip`. |
| `ip_country` | query | no | Country of the IP, ISO 3166-1 alpha-2 in upper case (`DE`). |
| `q` | query | no | Prefix of the masked identifier hint (`j***@`). Requires `users:read_pii`. |

Records are always ordered by `occurred_at`, newest first; there is no `order` parameter (`order=desc` is accepted, any other value fails with `validation_failed`). A cursor is only valid with the filters it was issued for.

The `ip` and `q` filters need their permission even though they only narrow the result: without it the request fails with `403 insufficient_permissions` before any search, so a key cannot probe values it is not allowed to read.

## Response

`200 OK`. `data` holds the records on the page; `list_metadata.after` points to older records and `list_metadata.before` to newer ones (`null` when there are none). No total count is returned. Empty fields are `null`.

`ip`, `ip_asn`, `user_agent` and `user_agent_family` are present only when the key has the `audit-events:read_ip` permission, and `identifier_hint` only when it has `users:read_pii`. Without the permission the field is left out entirely (no masked value). `ip_country` is always returned.

```json
{
  "data": [
    {
      "id": "evt_01j9xk3m7q8r2s4t6v8w0y2z4a",
      "occurred_at": "2026-10-01T08:15:42.120Z",
      "type": "authentication.password.failed",
      "outcome": "failure",
      "reason_code": "invalid_credentials",
      "user_id": "usr_0a1b2c3d4e5f6g7h8j9k0m1n2p",
      "org_id": null,
      "application_id": "app_01j9xk3m7q8r2s4t6v8w0y2z4b",
      "connection_id": "conn_01j9xk3m7q8r2s4t6v8w0y2z4c",
      "directory_id": null,
      "session_id": null,
      "identifier_hint": "a***@e***.com",
      "ip": "203.0.113.7",
      "ip_country": "DE",
      "ip_asn": 64500,
      "user_agent": "Mozilla/5.0 (X11; Linux x86_64)",
      "user_agent_family": "Firefox",
      "risk": null,
      "auth_context": null,
      "act_chain": null,
      "details": {"attempt": 3},
      "request_id": "0192a6c1-7d3e-7a10-9b2c-3d4e5f607182",
      "correlation_id": null,
      "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
    }
  ],
  "list_metadata": {
    "before": null,
    "after": "<opaque cursor>"
  }
}
```

## Errors

Every error is an `application/problem+json` body with a stable `code`.

| HTTP | `code` | When |
|---|---|---|
| 400 | `invalid_cursor` | The cursor is malformed or was not issued for this request. |
| 400 | `invalid_filter` | The log service rejected a filter or the cursor. |
| 400 | `range_outside_retention` | `from` is earlier than the retention window of your plan. |
| 422 | `validation_failed` | A query parameter is invalid (`limit` out of range, bad timestamp, `to` not after `from`, more than 20 `type` values, malformed id or IP, repeated parameter). |
| 401 | `unauthenticated` | The API key is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The key lacks `logs:read`, or uses `ip` without `audit-events:read_ip` or `q` without `users:read_pii` (`required_permissions` lists what the request needs). |
| 429 | `rate_limited` | The rate limit was exceeded; honor `Retry-After`. |
| 503 | `service_unavailable` | A dependency is temporarily unavailable; retry later. |

## Example

```bash
curl "https://api.eu.keenauth.com/v1/logs?type=authentication.&outcome=failure&from=2026-10-01T00:00:00Z" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
```

## Personal data

This endpoint carries personal data: environment logs. [Personal data in the KeenAuth APIs](/docs/policies/personal-data) describes what is stored, how long it is kept and how it is deleted. Do not send special categories of personal data (health, biometric data, religion, political opinions, sexual orientation) in any field.
