
# Cambiar el rpId de la clave de acceso de una conexión

`POST /v1/connections/{connection_id}:change-rp-id` · permiso `connections:write`

Mueve una conexión de clave de acceso a un nuevo rpId e inicia un periodo de migración. Una clave de acceso está vinculada al rpId con el que se registró, por lo que, una vez que los usuarios tengan claves de acceso, esta es la única forma de cambiar el rpId: un `PATCH` que modifique `settings.rp_id` se rechaza con `409 rp_id_change_requires_migration`.

Durante el periodo, los usuarios todavía pueden iniciar sesión con claves de acceso del rpId anterior, y las nuevas claves de acceso se registran en el nuevo rpId. Cuando termina el periodo, o cuando usted lo finaliza antes con [Completar la migración del rpId](complete-rp-id-migration.md), las claves de acceso que sigan en el rpId anterior se revocan (motivo `rp_id_changed`). Los usuarios que no tengan otro método de inicio de sesión necesitarán entonces inicio de sesión sin contraseña por correo electrónico o recuperación de cuenta. Solo puede ejecutarse una migración a la vez en un entorno.

El rpId de la conexión, el registro de la migración, la entrada de auditoría de gestión y el evento `passkey_rp_id.migration_started` se escriben juntos. Un dominio personalizado que sea el rpId, o el rpId anterior de una migración en curso, no se puede eliminar (`409 domain_in_use_by_rp_id`).

## Solicitud

| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
| `connection_id` | ruta | sí | ID de la conexión de clave de acceso (`conn_…`). |
| `If-Match` | encabezado | sí | El `ETag` de la conexión (consulte [Obtener una conexión](get.md)). |
| `Idempotency-Key` | encabezado | no | Clave opcional que hace seguro reintentar una solicitud (de 16 a 64 caracteres). |
| `new_rp_id` | cadena | sí | El nuevo rpId: el nombre de host de un dominio personalizado `active` del entorno (en minúsculas, etiqueta A de IDNA), o una cadena vacía para usar cada host de inicio de sesión como su propio rpId. Como máximo 253 bytes. |
| `confirm_rp_id` | cadena | sí | `new_rp_id` escrito de nuevo. |
| `migration_window_days` | entero | no | Cuántos días siguen funcionando las claves de acceso del rpId anterior: de 30 a 365, valor predeterminado 90. |

```json
{
  "new_rp_id": "login.example.com",
  "confirm_rp_id": "login.example.com",
  "migration_window_days": 90
}
```

## Respuesta

`200 OK`; la migración y un encabezado `ETag` con la nueva versión de la conexión.

```json
{
  "id": "rpm_01j9xr4a6b8c0d2e4f6g8h0j2k",
  "connection_id": "conn_01j9xp6q0r1s5t7v9w1x3y5z7b",
  "previous_rp_id": null,
  "new_rp_id": "login.example.com",
  "status": "active",
  "started_at": "2026-10-27T10:00:00Z",
  "ends_at": "2027-01-25T10:00:00Z",
  "completed_at": null,
  "revoked_count": null,
  "new_registration_count": null,
  "fallback_enabled_by_migration": false
}
```

| Campo | Descripción |
|---|---|
| `previous_rp_id`, `new_rp_id` | El rpId antes y después del cambio; `null` significa que cada host de inicio de sesión es su propio rpId. |
| `status` | `active` mientras el periodo está en curso; `completed` cuando terminó; `completed_early` cuando se finalizó antes. |
| `ends_at` | Cuándo está previsto que termine el periodo. |
| `completed_at`, `revoked_count`, `new_registration_count` | Se escriben al cerrarse la migración; `null` mientras esté `active`. |
| `fallback_enabled_by_migration` | `true` cuando se activó durante el periodo un método de inicio de sesión alternativo porque las claves de acceso eran el único primer factor. |

## Errores

| HTTP | código | Cuándo |
|---|---|---|
| 400 | `unknown_field` | El cuerpo contiene un campo desconocido. |
| 404 | `not_found` | La conexión no existe o pertenece a otro entorno. |
| 409 | `rp_id_migration_in_progress` | Hay otra migración de rpId en curso en este entorno. |
| 412 | `precondition_failed` | `If-Match` no coincide con la versión actual. |
| 422 | `validation_failed` | Falta un campo, es demasiado largo o está fuera de rango; `new_rp_id` no es un dominio personalizado `active` del entorno o es igual al rpId actual; `confirm_rp_id` no coincide; o la conexión no es una conexión de clave de acceso (`errors[].pointer`: `/new_rp_id`, `/confirm_rp_id`, `/migration_window_days`, `/connection_id`). |
| 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 necesario. |
| 429 | `rate_limited` | Se superó el límite de solicitudes; reintente después del periodo indicado en `Retry-After`. |
| 503 | `service_unavailable` | Una dependencia no está disponible temporalmente; reintente después del periodo indicado en `Retry-After`. |

## Ejemplo

```bash
curl -X POST "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b:change-rp-id" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H 'If-Match: "3"' \
  -H "Content-Type: application/json" \
  -d '{"new_rp_id":"login.example.com","confirm_rp_id":"login.example.com"}'
```

```bash
keenauth connections change-rp-id conn_01j9xp6q0r1s5t7v9w1x3y5z7b --if-match '"3"' --yes \
  --data '{"new_rp_id":"login.example.com","confirm_rp_id":"login.example.com"}'
```
