
# Einen Admin-Portal-Link erstellen

`POST /v1/admin-portal-links` · Berechtigung `admin-portal-links:write`

Erstellt einen Link, mit dem die IT-Administratorin oder der IT-Administrator einer Ihrer Kundenorganisationen SSO, Verzeichnissynchronisierung, Domänenverifizierung und mehr im gehosteten Admin Portal einrichten kann, ohne Ihr Support-Team. Erzeugen Sie jedes Mal einen neuen Link, wenn Ihr Administrator in Ihrer Anwendung auf „SSO einrichten“ klickt, und leiten Sie ihn sofort auf `url` weiter: Der Link ist 5 Minuten gültig und öffnet genau einmal eine Portal-Sitzung. `url` wird nur in dieser Antwort und nur einmal zurückgegeben; kein Endpunkt liefert sie später erneut aus. Die Antwort enthält `Cache-Control: no-store`, und eine für denselben `Idempotency-Key` wiederholte Antwort lässt `url` weg und enthält `secret_redacted: true`. Die Portal-Sitzung bleibt 60 Minuten im Leerlauf und höchstens 8 Stunden gültig; widerrufen Sie sie mit `DELETE /v1/admin-portal-links/{link_id}`. Die Erstellung wird als `admin_portal_link.created` protokolliert (die URL gelangt nie in das Audit-Log).

`audit_logs` erfordert den Business-Tarif und `log_streams` den Enterprise-Tarif; die übrigen Intents sind in jedem Tarif verfügbar. `delivery: email` versendet stattdessen eine Einladung: Sie ist 7 Tage gültig und wird an `recipient_email` gesendet; die Antwort enthält weder `url` noch eine Adresse. Öffnet der Empfänger die Einladung, wird ein 6-stelliger Code (10 Minuten gültig) an dieselbe Adresse geschickt, und nur der bestätigte Code öffnet die Portal-Sitzung. Kann die Einladungs-E-Mail nicht gesendet werden, antwortet der Aufruf mit `503 service_unavailable` und `Retry-After` und legt nichts an. Widerrufen Sie eine Einladung mit `DELETE /v1/admin-portal-links/{link_id}`. Die Empfängeradresse erscheint nie in einer Antwort, einer Liste, dem Audit-Log oder einem Protokoll.

## Anfrage

| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
| `organization_id` | string | ja | Organisations-ID (`org_…`); sie muss in dieser Umgebung existieren. |
| `intents` | string[] | ja | 1 bis 6 Werte aus `sso`, `dsync`, `domain_verification`, `certificate_renewal`, `audit_logs` (Business), `log_streams` (Enterprise), jeder höchstens einmal. |
| `return_url` | string | ja | Absolute `https`-URL mit höchstens 2048 Byte, ohne Benutzerinformationen oder Fragment. Ihr Ursprung muss dem Ursprung einer `redirect_uri` einer aktiven, in dieser Umgebung registrierten Anwendung entsprechen. |
| `delivery` | string | nein | `link` (Standard; `url` in der Antwort, 5 Minuten gültig, einmal verwendbar) oder `email` (7 Tage gültige Einladung per E-Mail an `recipient_email`; ohne `url`). |
| `recipient_email` | string | nein | Nur mit `delivery: email`, dort aber Pflicht; höchstens 320 Zeichen. Fehlt sie: `422` `/recipient_email` `required`; mit `delivery: link`: `not_allowed`; ungültige Adresse: `invalid_value`. |

## Antwort

`201 Created` mit dem Link und seiner einmalig verwendbaren `url`.

```json
{
  "id": "apl_01j9xv2c4d6e8f0g2h4j6k8m0n",
  "organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
  "intents": [
    "dsync",
    "sso"
  ],
  "delivery": "link",
  "return_url": "https://app.example.com/settings/sso",
  "expires_at": "2026-10-12T09:36:00.123456Z",
  "consumed_at": null,
  "revoked_at": null,
  "created_at": "2026-10-12T09:31:00.123456Z",
  "url": "https://acme.eu.keenauth.app/portal/l/<token>"
}
```

## Fehler

| HTTP | code | Wann |
|---|---|---|
| 403 | `plan_feature_unavailable` | Ein Intent benötigt einen höheren Tarif; `feature` und `required_plan` benennen ihn. |
| 404 | `not_found` | Die Organisation existiert in dieser Umgebung nicht. |
| 409 | `organization_disabled` | Die Organisation ist nicht aktiv (deaktiviert); es wird kein Link erstellt. |
| 409 | `organization_pending_deletion` | Die Organisation ist zur Löschung vorgemerkt; es wird kein Link erstellt. |
| 422 | `validation_failed` | Ein Feld fehlt oder ist ungültig; `/return_url` `origin_not_registered`, wenn sein Ursprung keiner registrierten Anwendung entspricht; `/recipient_email` `required`, `not_allowed` oder `invalid_value`. |
| 401 | `unauthenticated` | Die Anmeldedaten fehlen, sind ungültig oder widerrufen. |
| 403 | `insufficient_permissions` | Den Anmeldedaten fehlt die erforderliche Berechtigung. |
| 429 | `rate_limited` | Das Ratenlimit wurde überschritten; wiederholen Sie die Anfrage nach der Frist `Retry-After`. |
| 503 | `service_unavailable` | Eine Abhängigkeit ist vorübergehend nicht verfügbar, oder (`delivery: email`) die Einladungs-E-Mail kann nicht gesendet werden; es wird nichts erstellt. Wiederholen Sie die Anfrage nach der Frist `Retry-After`. |

## Beispiel

```bash
curl -i -X POST "https://api.eu.keenauth.com/v1/admin-portal-links" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{"organization_id":"org_01j9xk3m7q8r2s4t6v8w0y2z4a","intents":["sso","dsync"],"return_url":"https://app.example.com/settings/sso"}'
```

### Einladung per E-Mail senden

```bash
curl -i -X POST "https://api.eu.keenauth.com/v1/admin-portal-links" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"organization_id":"org_01j9xk3m7q8r2s4t6v8w0y2z4a","intents":["sso"],"return_url":"https://app.example.com/settings/sso","delivery":"email","recipient_email":"it@customer.example"}'
```

`201 Created`; die Antwort enthält weder `url` noch eine Adresse:

```json
{
  "id": "apl_01j9xv2c4d6e8f0g2h4j6k8m0n",
  "organization_id": "org_01j9xk3m7q8r2s4t6v8w0y2z4a",
  "intents": [
    "sso"
  ],
  "delivery": "email",
  "return_url": "https://app.example.com/settings/sso",
  "expires_at": "2026-10-19T09:31:00.123456Z",
  "consumed_at": null,
  "revoked_at": null,
  "created_at": "2026-10-12T09:31:00.123456Z"
}
```

Mit der CLI: `keenauth admin-portal-links create --organization-id org_01j9xk3m7q8r2s4t6v8w0y2z4a --intents sso --return-url https://app.example.com/settings/sso --delivery email --recipient-email it@customer.example`.
