
# Report sui membri inattivi

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

Elenca i membri attivi di un'organizzazione che non hanno effettuato alcun accesso riuscito in quell'organizzazione negli ultimi `days` giorni. Usalo per trovare gli account da rimuovere quando una connessione non ha il provisioning SCIM: controlla l'elenco, poi sospendi le appartenenze selezionate con `POST /v1/organizations/{org_id}/memberships/{membership_id}:suspend`.

L'ambiente proviene sempre dalla chiave API; non esiste un parametro per l'ambiente. Le righe contengono solo identificatori e timestamp, nessun nome, indirizzo email, indirizzo IP o `User-Agent`. Poiché gli identificatori utente sono dati personali, il report è limitato alle chiavi con `reports:read`.

## Cosa conta come accesso

Un'autenticazione riuscita conta quando è stata completata nel contesto di questa organizzazione. Un accesso senza un'organizzazione selezionata non conta. Un'appartenenza la cui attivazione (`activated_at`, oppure il suo orario di creazione se non è mai stata attivata) è più recente della soglia non viene elencata, quindi un membro entrato ieri non compare mai in un report di 30 giorni.

## Richiesta

| Parametro | In | Obbligatorio | Descrizione |
|---|---|---|---|
| `organization_id` | query | sì | L'organizzazione (`org_…`). |
| `days` | query | no | Soglia di inattività in giorni, da 7 a 365. Predefinito 30. |
| `limit` | query | no | Dimensione della pagina, da 1 a 100. Predefinito 50. |
| `cursor` | query | no | `next_cursor` della pagina precedente. Valido solo per l'ambiente, `organization_id` e `days` per cui è stato emesso. |

Le righe seguono l'ordine in cui le appartenenze sono state aggiornate per ultime. La soglia (`inactive_since`) viene calcolata una sola volta, nella prima pagina, e riportata nel cursore, così ogni pagina dello stesso report usa lo stesso istante.

Una pagina analizza al massimo 500 appartenenze e può restituire meno righe di `limit`, anche nessuna. Continua a seguire `next_cursor` finché non è `null`.

## Risposta

`200 OK`.

| Campo | Descrizione |
|---|---|
| `organization_id` | L'organizzazione del report. |
| `days` | La soglia utilizzata. |
| `inactive_since` | L'istante della soglia (orario della richiesta meno `days`, RFC 3339, UTC). Vengono elencati i membri senza accessi da allora. |
| `data_since` | Orario della prima autenticazione riuscita registrata per l'ambiente; gli accessi precedenti sono sconosciuti. `null` quando l'ambiente non ha ancora alcuna registrazione. |
| `complete` | `true` quando `data_since` non è successivo a `inactive_since`, quindi l'elenco copre l'intera finestra della soglia. |
| `data` | Le righe di questa pagina (vedi sotto). |
| `next_cursor` | Cursore per la pagina successiva, `null` nell'ultima pagina. |

Ogni riga in `data`:

| Campo | Descrizione |
|---|---|
| `membership_id` | `mem_…`. |
| `user_id` | `usr_…`. |
| `activated_at` | Quando l'appartenenza è diventata attiva (oppure il suo orario di creazione se non è mai stata attivata). |
| `last_authenticated_at` | Ultima autenticazione riuscita in questa organizzazione, oppure `null` quando non ne è stata registrata alcuna dopo `data_since`. |

Quando `complete` è `false`, un membro elencato potrebbe aver effettuato l'accesso prima di `data_since`, quindi non considerare l'elenco come definitivo. Quando `data_since` è `null`, per l'ambiente non è ancora stato registrato alcun accesso e vengono elencati tutti i membri abbastanza vecchi.

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

## Errori

Ogni errore è un corpo `application/problem+json` con un `code` stabile.

| HTTP | `code` | Quando |
|---|---|---|
| 400 | `invalid_cursor` | Il cursore è malformato oppure è stato emesso per un altro ambiente, un'altra organizzazione o un altro `days`. |
| 404 | `not_found` | L'organizzazione non esiste oppure appartiene a un altro ambiente. |
| 422 | `validation_failed` | `organization_id` manca o è malformato, `days` o `limit` è fuori intervallo, oppure un parametro è ripetuto. |
| 401 | `unauthenticated` | La chiave API manca, non è valida o è stata revocata. |
| 403 | `insufficient_permissions` | La chiave non dispone di `reports:read`. |
| 429 | `rate_limited` | È stato superato il limite di richieste; rispetta `Retry-After`. |
| 503 | `service_unavailable` | Il servizio di reportistica è temporaneamente non disponibile; riprova più tardi. |

## Esempio

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

## Dati personali

Questo endpoint contiene dati personali: appartenenze alle organizzazioni e inviti (identificatori di utenti e appartenenze con orari di accesso). [Dati personali nelle API di KeenAuth](/docs/policies/personal-data) descrive cosa viene memorizzato, per quanto tempo viene conservato e come viene cancellato. Non inviare categorie particolari di dati personali (salute, dati biometrici, religione, opinioni politiche, orientamento sessuale) in nessun campo.
