Planificar un cambio de configuración
POST /v1/config-plans · permiso config:read y el permiso de lectura de cada tipo del documento
Compara un documento de configuración con la configuración actual del entorno y guarda el resultado como un plan. No se cambia nada: un plan solo muestra lo que haría aplicar el documento. Úsalo para revisar una promoción de development a staging o production antes de aplicarla.
Solicitud
| Campo | Descripción |
|---|---|
document |
Obligatorio. Un documento de configuración con el formato de GET /v1/config-export. Debe cumplir el JSON Schema https://docs.keenauth.com/config/schema/v1.json. |
prune |
Opcional, false por defecto. Si es true, se planifica eliminar los recursos de los tipos del documento que faltan en el documento. |
- Los tipos del documento son
kindssi se indica (entonces cada recurso debe ser de un tipo listado); si no, los tipos de sus recursos. Solo se comparan estos tipos; los demás quedan como están. - Un recurso que falta en el documento no se elimina salvo que
pruneseatrue. Los tipos únicos (environment_settings,identity_settings,branding) nunca se eliminan. - En los tipos singleton, un campo que falta en el documento no cambia: se conserva el valor actual del destino. Así, un documento exportado antes de que existiera un campo no restablece ese campo. Un valor indicado explícitamente, incluido
null, se sigue escribiendo. En los demás tipos, un campo que falta toma su valor predeterminado. - El documento no debe contener valores secretos. Un campo secreto solo contiene un marcador
secret_refonull; un valor se rechaza y nunca se devuelve. - Los
warningsdel documento se ignoran; se aceptan como máximo 15.000 (una exportación nunca contiene más). - Los permisos son los de una exportación de los mismos tipos. Con
prunetambién se leen los tipos que pueden hacer referencia a un recurso eliminado, así que sus permisos también son necesarios.
Respuesta
201 Created con Location: /v1/config-plans/{plan_id} y Cache-Control: no-store.
| Campo | Descripción |
|---|---|
id |
ID del plan, cfgp_…. |
status |
planned; expired después de expires_at. |
expires_at |
El plan es válido durante 1 hora. Se elimina 7 días después de caducar. |
summary |
Número de acciones create, update, delete y no_op. |
changes |
Una entrada por recurso, en orden de tipo y luego por key. |
warnings |
secret_required: la conexión necesita un client secret que el destino aún no tiene. |
Cada cambio tiene kind, key, action (create, update, delete o no_op), object_version (la versión del recurso de destino al planificar; null en create), requires_secret, fields y, en create y update, el spec deseado. Cada entrada de fields es una diferencia de campo: pointer (RFC 6901, por ejemplo /spec/name), op (add, remove o replace, como en RFC 6902), before y after. Las listas se comparan como valores completos.
Un documento exportado enviado sin cambios planifica no_op para cada recurso, sea cual sea el orden de los recursos y de las listas de tipo conjunto.
{
"id": "cfgp_01m4qpqtywfs7930tb6kqn5rc5",
"status": "planned",
"prune": false,
"kinds": ["connection"],
"expires_at": "2026-10-12T11:00:00Z",
"summary": {"create": 1, "update": 1, "delete": 0, "no_op": 1},
"changes": [
{"kind": "connection", "key": "db", "action": "no_op", "object_version": 5, "requires_secret": false, "fields": []},
{"kind": "connection", "key": "github", "action": "create", "object_version": null, "requires_secret": true, "fields": [], "spec": {"type": "social", "strategy": "github", "name": "GitHub", "display_name": null, "status": "active", "settings": {}, "client_secret": {"secret_ref": {"source": "env", "name": "KEENAUTH_CONNECTION_GITHUB_CLIENT_SECRET"}}}},
{"kind": "connection", "key": "google", "action": "update", "object_version": 4, "requires_secret": false, "fields": [{"pointer": "/spec/name", "op": "replace", "before": "Google", "after": "Google Workspace"}], "spec": {"type": "social", "strategy": "google", "name": "Google Workspace", "display_name": null, "status": "active", "settings": {}, "client_secret": {"secret_ref": {"source": "env", "name": "KEENAUTH_CONNECTION_GOOGLE_CLIENT_SECRET"}}}}
],
"warnings": [{"code": "secret_required", "kind": "connection", "key": "github", "pointer": "/spec/client_secret"}]
}
Cada plan escribe una entrada config_plan.created en el registro de gestión del entorno.
Límites
- Frecuencia: los planes tienen su propio límite por minuto y entorno: en
production, 20 en Free, 60 en Startup y Business, 120 en Enterprise; endevelopmentystaging, una décima parte (al menos 2). - Cuota por entorno: como máximo 100 planes que no se hayan aplicado ni caducado, y como máximo 2.000 planes y 1 GiB de planes almacenados hasta que se eliminan (7 días después de caducar). Los planes de otros entornos nunca cuentan.
- Capacidad: el servidor calcula un número limitado de planes grandes a la vez; un entorno puede usar como máximo una cuarta parte de esa capacidad.
- Límites de campos: son los que el servicio de configuración aplica al escribir: el esquema limita listas y textos (por ejemplo
redirect_uris50,allowed_web_origins20,permissions1.000), lossettingsde una conexión tienen como máximo 32 KiB y 8 niveles de profundidad, y losjwksde una aplicación y elconsent_text_i18nde cada permiso como máximo 16 KiB.
Errores
| HTTP | code | Cuándo |
|---|---|---|
| 400 | malformed_request, unknown_field |
El cuerpo no es JSON o tiene un campo distinto de document y prune. |
| 401 | unauthenticated |
Las credenciales faltan, no son válidas o se revocaron. |
| 403 | insufficient_permissions |
A las credenciales les falta un permiso necesario; required_permissions los enumera todos. |
| 413 | config_document_too_large, payload_too_large |
El documento supera los 5000 recursos o 10 MiB; planifica menos tipos. |
| 422 | validation_failed |
Consulta abajo; errors[].pointer apunta dentro de la solicitud (/document/...). |
| 429 | rate_limited |
Se alcanzó el límite de frecuencia de planes o la cuota de planes del entorno, o el entorno está calculando demasiados planes; vuelve a intentarlo tras el periodo Retry-After (en la cuota, cuando el plan más antiguo caduque o se elimine). |
| 503 | service_unavailable |
El cálculo de planes está al límite de capacidad o una dependencia no está disponible temporalmente; vuelve a intentarlo tras el periodo Retry-After. |
errors[].code |
Significado |
|---|---|
required |
Falta document. |
invalid |
El documento no cumple el esquema en este puntero. |
duplicate |
Dos recursos tienen el mismo kind y key. |
kind_not_listed |
El tipo del recurso no está en kinds. |
secret_value |
Se encontró un valor secreto; usa un marcador secret_ref. |
unresolved_reference |
La key referenciada no existiría después del cambio. |
key_in_use |
La key pertenece a una aplicación que no se gestiona con configuración (propiedad de una organización o autorregistrada) o a la API del sistema. |
still_referenced |
/prune: un recurso que se mantiene hace referencia a un recurso que el plan eliminaría. |
too_large |
Un recurso, una advertencia o un campo de nivel superior tiene más de 200.000 valores JSON. |
too_long |
Los settings de una conexión superan 32 KiB, o los jwks de una aplicación o el consent_text_i18n de un permiso superan 16 KiB. |
too_deep |
Los settings de una conexión tienen más de 8 niveles de anidamiento. |
reserved |
El identifier de la API está en el espacio de nombres urn:idp: de la plataforma. |
Ejemplo
curl -X POST "https://api.eu.keenauth.com/v1/config-plans" \
-H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
-H "Content-Type: application/json" \
-d "{\"document\": $(cat keenauth.json), \"prune\": false}"
keenauth config plan -f keenauth.yaml