---
title: "List pre-auth attempts"
method: GET
path: "/admin/auth-events"
tags: ["admin"]
---

# List pre-auth attempts

`GET /admin/auth-events`

## Request

- Base URL: `https://api.instruxi.dev/api/v1/enforcer`
- URL: `https://api.instruxi.dev/api/v1/enforcer/admin/auth-events`
- Auth: one of:
  - API key in header `Authorization`
  - API key in header `X-API-Key`

Auth-funnel events for one tenant, newest first — including the attempts that never reached an account, which is the whole point. Pass email to answer "did this address ever try, and what failed": the address is hashed server-side and matched against the stored hash, so the search term is never written to the database and the plaintext never had to be stored to be findable. Scoped to the caller's tenant; only a cross-tenant admin may name another via tenant_id. from/to accept RFC3339 or YYYY-MM-DD. Unknown query parameters are a 400, not a silently unfiltered list.

## Query parameters

- `tenant_id` string
- `email` string
- `event` 'otp_requested' | 'otp_send_failed' | 'otp_verify_failed' | 'login_failed'
- `group_id` string, uuid
- `exclude_group_id` string, uuid
- `from` string
- `to` string
- `limit` integer
- `offset` integer

## Response `200`

OK

- InternalDeliveryHttpHandlerAuthAttemptListResponse
  - `events` EnforcerV3InternalDomainAuthattemptEvent[]
    - `account_id` string: AccountID is NULL for the normal case — a caller who cannot log in has no account context. It is populated only where the server could resolve one anyway, and its absence is never an error.
    - `client_ip` string
    - `context` integer[]
    - `created_at` string
    - `email_masked` string: EmailMasked is enough to recognize an address in a feed, not enough to be an address list if the table leaks.
    - `event` string
    - `id` string
    - `message` string
    - `tenant_id` string
    - `user_agent` string
  - `limit` integer
  - `offset` integer
  - `tenant_id` string: TenantID is the tenant actually read, which for a tenant-scoped caller is always their own regardless of what they asked for.
  - `total` integer

## Other responses

- `400`: Bad Request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: group_not_found

---

[API](https://skmtc.dev/instruxi/apis/enforcer-api.md) · [All operations](https://skmtc.dev/instruxi/apis/enforcer-api/llms.txt) · [OpenAPI document](https://skmtc.dev/instruxi/apis/enforcer-api/revisions/fa82bc1becc0?raw)
