---
title: "Configure SAML SSO for organization (owner only)"
method: PUT
path: "/orgs/{org_id}/sso"
tags: ["Organizations"]
---

# Configure SAML SSO for organization (owner only)

`PUT /orgs/{org_id}/sso`

## Request

- Base URL: `https://api.mnemom.ai/v1`
- URL: `https://api.mnemom.ai/v1/orgs/{org_id}/sso`
- Auth: HTTP bearer

Every `allowed_domains` entry is normalized (trimmed, lowercased, trailing dot stripped) and must be owned by this organization: either already bound to it, or covered by a DNS-TXT-verified domain claim (`/domains`) held by this org or by the calling owner's personal org. Unverified domains → 403 `sso_domain_unverified`; public email providers (gmail.com, outlook.com, ...) → 400 `sso_domain_public`; a domain already bound to another organization's SSO → 409 `sso_domain_conflict`. `metadata_url` — Outbound URL rules: the URL must be https and must point at a publicly reachable host. Credentials in the URL, single-label or internal host names (localhost, *.local, *.internal, *.home.arpa), and hosts that are or resolve to loopback, private (RFC1918), link-local (including cloud metadata), CGNAT, IPv6 unique-local/link-local, or other non-public addresses are rejected with 400. The host is resolved and checked when saved; the identity provider fetches it from there.

## Path parameters

- `org_id` string, required

## Request body

- object
  - `metadata_url` string, uri, required
  - `idp_name` string
  - `default_role` 'admin' | 'member' | 'viewer' | 'auditor'
  - `allowed_domains` string[], required
  - `enforced` boolean

## Response `200`

SSO configured

- object

## Other responses

- `400`: Bad request
- `401`: Authentication required
- `403`: Forbidden
- `404`: Resource not found
- `409`: Resource conflict — the request cannot proceed because of a current state conflict (e.g., resource already exists, version mismatch, in-flight idempotency key with a different body).
- `429`: Rate-limit exceeded. The global per-IP limiter (100 requests/minute, applied to every `/v1/*` route) rejected this request. Back off until the window resets — `Retry-After` carries the cooldown in seconds and `X-RateLimit-Reset` the absolute reset time.
- `500`: Server error — request was well-formed but the server failed to fulfill it. Typically a downstream dependency (DB / RPC / external API) returned an unexpected error.

---

[API](https://skmtc.dev/mnemom/apis/mnemom-api.md) · [All operations](https://skmtc.dev/mnemom/apis/mnemom-api/llms.txt) · [OpenAPI document](https://skmtc.dev/mnemom/apis/mnemom-api/revisions/274b7a6ea182?raw)
