
# Sostituisci la politica di età

`PUT /v1/age-policy` · autorizzazione `identity-settings:write`

Scrive l'intera politica di età. `If-Match` è obbligatorio (`428` se manca, `412` se non corrisponde); una politica mai scritta ha versione `"0"`. Regole: `min_age` e soglie per paese sono 13-21; i codici paese sono ISO 3166-1 alpha-2 (maiuscoli), massimo 250 voci; `parental_consent_below` è `null` oppure 1..`min_age`; `store_birthdate` può essere `true` solo quando `mode` è `birthdate`. La politica si applica solo alle iscrizioni successive; gli utenti esistenti non cambiano.

## Richiesta

Corpo JSON (i campi sconosciuti vengono rifiutati con `400 unknown_field`):

| Campo | Tipo | Obbligatorio | Descrizione |
|---|---|---|---|
| `If-Match` | header | sì | Intestazione: il valore `ETag` da `GET /v1/age-policy`. |
| `mode` | string | sì | `off`, `attestation` (domanda neutra su anno e mese di nascita, valore non memorizzato) oppure `birthdate`. |
| `min_age` | integer | sì | 13-21. |
| `country_min_age` | object | sì | Codice paese → soglia (13-21); i paesi mancanti usano `min_age`. |
| `country_source` | string | sì | `ip` oppure `declared`. |
| `under_age_action` | string | sì | `block` oppure `create_minor`. |
| `parental_consent_below` | integer \| null | no | `null` (nessun consenso dei genitori) oppure 1..`min_age`. |
| `pending_consent_action` | string | sì | `block_sign_in` oppure `issue_limited`. |
| `store_birthdate` | boolean | sì | `true` solo con `mode: birthdate`. |
| `applies_to` | string | sì | `self_signup` oppure `all`. |

## Risposta

`200 OK` con la politica e l'intestazione `ETag`.

```json
{
  "mode": "attestation",
  "min_age": 16,
  "country_min_age": {"DE": 16, "FR": 15, "IT": 14},
  "country_source": "ip",
  "under_age_action": "block",
  "parental_consent_below": null,
  "pending_consent_action": "block_sign_in",
  "store_birthdate": false,
  "applies_to": "self_signup",
  "updated_at": "2026-10-05T09:30:00.123456Z"
}
```

## Token

Finché `mode` non è `off`, gli ID token, gli access token e la risposta UserInfo contengono il `age_group` dell'utente (`adult`, `minor` o `unknown`) indipendentemente dagli scope richiesti, e `parental_consent_status` (`not_required`, `pending`, `granted`, `denied` o `revoked`) quando ha un valore. Con `mode: off` non viene emesso nessuno dei due claim. Entrambi sono scritti solo da KeenAuth (hook e template dei claim non possono impostarli); modificali con `PATCH /v1/users/{user_id}`.

Con `pending_consent_action: block_sign_in`, un utente il cui `parental_consent_status` è `pending`, `denied` o `revoked` non riceve alcun token: la richiesta di autorizzazione termina con `access_denied` e l'endpoint dei token risponde `invalid_grant` (`Parental consent has not been granted.`) per i grant authorization code, device code e refresh token. Un refresh token non viene revocato; torna a funzionare quando il consenso è `granted`. Con `issue_limited` i token vengono emessi e la tua applicazione limita l'utente tramite i claim.

## Errori

| HTTP | code | Quando |
|---|---|---|
| 400 | `unknown_field` | Il corpo contiene un campo sconosciuto. |
| 412 | `precondition_failed` | `If-Match` non corrisponde alla versione attuale. |
| 415 | `unsupported_media_type` | Il content type non è `application/json`. |
| 422 | `validation_failed` | Un campo manca (`required`) o viola una regola sopra; il puntatore indica il campo, per esempio `/country_min_age/DE`. |
| 428 | `precondition_required` | L'intestazione `If-Match` manca. |
| 401 | `unauthenticated` | La credenziale manca, non è valida o è stata revocata. |
| 403 | `insufficient_permissions` | La credenziale non ha l'autorizzazione richiesta. |
| 429 | `rate_limited` | È stato superato il limite di richieste; riprova dopo il periodo `Retry-After`. |
| 503 | `service_unavailable` | Una dipendenza è temporaneamente non disponibile; riprova dopo il periodo `Retry-After`. |

## Esempio

```bash
curl -X PUT https://api.eu.keenauth.com/v1/age-policy \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "0"' \
  -d '{"mode":"attestation","min_age":16,"country_min_age":{"DE":16,"FR":15},"country_source":"ip","under_age_action":"block","parental_consent_below":null,"pending_consent_action":"block_sign_in","store_birthdate":false,"applies_to":"self_signup"}'
```
