Reemplazar la política de edad
PUT /v1/age-policy · permiso identity-settings:write
Escribe la política de edad completa. If-Match es obligatorio (428 si falta, 412 si no coincide); una política que nunca se escribió tiene la versión "0". Reglas: min_age y los umbrales por país están entre 13 y 21; los códigos de país son ISO 3166-1 alpha-2 (en mayúsculas), con un máximo de 250 entradas; parental_consent_below es null o 1..min_age; store_birthdate puede ser true solo cuando mode es birthdate. La política se aplica solo a los registros posteriores; los usuarios existentes no cambian.
Solicitud
Cuerpo JSON (los campos desconocidos se rechazan con 400 unknown_field):
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
If-Match |
header | sí | Encabezado: el valor ETag de GET /v1/age-policy. |
mode |
string | sí | off, attestation (pregunta neutral de año y mes de nacimiento, el valor no se almacena) o birthdate. |
min_age |
integer | sí | 13-21. |
country_min_age |
object | sí | Código de país → umbral (13-21); los países sin valor usan min_age. |
country_source |
string | sí | ip o declared. |
under_age_action |
string | sí | block o create_minor. |
parental_consent_below |
integer | null | no | null (sin consentimiento parental) o 1..min_age. |
pending_consent_action |
string | sí | block_sign_in o issue_limited. |
store_birthdate |
boolean | sí | true solo con mode: birthdate. |
applies_to |
string | sí | self_signup o all. |
Respuesta
200 OK con la política y el encabezado ETag.
{
"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"
}
Tokens
Mientras mode no sea off, los ID tokens, access tokens y la respuesta de UserInfo incluyen el age_group del usuario (adult, minor o unknown) independientemente de los scopes solicitados, y parental_consent_status (not_required, pending, granted, denied o revoked) cuando tiene un valor. Con mode: off no se emite ninguno de los dos claims. Solo KeenAuth escribe ambos (tus hooks y plantillas de claims no pueden establecerlos); cámbialos con PATCH /v1/users/{user_id}.
Con pending_consent_action: block_sign_in, un usuario cuyo parental_consent_status es pending, denied o revoked no recibe ningún token: la solicitud de autorización termina con access_denied y el endpoint de token responde invalid_grant (Parental consent has not been granted.) para las concesiones de código de autorización, código de dispositivo y refresh token. Un refresh token no se revoca; vuelve a funcionar cuando el consentimiento sea granted. Con issue_limited se emiten tokens y tu aplicación restringe al usuario según los claims.
Errores
| HTTP | código | Cuándo |
|---|---|---|
| 400 | unknown_field |
El cuerpo contiene un campo desconocido. |
| 412 | precondition_failed |
If-Match no coincide con la versión actual. |
| 415 | unsupported_media_type |
El tipo de contenido no es application/json. |
| 422 | validation_failed |
Falta un campo (required) o incumple alguna regla anterior; el puntero indica el campo, por ejemplo /country_min_age/DE. |
| 428 | precondition_required |
Falta el encabezado If-Match. |
| 401 | unauthenticated |
La credencial falta, no es válida o fue revocada. |
| 403 | insufficient_permissions |
La credencial no tiene el permiso requerido. |
| 429 | rate_limited |
Se superó el límite de frecuencia; reintenta después del período Retry-After. |
| 503 | service_unavailable |
Una dependencia no está disponible temporalmente; reintenta después del período Retry-After. |
Ejemplo
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"}'