
# Informe de miembros inactivos

`GET /v1/reports/inactive-members` · permiso `reports:read`

Lista los miembros activos de una organización que no han tenido ningún inicio de sesión correcto en esa organización durante los últimos `days` días. Úselo para encontrar cuentas que eliminar cuando una conexión no tiene aprovisionamiento SCIM: revise la lista y, después, suspenda las membresías seleccionadas con `POST /v1/organizations/{org_id}/memberships/{membership_id}:suspend`.

El entorno siempre procede de la clave de API; no existe un parámetro de entorno. Las filas contienen solo identificadores y marcas de tiempo, sin nombre, dirección de correo electrónico, dirección IP ni `User-Agent`. Como los identificadores de usuario son datos personales, el informe se limita a las claves con `reports:read`.

## Qué cuenta como inicio de sesión

Una autenticación correcta cuenta cuando se completó en el contexto de esta organización. Un inicio de sesión sin organización seleccionada no cuenta. No se incluye una membresía cuya activación (`activated_at`, o su fecha de creación si nunca se activó) sea posterior al umbral; por eso, un miembro que se unió ayer nunca aparece en un informe de 30 días.

## Solicitud

| Parámetro | En | Obligatorio | Descripción |
|---|---|---|---|
| `organization_id` | consulta | sí | La organización (`org_…`). |
| `days` | consulta | no | Umbral de inactividad en días, de 7 a 365. Predeterminado 30. |
| `limit` | consulta | no | Tamaño de página, de 1 a 100. Predeterminado 50. |
| `cursor` | consulta | no | `next_cursor` de la página anterior. Válido solo para el entorno, `organization_id` y `days` para los que se emitió. |

Las filas siguen el orden en que se actualizaron por última vez las membresías. El umbral (`inactive_since`) se calcula una sola vez, en la primera página, y se transporta en el cursor, de modo que todas las páginas de un mismo informe usan el mismo instante.

Una página analiza como máximo 500 membresías y puede devolver menos filas que `limit`, incluso ninguna. Siga usando `next_cursor` hasta que sea `null`.

## Respuesta

`200 OK`.

| Campo | Descripción |
|---|---|
| `organization_id` | La organización del informe. |
| `days` | El umbral utilizado. |
| `inactive_since` | El instante del umbral (hora de la solicitud menos `days`, RFC 3339, UTC). Se incluyen los miembros sin inicio de sesión desde entonces. |
| `data_since` | Hora de la primera autenticación correcta registrada para el entorno; los inicios de sesión anteriores a ella se desconocen. `null` cuando el entorno aún no tiene ningún registro. |
| `complete` | `true` cuando `data_since` no es posterior a `inactive_since`, de modo que la lista cubre todo el período del umbral. |
| `data` | Las filas de esta página (véase más abajo). |
| `next_cursor` | Cursor para la página siguiente, `null` en la última página. |

Cada fila de `data`:

| Campo | Descripción |
|---|---|
| `membership_id` | `mem_…`. |
| `user_id` | `usr_…`. |
| `activated_at` | Cuándo se activó la membresía (su fecha de creación si nunca se activó). |
| `last_authenticated_at` | Última autenticación correcta en esta organización, o `null` si no se ha registrado ninguna desde `data_since`. |

Cuando `complete` es `false`, un miembro incluido en la lista puede haber iniciado sesión antes de `data_since`, así que no considere la lista como definitiva. Cuando `data_since` es `null`, todavía no se ha registrado ningún inicio de sesión para el entorno y se incluye a todos los miembros con antigüedad suficiente.

```json
{
  "organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4d",
  "days": 30,
  "inactive_since": "2027-02-03T09:30:00Z",
  "data_since": "2026-12-01T08:00:00Z",
  "complete": true,
  "data": [
    {
      "membership_id": "mem_01j9xk3m7q8r2s4t6v8w0y2z4e",
      "user_id": "usr_01j9xk3m7q8r2s4t6v8w0y2z4f",
      "activated_at": "2026-12-10T10:00:00Z",
      "last_authenticated_at": "2027-01-05T17:45:00Z"
    }
  ],
  "next_cursor": null
}
```

## Errores

Todo error es un cuerpo `application/problem+json` con un `code` estable.

| HTTP | `code` | Cuándo |
|---|---|---|
| 400 | `invalid_cursor` | El cursor tiene un formato incorrecto o se emitió para otro entorno, organización o `days`. |
| 404 | `not_found` | La organización no existe o pertenece a otro entorno. |
| 422 | `validation_failed` | Falta `organization_id` o tiene un formato incorrecto, `days` o `limit` está fuera de rango, o un parámetro está repetido. |
| 401 | `unauthenticated` | Falta la clave de API, no es válida o ha sido revocada. |
| 403 | `insufficient_permissions` | La clave no tiene `reports:read`. |
| 429 | `rate_limited` | Se superó el límite de frecuencia; respete `Retry-After`. |
| 503 | `service_unavailable` | El servicio de informes no está disponible temporalmente; reintente más tarde. |

## Ejemplo

```bash
curl "https://api.eu.keenauth.com/v1/reports/inactive-members?organization_id=org_01j9xk3m7q8r2s4t6v8w0y2z4d&days=60" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY"
```

```bash
keenauth reports inactive-members org_01j9xk3m7q8r2s4t6v8w0y2z4d --days 60
```

## Datos personales

Este endpoint trata datos personales: membresías e invitaciones de organizaciones (identificadores de usuario y de membresía con horas de inicio de sesión). [Datos personales en las API de KeenAuth](/docs/policies/personal-data) describe qué se almacena, durante cuánto tiempo se conserva y cómo se elimina. No envíe categorías especiales de datos personales (salud, datos biométricos, religión, opiniones políticas, orientación sexual) en ningún campo.
