
# Migrate the SP host of a connection

`POST /v1/connections/{connection_id}:migrate-sp-host` · permission `connections:write`

Starts moving the SP endpoints (ACS, metadata, single logout, OIDC callback) of an enterprise connection to a new host, for example from the `keenauth.app` host to your verified custom domain. The SP URLs are otherwise frozen, because the identity provider has them.

The request creates a **draft revision** of kind `sp_host`, whatever the connection's status. Nothing changes for sign-ins yet:

1. Download the new SP metadata with [Download the SP metadata](sp-metadata.md) and `revision_id`, and give it to the identity provider's administrator. The new host already serves this metadata and the draft's test sign-in, nothing else.
2. Test the draft with [Test a connection](test.md) and `revision_id`.
3. [Publish the revision](publish-revision.md). The connection now uses the new host. The old host keeps answering for 30 more days so the identity provider can be updated, then it returns `404`.

A new draft discards the connection's previous draft. The request is audited as `connection.revision_created`.

## Request

| Field | Type | Required | Description |
|---|---|---|---|
| `connection_id` | path | yes | Enterprise connection ID (`conn_…`). |
| `Idempotency-Key` | header | no | Optional key that makes a retried request safe (16-64 characters). |
| `sp_host` | string | yes | The new host: an active host of this environment (its `keenauth.app` host or a verified custom domain), lower case, without a port. |

## Response

`200 OK` with the draft revision:

```json
{
  "id": "connrev_01j9xr8c2d4e6f8g0h2j4k6m8n",
  "connection_id": "conn_01j9xp6q0r1s5t7v9w1x3y5z7b",
  "protocol": "saml",
  "kind": "sp_host",
  "status": "draft",
  "discard_reason": null,
  "created_at": "2026-10-28T10:00:00Z",
  "decided_at": null,
  "purge_after": null,
  "superseded_revision_id": null,
  "changes": {
    "sp_host": "login.example.com",
    "idp_entity_id": null,
    "idp_sso_url": null,
    "idp_slo_url": null,
    "certificate_fingerprints": [],
    "mfa_authn_context_values": null,
    "issuer": null,
    "client_id": null,
    "client_auth_method": null,
    "provider_profile": null,
    "client_secret_change": null
  },
  "latest_test": null
}
```

`superseded_revision_id` is the previous draft this request discarded, if any.

## Errors

| HTTP | code | When |
|---|---|---|
| 400 | `unknown_field` | The body has an unknown field. |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks `connections:write`. |
| 404 | `not_found` | The connection does not exist in this environment or is not an enterprise connection. |
| 409 | `conflict` | The previous SP host migration's 30-day window is still open, or the connection has no protocol configuration yet. |
| 422 | `validation_failed` | `errors[]` points at `/sp_host` with `required`, `invalid_value` (not a lower-case host name), `not_in_environment` (not an active host of this environment) or `unchanged` (already the connection's SP host). |
| 429 | `rate_limited` | The rate limit was exceeded; retry after the `Retry-After` period. |
| 503 | `service_unavailable` | A dependency is temporarily unavailable; retry after the `Retry-After` period. |

## Example

```bash
curl -X POST "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b:migrate-sp-host" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"sp_host":"login.example.com"}'
```

```bash
keenauth connections migrate-sp-host conn_01j9xp6q0r1s5t7v9w1x3y5z7b --sp-host login.example.com --yes
```
