
# Actualizar una conexión

`PATCH /v1/connections/{connection_id}` · permiso `connections:write`

Actualiza una conexión mediante un merge patch de JSON (`application/merge-patch+json`, RFC 7396). `If-Match` es obligatorio. `key`, `type`, `strategy` y `org_id` no se pueden cambiar. Un patch que no cambia nada no escribe nada y conserva la versión. La configuración no debe contener secretos.

## Solicitud

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `connection_id` | string | sí | Identificador de la conexión (`conn_…`). |
| `If-Match` | header | sí | El `ETag` de la conexión tal como se leyó por última vez. Si falta: `428`; si está obsoleto: `412`. |
| `key` | string | no | No se puede cambiar; se acepta el mismo valor. |
| `type` | string | no | No se puede cambiar. |
| `strategy` | string | no | No se puede cambiar. |
| `name` | string | no | De 1 a 128 caracteres. |
| `display_name` | string \| null | no | `null` lo borra. |
| `status` | string | no | `active` o `inactive`. |
| `org_id` | string \| null | no | No se puede cambiar; se acepta el mismo valor. |
| `allowed_email_domains` | array of strings \| null | no | Reemplaza la lista; `null` o `[]` la borra. Las mismas reglas que al crear; en una conexión de organización solo se comprueban los dominios recién añadidos frente a los dominios verificados de la organización. |
| `allow_external_domains` | boolean | no | Solo `enterprise`. |
| `jit_mode` | string | no | `create`, `create_and_update` u `off`. Solo `enterprise`. |
| `email_trust` | boolean | no | Solo `enterprise`. Activarlo en una conexión de organización requiere un `allowed_email_domains` no vacío en el que todos los dominios sean dominios verificados de la organización. |
| `default_role_ids` | array of strings \| null | no | Reemplaza la lista; `null` o `[]` la borra. Las mismas reglas que al crear; solo se comprueban los roles recién añadidos, de modo que un rol que ya estaba en la lista y se eliminó después no bloquea la actualización (se omite al iniciar sesión). |
| `trust_idp_mfa` | boolean | no | Solo `enterprise`. |
| `settings` | object \| null | no | Se fusiona de forma recursiva (RFC 7396); un miembro `null` elimina esa clave; `null` borra toda la configuración. Sin secretos. |

## Respuesta

`200 OK` con la conexión actualizada y el nuevo `ETag`.

```json
{
  "id": "conn_0k3v8m1q2x9dz4h7s5t6w0y1ab",
  "key": "google",
  "type": "social",
  "strategy": "google",
  "name": "Google",
  "display_name": "Sign in with Google",
  "status": "active",
  "org_id": null,
  "allowed_email_domains": [],
  "allow_external_domains": false,
  "jit_mode": null,
  "email_trust": null,
  "default_role_ids": [],
  "trust_idp_mfa": null,
  "allow_idp_initiated": null,
  "idp_initiated_default_application_id": null,
  "idp_initiated_allowed_application_ids": [],
  "settings": {},
  "created_at": "2026-10-05T09:30:00.123456Z",
  "updated_at": "2026-10-05T09:30:00.123456Z"
}
```

## Configuración de clave de acceso

Para `type: "passkey"` el objeto `settings` acepta solo las claves indicadas más abajo. Cualquier otra clave, un tipo incorrecto o un valor fuera de rango se rechaza con `422 validation_failed` y un `errors[].pointer` como `/settings/max_credentials_per_user`. Un valor `null` significa el valor por defecto. Los errores de forma se notifican antes que los errores de plan.

