
# Lister les journaux

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

Liste les enregistrements de journal de l'environnement (connexions, sessions, jetons, MFA, protection contre les attaques et plus) avec pagination par curseur, du plus récent au plus ancien. Les enregistrements plus anciens que la période de conservation de votre offre (Free 7, Startup 14, Business 30, Enterprise 90 jours) ne sont jamais renvoyés.

## Requête

| Paramètre | Dans | Obligatoire | Description |
|---|---|---|---|
| `limit` | query | non | Taille de page, de 1 à 100. Valeur par défaut : 20. |
| `after` | query | non | Curseur opaque issu de `list_metadata.after` (enregistrements plus anciens). Exclusif avec `before`. |
| `before` | query | non | Curseur opaque issu de `list_metadata.before` (enregistrements plus récents). Exclusif avec `after`. |
| `from` | query | non | Heure RFC 3339 ; enregistrements à cette heure ou après. Doit se situer dans la période de conservation. |
| `to` | query | non | Heure RFC 3339 ; enregistrements antérieurs à cette heure. Doit être postérieure à `from`. |
| `type` | query | non | Préfixe de type de journal, comme `authentication.` ou `session.created`. Répétez le paramètre pour jusqu'à 20 valeurs ; un enregistrement correspondant à l'une d'elles est renvoyé. |
| `outcome` | query | non | `success`, `failure`, `denied` ou `error`. |
| `user_id`, `org_id`, `application_id`, `connection_id`, `directory_id`, `session_id` | query | non | Correspondance exacte sur l'identifiant préfixé (`usr_`, `org_`, `app_`, `conn_`, `dir_`, `ses_`). |
| `request_id` | query | non | `Idp-Request-Id` d'une requête (UUID), par exemple l'identifiant affiché sur une page d'erreur de connexion hébergée. |
| `correlation_id` | query | non | `Idp-Correlation-Id` d'un workflow (UUID). |
| `ip` | query | non | Adresse IP ou bloc CIDR (`203.0.113.0/24`). Nécessite `audit-events:read_ip`. |
| `ip_country` | query | non | Pays de l'IP, code ISO 3166-1 alpha-2 en majuscules (`DE`). |
| `q` | query | non | Préfixe de l'indice d'identifiant masqué (`j***@`). Nécessite `users:read_pii`. |

Les enregistrements sont toujours triés par `occurred_at`, du plus récent au plus ancien ; il n'existe pas de paramètre `order` (`order=desc` est accepté, toute autre valeur échoue avec `validation_failed`). Un curseur n'est valide qu'avec les filtres pour lesquels il a été émis.

Les filtres `ip` et `q` nécessitent leur autorisation même s'ils ne font que restreindre le résultat : sans elle, la requête échoue avec `403 insufficient_permissions` avant toute recherche, afin qu'une clé ne puisse pas sonder des valeurs qu'elle n'est pas autorisée à lire.

## Réponse

`200 OK`. `data` contient les enregistrements de la page ; `list_metadata.after` pointe vers les enregistrements plus anciens et `list_metadata.before` vers les plus récents (`null` s'il n'y en a pas). Aucun nombre total n'est renvoyé. Les champs vides valent `null`.

Les champs `ip`, `ip_asn`, `user_agent` et `user_agent_family` ne sont présents que si la clé possède l'autorisation `audit-events:read_ip`, et `identifier_hint` uniquement si elle possède `users:read_pii`. Sans cette autorisation, le champ est omis entièrement (aucune valeur masquée). `ip_country` est toujours renvoyé.

```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>"
  }
}
```

## Erreurs

Chaque erreur est un corps `application/problem+json` accompagné d'un `code` stable.

| HTTP | `code` | Quand |
|---|---|---|
| 400 | `invalid_cursor` | Le curseur est mal formé ou n'a pas été émis pour cette requête. |
| 400 | `invalid_filter` | Le service de journaux a rejeté un filtre ou le curseur. |
| 400 | `range_outside_retention` | `from` est antérieur à la période de conservation de votre offre. |
| 422 | `validation_failed` | Un paramètre de requête est invalide (`limit` hors plage, horodatage incorrect, `to` non postérieur à `from`, plus de 20 valeurs `type`, identifiant ou IP mal formé, paramètre répété). |
| 401 | `unauthenticated` | La clé d'API est absente, invalide ou révoquée. |
| 403 | `insufficient_permissions` | La clé ne possède pas `logs:read`, ou utilise `ip` sans `audit-events:read_ip` ou `q` sans `users:read_pii` (`required_permissions` indique ce dont la requête a besoin). |
| 429 | `rate_limited` | La limite de débit a été dépassée ; respectez `Retry-After`. |
| 503 | `service_unavailable` | Une dépendance est temporairement indisponible ; réessayez plus tard. |

## Exemple

```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"
```

## Données personnelles

Cet endpoint contient des données personnelles : les journaux de l'environnement. [Données personnelles dans les API KeenAuth](/docs/policies/personal-data) décrit ce qui est stocké, la durée de conservation et la manière dont elles sont supprimées. N'envoyez aucune catégorie particulière de données personnelles (santé, données biométriques, religion, opinions politiques, orientation sexuelle) dans aucun champ.
