Establecer el CSS personalizado
PUT /v1/branding/css · permiso branding:write
Escribe el CSS personalizado del borrador del entorno (plan Startup o superior, función branding_custom_css). El CSS pasa por un saneador de lista permitida: solo clases de ui_catalog (idp-*) y propiedades y valores permitidos; la capa protegida (texto legal, consentimiento y elementos de accesibilidad) no se puede ocultar ni cubrir. Todo o nada: con una sola infracción no se escribe nada. El borrador guarda la salida canónica del saneador, no el texto enviado; css en la respuesta es esa salida. Una cadena vacía lo borra y no está sujeta al plan.
Solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
If-Match |
encabezado | sí | El ETag del borrador leído por última vez ("0" si nunca se escribió). Ausente: 428; obsoleto: 412. |
css |
cadena | sí | Como máximo 51200 bytes, UTF-8 válido; "" borra. |
Respuesta
200 OK con el borrador del entorno y su ETag. theme contiene solo los tokens definidos; los demás heredan el valor predeterminado de la plataforma.
{
"theme": {"mode": "light", "light": {"color": {"primary": "#0a3d91"}}, "logo_height": 40},
"css": ".idp-c .idp-title{color:#0a3d91}\n",
"page_template": null,
"updated_at": "2026-10-05T09:30:00.123456Z"
}
Errores
| HTTP | código | Cuándo |
|---|---|---|
| 400 | unknown_field |
El cuerpo tiene un campo desconocido o no es un objeto JSON. |
| 403 | plan_feature_unavailable |
El plan no incluye la función (plan_feature_unavailable, extensiones feature y required_plan). Los entornos de desarrollo no están restringidos. |
| 412 | precondition_failed |
If-Match no coincide con la versión actual del borrador. |
| 422 | validation_failed |
css falta o es null (required), es demasiado largo (too_long) o no es UTF-8 válido (invalid_utf8). |
| 422 | branding_validation_failed |
El CSS no superó el saneador. La extensión violations enumera todas las infracciones: line, column (desde 1), rule (por ejemplo class_not_in_catalog, protected_property, property_not_allowed, syntax_error) y, si existe, name (nombre de la propiedad, la clase o la función). Los valores CSS nunca se devuelven. Tras 100 infracciones el saneador se detiene; el último elemento tiene la regla too_many_issues. La salida canónica es más larga que la entrada (cada regla recibe un prefijo de ámbito); si supera los 51200 bytes, la única infracción es la regla too_large en la línea 1, columna 1. |
| 428 | precondition_required |
Falta el encabezado If-Match. |
| 401 | unauthenticated |
La credencial falta, no es válida o se ha revocado. |
| 403 | insufficient_permissions |
La credencial no tiene el permiso necesario. |
| 429 | rate_limited |
Se superó el límite de frecuencia; vuelva a intentarlo tras el periodo Retry-After. |
| 503 | service_unavailable |
Una dependencia no está disponible temporalmente; vuelva a intentarlo tras el periodo Retry-After. |
Ejemplo de rechazo del saneador:
.idp-button{position:fixed}
.my-banner{color:red}
{
"type": "https://docs.keenauth.com/errors/branding_validation_failed",
"title": "Branding validation failed",
"status": 422,
"code": "branding_validation_failed",
"violations": [
{"line": 1, "column": 13, "rule": "property_not_allowed", "name": "position"},
{"line": 2, "column": 1, "rule": "class_not_in_catalog", "name": "my-banner"}
],
"request_id": "req_01J9Z3N5W8Q2F6V4K7T1M0XB3C"
}
Ejemplo
curl -X PUT https://api.eu.keenauth.com/v1/branding/css \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-H 'If-Match: "3"' \
-d '{"css":".idp-title { color: #0a3d91 }"}'