| Clave | Tipo | Notas |
|---|---|---|
| `rp_id` | string | Ausente, `null` o vacío: cada host de inicio de sesión es su propio rpId. En otro caso, el nombre de host de un dominio personalizado `active` del entorno (en minúsculas, A-label de IDNA); cualquier otro valor da `422 validation_failed` (`/settings/rp_id`). Cuando el entorno ya tenga claves de acceso, cámbielo con [Cambiar el rpId de la clave de acceso](change-rp-id.md). |
| `rp_name` | string | Hasta 128 caracteres. |
| `passkey_first_factor_enabled`, `security_key_second_factor_enabled` | boolean | Por defecto `true`. |
| `user_verification` | string | `preferred` (por defecto) o `required`. |
| `max_credentials_per_user` | integer | De 1 a 20, por defecto 20; las fracciones se rechazan. |
| `require_device_bound_passkeys` | boolean | Sujeto al plan: `true` requiere Startup. |
| `attestation_required` | boolean | Sujeto al plan: `true` requiere Enterprise. |
| `aaguid_allowlist`, `aaguid_blocklist` | array of UUID strings | Como máximo 500 entradas únicas cada una (los errores apuntan a `/settings/<key>/<index>`). Sujeto al plan: una lista no vacía requiere Enterprise. |
| `related_origins` | array of strings | Orígenes `https://host[:port]`. Sujeto al plan: una lista no vacía requiere Enterprise. |
| `passkey_enrollment_prompt` | string | `off` o `after_login` (por defecto). |

Escribir un valor no predeterminado de una clave sujeta al plan falla con `403 plan_feature_unavailable` y los miembros `feature` y `required_plan`. Hasta que estén disponibles las entitlements del plan, estas claves no se pueden establecer en ningún entorno; escribir un valor por defecto (`false`, `[]`, `null`) o eliminar la clave siempre está permitido. Cuando la función esté disponible, cada entrada de `related_origins` debe ser un dominio personalizado verificado y activo del entorno; en caso contrario la solicitud falla con `422 related_origin_not_verified`. La configuración se valida después de aplicar el merge patch, y solo cuando `settings` forma parte del patch.

## Errores

| HTTP | code | Cuándo |
|---|---|---|
| 400 | `unknown_field` | El patch contiene un campo desconocido o de solo lectura. |
| 404 | `not_found` | La conexión no existe o pertenece a otro entorno. |
| 409 | `connection_test_required` | El patch pone una conexión `enterprise` en `active`, o añade un dominio a `allowed_email_domains` de una conexión `active`, sin una prueba exitosa de la configuración resultante en las últimas 24 horas (véase Activar una conexión); no se escribe nada. Eliminar dominios no se comprueba. |
| 409 | `rp_id_change_requires_migration` | El patch cambia `settings.rp_id` de una conexión de clave de acceso mientras el entorno tiene claves de acceso que dejarían de funcionar; utilice [Cambiar el rpId de la clave de acceso](change-rp-id.md). No se escribe nada. |
| 412 | `precondition_failed` | `If-Match` no coincide con la versión actual. |
| 415 | `unsupported_media_type` | El tipo de contenido no es `application/merge-patch+json`. |
| 422 | `validation_failed` | Un valor no es válido o cambió un campo inmutable (`code: immutable`). |
| 422 | `related_origin_not_verified` | Un origen relacionado no es un dominio personalizado verificado del entorno. |
| 403 | `plan_feature_unavailable` | El plan no incluye una configuración que usted ha establecido (miembros `feature` y `required_plan`), por ejemplo `attestation_required`. |
| 428 | `precondition_required` | Falta la cabecera `If-Match`. |
| 401 | `unauthenticated` | La credencial falta, no es válida o ha sido revocada. |
| 403 | `insufficient_permissions` | La credencial no tiene el permiso necesario. |
| 429 | `rate_limited` | Se ha superado el límite de uso; reintente después del periodo indicado en `Retry-After`. |
| 503 | `service_unavailable` | Una dependencia no está disponible temporalmente (por ejemplo, la comprobación de claves de acceso de un cambio de `rp_id` no pudo ejecutarse, por lo que no se escribe nada); reintente después del periodo indicado en `Retry-After`. |

## Ejemplo

```bash
curl -X PATCH https://api.eu.keenauth.com/v1/connections/conn_0k3v8m1q2x9dz4h7s5t6w0y1ab \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/merge-patch+json" \
  -H 'If-Match: "1"' \
  -d '{"display_name":"Sign in with Google"}'
```
