
# Import SAML IdP metadata into a connection

`POST /v1/connections/{connection_id}:import-metadata` · permission `connections:write`

Applies an uploaded SAML 2.0 metadata document from the identity provider to an enterprise SAML connection.

- The identity provider side of the connection (entity ID, HTTP-Redirect single sign-on URL, single logout URL) is replaced with the values from the document.
- Signing certificates in the document that are not yet expired and not yet registered are added (`source` is `manual`). Certificates already on the connection stay active; delete them with [Delete a certificate](../connection-certificates/delete.md).
- The connection now follows the uploaded document: a stored metadata URL and certificate pinning are cleared.
- The change invalidates the last passed [connection test](test.md); activating the connection needs a new passed test.

On an **active** connection, a document that changes the identity provider's entity ID or SSO URL, or that removes a signing pin, is not applied. The whole import becomes a [draft revision](revisions.md): the response shows the unchanged live identity provider side, `added_certificate_fingerprints` is empty and `revision` is set. Test the draft with [Test a connection](test.md) and `revision_id`, then [publish it](publish-revision.md). Other imports (new certificates, SLO URL, MFA values) apply directly.

The document is parsed with strict limits (at most 1 MiB, no `DOCTYPE`). When the document is invalid the response does not say why and neither the reason nor the document content is logged. A document with several `EntityDescriptor` elements needs `entity_id`. The request takes no `If-Match` header because SAML material has no version. Writes are audited as `connection.idp_metadata_imported`, plus `connection.idp_certificate_added` for each new certificate.

## Request

| Field | Type | Required | Description |
|---|---|---|---|
| `connection_id` | path | yes | Enterprise SAML connection ID (`conn_…`). |
| `metadata_xml` | string | yes | The metadata document (`EntityDescriptor` or `EntitiesDescriptor`), at most 1 MiB. |
| `entity_id` | string | for several entities | The entity ID of the identity provider to take from a document with several entities. With one entity it must match. |
| `mfa_authn_context_values` | array \| null | no | SAML `AuthnContextClassRef` values that count as multi-factor authentication by the identity provider (at most 10). When given (an empty list too) they are stored; when omitted or `null` the stored values are kept. |

## Response

`200 OK`:

```json
{
  "idp_entity_id": "https://idp.example.com/entity",
  "idp_sso_url": "https://idp.example.com/sso/redirect",
  "idp_slo_url": null,
  "certificates": [
    {"id": "conncert_01j9xq2m4n6p8r0s2t4v6w8y0a", "sha256_fingerprint": "3b0c…", "not_before": "2026-01-01T00:00:00Z", "not_after": "2028-01-01T00:00:00Z", "source": "manual"}
  ],
  "added_certificate_fingerprints": ["3b0c…"]
}
```

| Field | Description |
|---|---|
| `idp_entity_id`, `idp_sso_url`, `idp_slo_url` | The identity provider side after the import; `idp_slo_url` is `null` when the document has no single logout service. |
| `certificates` | The active signing certificates of the connection (see [List certificates](../connection-certificates/list.md)). |
| `added_certificate_fingerprints` | SHA-256 fingerprints of the certificates this import added; certificates already registered are not listed. |
| `revision` | Only when the import became a draft revision: the draft (see [List the revisions](revisions.md)). |

## Errors

| HTTP | code | When |
|---|---|---|
| 404 | `not_found` | The connection does not exist in this environment or is not an enterprise connection. |
| 409 | `conflict` | The connection is not a SAML connection, has no SAML configuration yet, or the import would exceed 3 active certificates (nothing is changed). |
| 422 | `validation_failed` | The document or a field is invalid; `errors[]` points at the field (`/metadata_xml`, `/entity_id`, `/mfa_authn_context_values`). In staging and production environments a test identity provider is also refused at `/metadata_xml`: an entity ID under the reserved `.invalid` domain, or the public test key of the [local mock server](/docs/cli/mock-server). |
| 413 | `payload_too_large` | The request body is larger than 4 MiB. |
| 400 | `unknown_field` | The body has an unknown field. |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks the required permission. |
| 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
jq -Rs '{metadata_xml: .}' idp-metadata.xml > import.json
curl -X POST "https://api.eu.keenauth.com/v1/connections/conn_01j9xp6q0r1s5t7v9w1x3y5z7b:import-metadata" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d @import.json
```

```bash
keenauth connections import-metadata conn_01j9xp6q0r1s5t7v9w1x3y5z7b --metadata-file idp-metadata.xml
```
