API Reference
Explore and integrate against the complete admin and protocol API — documented live from the running server.
What it is
HelixIAM publishes its full API as OpenAPI, generated directly from the running server, so the reference is always exactly in step with the version you are running. Browse it interactively, or pull the spec to generate a typed client in your language of choice.
| Resource |
URL |
| Interactive docs |
/swagger-ui.html |
| OpenAPI spec |
/v3/api-docs |
# Fetch the machine-readable spec
curl https://auth.example.com/v3/api-docs -o helix-openapi.json
The spec covers both the admin API (realms, applications, users, roles, scopes, identity providers, sessions, webhooks, SCIM targets, import/export) and the protocol endpoints (OIDC, SAML, account).
Generate a client
Point any OpenAPI generator at the spec to scaffold a typed SDK:
openapi-generator-cli generate \
-i helix-openapi.json \
-g typescript-fetch \
-o ./helix-client
Use standard OIDC or a generated client
For login flows, integrate over standard OIDC with any library — no HelixIAM SDK required. For admin automation, generate a typed client from this OpenAPI spec in your language of choice. A first-party TypeScript SDK is in development.
Dynamic Client Registration
Applications can register themselves programmatically via Dynamic Client Registration (DCR) at:
DCR is protected by an initial access token issued by an administrator. Present it to register a new client and receive its credentials and a registration access token for later management.
POST /realms/acme/connect/register
Authorization: Bearer <initial-access-token>
Content-Type: application/json
{
"client_name": "Acme Web",
"redirect_uris": ["https://app.example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"]
}
Besides the RFC 7591 basics, registration accepts and returns these OpenID Connect metadata (v1.1.0-rc.14):
| Metadata |
Admin API field |
Notes |
jwks |
jwks |
A JWK Set by value, instead of jwks_uri; the two are mutually exclusive. 1 to 10 public signing keys |
id_token_signed_response_alg |
idTokenSignatureAlg |
RS256, PS256 or ES256 |
userinfo_signed_response_alg |
userinfoSignedResponseAlg |
Userinfo is answered as a signed JWT |
logo_uri, policy_uri, tos_uri |
logoUri, policyUri, tosUri |
https only; shown on the sign-in and consent pages |
request_uris |
requestUris |
At most 10 https URLs a request object may be fetched from |
initiate_login_uri |
initiateLoginUri |
https only |
A registration without scope gets openid, plus offline_access for a client of the refresh_token grant. A
response that issues a client_secret carries client_secret_expires_at: 0. Response types with id_token or token
need the implicit grant, which the realm administrator must allow for registration (never by default). Details:
OIDC client settings and OpenID Connect flows.
Mint initial access tokens carefully
Treat initial access tokens like onboarding credentials: scope them, time-box them, and hand them only to trusted provisioning systems.
Endpoint catalog
The tables below are generated from the running server's OpenAPI spec (/v3/api-docs). Helix exposes two API surfaces that authenticate differently — see Authenticating to the API:
| Surface |
Path prefix |
Auth |
| Admin API |
/admin/realms/{realm}/… |
Admin session + CSRF (writes need X-XSRF-TOKEN) |
| Protocol |
/realms/{realm}/… |
OAuth2 / OIDC bearer tokens |
Admin API
All paths below are relative to /admin/realms/{realm}.
Users
| Method & path |
Purpose |
GET /users · POST /users |
List / create users |
GET · PUT · DELETE /users/{userId} |
Read / update / delete a user |
GET · POST /users/{userId}/roles |
List / assign user role mappings |
DELETE /users/{userId}/roles/{roleId} |
Unassign a role |
GET /users/{userId}/credentials |
List a user's credentials |
DELETE /users/{userId}/credentials/{type}/{id} |
Revoke a credential |
PUT /users/{userId}/password |
Reset a user's password |
GET · PUT /users/{userId}/required-actions |
Get / set required actions |
POST /users/{userId}/impersonate |
Impersonate a user |
GET /users/{userId}/gdpr/export |
Export a user's personal data |
GET /users/{userId}/gdpr/consents |
List a user's consent records |
DELETE /users/{userId}/gdpr |
Erase a user (right to be forgotten) |
POST /users/import |
Bulk-import users |
Clients
| Method & path |
Purpose |
GET /clients · POST /clients |
List / create OIDC clients |
GET · PUT · DELETE /clients/{id} |
Read / update / delete a client |
GET · POST /clients/{id}/secret |
Reveal / regenerate the client secret |
GET · POST /clients/{clientId}/roles · DELETE .../roles/{name} |
Client roles |
GET · POST /clients/{clientId}/mappers · PUT · DELETE .../mappers/{mapperId} |
Protocol mappers |
GET · POST · DELETE /clients/{clientId}/service-account/roles |
Service-account role mappings |
GET · PUT /clients/{clientId}/allowed-resources |
Resource-indicator allow-list (RFC 8707) |
GET · PUT /clients/{clientId}/authz/settings |
Authorization Services (UMA) settings |
GET · POST /clients/{clientId}/authz/resources · DELETE .../resources/{name} |
UMA resources |
GET · POST /clients/{clientId}/authz/policies · DELETE .../policies/{name} |
UMA policies |
GET · POST /clients/{clientId}/authz/permissions · DELETE .../permissions/{name} |
UMA permissions |
GET · POST /clients/{clientId}/authz/scopes · DELETE .../scopes/{name} |
UMA scopes |
POST /clients/{clientId}/authz/evaluate |
Evaluate an authorization request |
Roles
| Method & path |
Purpose |
GET /roles · POST /roles |
List / create realm roles |
DELETE /roles/{roleId} |
Delete a realm role |
PUT /roles/{roleId}/default |
Set the realm's default role |
Groups
| Method & path |
Purpose |
GET /groups · POST /groups |
List / create groups |
PUT · DELETE /groups/{groupId} |
Update / delete a group |
GET /groups/{groupId}/members · PUT · DELETE .../members/{userId} |
Group membership |
GET /groups/{groupId}/roles · PUT · DELETE .../roles/{roleId} |
Group role mappings |
Organizations
| Method & path |
Purpose |
GET /organizations · POST /organizations |
List / create organizations |
GET · PUT · DELETE /organizations/{orgId} |
Read / update / delete an organization |
GET /organizations/{orgId}/members · PUT · DELETE .../members/{userId} |
Organization membership |
Client scopes
| Method & path |
Purpose |
GET /client-scopes · POST /client-scopes |
List / create client scopes |
GET · DELETE /client-scopes/{scopeId} |
Read / delete a client scope |
PUT · DELETE /client-scopes/{scopeId}/claims/{claimId} |
Attach / detach a claim mapper |
Claims
| Method & path |
Purpose |
GET /claims · POST /claims |
List / create claim mappers |
PUT · DELETE /claims/{claimId} |
Update / delete a claim mapper |
Identity providers
| Method & path |
Purpose |
GET /identity-providers · POST /identity-providers |
List / create identity providers |
GET · PUT · DELETE /identity-providers/{alias} |
Read / update / delete a provider |
Webhooks
| Method & path |
Purpose |
GET /webhooks · POST /webhooks |
List / create subscriptions |
PUT · DELETE /webhooks/{id} |
Update / remove a subscription |
Applications
| Method & path |
Purpose |
GET /applications · POST /applications |
List / create applications |
GET · PUT · DELETE /applications/{name} |
Read / update / delete an application |
Agents (AI / non-human identity)
| Method & path |
Purpose |
GET /agents · POST /agents |
List / create agents |
GET · PUT · DELETE /agents/{id} |
Read / update / delete an agent |
POST /agents/{id}/activate · /suspend · /revoke |
Lifecycle transitions |
GET /agents/owner-review |
Owner attestation / review queue |
SAML clients
| Method & path |
Purpose |
GET /saml-clients · POST /saml-clients |
List / register SAML relying parties |
GET · PUT · DELETE /saml-clients/{entityId} |
Read / update / delete a SAML client |
POST /saml-clients/import · /import-url |
Import from metadata (body / URL) |
Keys
| Method & path |
Purpose |
GET /keys |
List realm signing keys |
GET /keys/access |
Whether the signed-in admin may change keys (realm-admin) |
POST /keys/import |
Import a private key + certificate chain (PENDING) |
POST /keys/csr |
Generate a PENDING key and a CSR (purpose: all, access, id or saml; empty = all). In a custody realm the key is generated in the realm's backend |
GET /keys/{keyId}/csr |
Download a key's CSR |
PUT /keys/{keyId}/certificate |
Attach a CA-signed certificate chain |
POST /keys/{keyId}/activate |
Activate a PENDING key (?force=true skips the staging time) |
DELETE /keys/{keyId} |
Retire a key (never the ACTIVE RS256 key) |
GET /settings/signing · PUT /settings/signing |
Realm signing algorithms (defaultAlg, samlAlg) |
POST /keys/rotate |
Generate and activate a new key |
Key custody (HSM / KMS)
See Key custody. Changing a profile needs a master-realm administrator.
| Method & path |
Purpose |
GET /key-custody |
The realm's profile (STANDARD, PROTECTED, HIGH), backend, backend health (backendHealthy, backendReachable, kekQuarantined), the backend's isolation (backendIsolation: level shared or dedicated, realmCount, dedicatedToRealm, allowsRealm; never other realms' ids), requireDedicatedBackendForHigh, kekReleaseState (DISABLED, DESTROYING or null), and keys per purpose with their custody |
PUT /key-custody |
Move the realm: {"profile", "backendId"}; 202 with the planned keys and when each starts signing. 400 on backendId when the backend cannot serve the realm's algorithms, is dedicated to other realms (backendRealmNotAllowed) or, with require-dedicated-backend-for-high, is not the realm's alone for High assurance (backendNotDedicated); 400 on profile, naming each one, while an enabled SAML service provider asks for an algorithm the target cannot sign (RSA-SHA1 outside Standard, RSA-SHA512 in High assurance) or, for High assurance, a wallet connection still signs with a software verifier key; 409 with code kekRotationRunning during an unfinished key-encryption key rotation, or kekReleasePending while the realm's key-encryption key is being released on a key store that no longer serves it |
GET /key-custody/kek-rotation |
The realm's latest key-encryption key rotation ({"rotation": null} when none): state (REWRAPPING, DISABLING, DONE, FAILED, ABANDONED), paused, rowsDone/rowsTotal, lastErrorCode/lastError/lastErrorKeys, KEK references and times. Any administrator of the realm. A paused rotation answers 503 temporarily_unavailable with Retry-After, code kekRotationPaused and the rotation |
POST /key-custody/kek-rotation |
Start (202) a rotation of a Protected realm's key-encryption key, or get the one running (200); resumes a stopped one (202). Master-realm administrators only (403). 409 with code: kekRotationNotProtected, kekRotationNoKek, kekRotationDbEncryptionKek, kekRotationChanged, kekRotationRefused; 400 with code backendRealmNotAllowed when the realm's backend no longer serves it (no KEK is made); 503 when the backend cannot be reached |
DELETE /key-custody/kek-rotation |
Abandon a stopped rotation that moved no key (200; the realm's key-encryption key is the earlier one again). Master-realm administrators only. 409 kekRotationNotStopped, kekRotationNewKekInUse or kekRotationUnlabelledKeys (keys written by an earlier release without a recorded KEK: resume instead); 400 backendRealmNotAllowed when the realm's backend no longer serves it |
PUT /key-custody/key-store-policy |
Set the realm's key-store policy: {"policy": "any" \| "sovereign"}; 200 with realmId, keyStorePolicy and changed. Master-realm administrators only (403). 409 keyStorePolicyConflict when the realm's current key store or a live key breaks the policy; 400 on policy when missing or unknown. GET /key-custody also answers keyStorePolicy and backendStoreClass; PUT /key-custody takes an optional keyStorePolicy, and refuses with the code keyStorePolicy a change the policy forbids |
POST /key-custody/kek-release/finish |
Finish a release of the realm's key-encryption key that is stuck at destroying (no server can finish it). Master-realm administrators only (403). 200 with destroyedInBackend and keks (forgotten ones are to be removed in the key store by hand); 409 kekReleaseNotDestroying when there is nothing to finish |
POST /verifier-keys/generate |
Generate a wallet verifier key (ES256 / ES384) in a backend: {name, algorithm, backendId} |
POST /verifier-keys/{name}/csr |
The verifier key's CSR, signed in the backend: {subject, dnsNames} |
PUT /verifier-keys/{name}/certificate |
Attach the CA-issued chain: {certificateChainPem} |
GET /verifier-keys |
Verifier keys that can sign; ?pending=true adds keys waiting for a certificate |
Credential issuer keys (HSM / KMS)
Paths are relative to the realm (/admin/realms/{realm}), as in the other tables. Writes need a realm administrator. See Key custody: credential issuer keys. Every answer to a GET carries the realm's profile in the X-Helix-Custody-Profile header.
| Method & path |
Purpose |
GET /credential-issuance/keys |
List issuer keys: id, kid, status, source, subject, issuer, notBefore, notAfter, fingerprint, chainPem, csrPem, createdAt, activatedAt, rotatedAt, custody, backendId (never a reference or key material) |
POST /credential-issuance/keys/generate |
Generate a test key certified by the realm's development CA. 400 code devCaRefused in High assurance; 409 code devCaSoftware while a software CA would certify a backend key |
POST /credential-issuance/keys/import |
Import {privateKeyPem, certificateChainPem}. 400 on privateKeyPem, code softwareKeyRefused, in High assurance |
POST /credential-issuance/keys/csr |
Generate a PENDING key and its CSR: {subject, dnsNames}. In Protected and High assurance the key is generated in the realm's backend |
PUT /credential-issuance/keys/{keyId}/certificate |
Attach the CA-signed chain: {certificateChainPem} |
POST /credential-issuance/keys/{keyId}/activate · POST /credential-issuance/keys/{keyId}/retire |
Activate a PENDING key / retire a key (the ACTIVE key: 409) |
GET /credential-issuance/keys/ca |
The development CA: {certificatePem, custody} |
DELETE /credential-issuance/keys/ca |
Retire the development CA: 204; 404 when there is none; 409 while an ACTIVE or PENDING generated key chains to it |
An unreachable backend is 503 temporarily_unavailable with Retry-After.
eID SP keys (HSM / KMS)
Paths are relative to the realm too, for eID connections (eid, digid, eherkenning, eidas). They need manage-identity-providers; a connection that is authoritative for the BSN (DigiD, eIDAS) also needs a realm administrator for every write. See Key custody: eID SP keys.
| Method & path |
Purpose |
GET /identity-providers/{alias}/sp-keys |
The connection's keys: id, usage, status, rsaBits, keyTransport, custody, backendId, subject, issuer, notAfter, fingerprint, chainPem, csrPem, createdAt, activatedAt; the realm's custody profile in the X-Helix-Custody-Profile response header |
GET /identity-providers/{alias}/sp-keys/algorithms |
What this scheme and backend allow: rsaBits, keyTransport ({method, digest, mgf} list), signatureAlgorithms, defaultKeyTransport, separateKeys |
POST /identity-providers/{alias}/sp-keys/csr |
Generate a key in the realm's backend and its CSR: {usage: SIGNING \| DECRYPTION \| SIGNING_DECRYPTION, rsaBits, keyTransport, subject, dnsNames}; 201. 400 on usage for SIGNING_DECRYPTION on eIDAS; 400 on keyTransport when the backend cannot honour the combination; 409 code tooManyPending above the pending cap |
PUT /identity-providers/{alias}/sp-keys/{keyId}/certificate |
Attach the CA-signed chain: {certificateChainPem} |
POST /identity-providers/{alias}/sp-keys/{keyId}/activate · POST /identity-providers/{alias}/sp-keys/{keyId}/retire |
Activate (200, the key) / retire (204; 404 for an unknown key; 409 for the ACTIVE key: activate its successor first) |
Clear a pasted key with clearSpSigningPrivateKey or clearSpDecryptionPrivateKey set to true in the provider's update body. A High-assurance realm refuses pasted keys (code pastedKeyInHighAssurance).
| Method & path |
Purpose |
GET /saml-idp/metadata-settings |
{signed, validityHours, lastError} (view-clients) |
PUT /saml-idp/metadata-settings |
{"signed": true, "validityHours": 168}; both fields required, validity 1 to 720 hours. signed: true makes one probe signature first: 400 on fieldErrors.signed when the key cannot sign, 503 when the backend is unreachable (manage-clients) |
Off by default. See Key custody: SAML metadata signing.
Sessions
| Method & path |
Purpose |
GET /sessions |
List active sessions |
DELETE /sessions/{id} |
Revoke a session |
GET /sessions/service-accounts |
List service-account sessions |
Authentication flows
| Method & path |
Purpose |
GET /flows · POST /flows |
List / create authentication flows |
GET · PUT · PATCH · DELETE /flows/{alias} |
Read / save / rename / delete a flow |
GET · PUT /flow |
Get / save the browser sign-in flow |
GET /authenticators |
List available authenticators |
Admin roles (RBAC)
| Method & path |
Purpose |
GET /admin-roles |
List admin roles |
PUT /admin-roles/{roleId} |
Set an admin role's permissions |
GET /admin-roles/permissions |
List assignable admin permissions |
Messaging (SMS / email / push)
| Method & path |
Purpose |
GET · PUT /messaging/providers |
List / save channel providers |
DELETE /messaging/providers/{channel}/{driver} |
Remove a provider |
POST /messaging/providers/{channel}/test |
Send a test message |
GET · PUT /messaging/templates |
List / save message templates |
POST /messaging/templates/preview |
Preview a rendered template |
GET · POST /messaging/push-tokens |
List / register push tokens |
SCIM targets (outbound provisioning)
| Method & path |
Purpose |
GET /scim-targets · POST /scim-targets |
List / register downstream SCIM targets |
PUT · DELETE /scim-targets/{id} |
Update / remove a target |
Import / export
| Method & path |
Purpose |
GET /export |
Export the realm |
POST /import |
Import a realm |
POST /import/keycloak |
Import from a Keycloak export |
POST /users/import |
Bulk-import users |
Realm settings & operations
| Method & path |
Purpose |
GET · PUT /settings |
Read / update realm settings. Creating a realm: 400 on realmId for an id that ends in -kek or starts with another realm's id followed by -kek (fieldErrorCodes.realmId = realmIdKek), and, while a key store is bound to realms, for an id that is another realm's id followed by -, the start of one, or differs from one only in case (fieldErrorCodes.realmId = realmIdPrefix). A realm import reports such a refusal as a failed realm entry with that code |
GET · PUT /subject-claim |
Read / set the subject-claim strategy |
GET · PUT /provisioning |
Read / update DCR & provisioning config |
POST /provisioning/initial-access-tokens |
Mint a DCR initial access token |
GET /endpoints |
Realm endpoint URLs |
GET /health |
Realm health |
GET /events |
Query the audit-event log |
POST /user-federation/{alias}/sync |
Trigger an LDAP sync |
GET/POST /workload-identity · GET/PUT/DELETE /workload-identity/{id} |
Workload identity federation configs |
Global admin endpoints
A few endpoints are server-wide rather than realm-scoped: GET /admin/metrics/summary (Prometheus-style summary), GET /admin/audit/config, and GET /admin/key-custody/plugins (the custody plugins the server loaded: type, pluginVersion, spiVersion, file, sha256Prefix; master-realm administrators only), the database encryption key rotation under /admin/database-encryption (GET the state; POST /rotation to start, POST /rotation/pause, /rotation/resume and /rotation/retry; master-realm administrators only) and GET /admin/key-custody/backends (the configured key custody backends: id, type, storeClass (software, sovereign, hyperscaler or plugin), algorithms, health, latency, and isolation: isolation shared or dedicated with its realms ids, and when there is something to say realmBinding, prefixOverlaps (realm, overlapsWith, isolationEnforced) and warnings; never their settings; master-realm administrators only).
Protocol endpoints (bearer / public)
These run under the realm prefix /realms/{realm}/… and authenticate with bearer tokens (or their own onboarding credential), not an admin session.
| Method & path |
Auth |
Purpose |
/account/** |
User bearer token |
End-user self-service — see Account console |
/scim/v2/** |
Per-realm SCIM token |
SCIM 2.0 provisioning — see SCIM |
POST /connect/register · GET/PUT/DELETE /connect/register/{clientInternalId} |
Initial / registration access token |
Dynamic Client Registration (RFC 7591) |
POST /workload-identity/token |
Workload JWT |
Exchange a workload JWT for a Helix token |
POST /agent/delegation/token |
Client / bearer |
On-behalf-of agent delegation (RFC 8693) |
POST /device/enroll · /device/enroll/start |
Enrollment token |
Device / MFA enrollment |
GET /push/{id} · POST /push/{id}/approve · /deny |
Session |
Push-based MFA approval |
GET /qr/{id} · POST /qr/{id}/confirm |
Session |
QR-based device confirmation |
POST /tx · GET /tx/{id} · POST /tx/{id}/sign · /consume |
Bearer |
Signing / consent transactions |
GET /saml/idp/metadata |
Public |
SAML 2.0 IdP metadata |
GET /.well-known/oauth-protected-resource |
Public |
RFC 9728 protected-resource metadata |
Standard OIDC/SAML endpoints
The usual protocol endpoints — /authorize, /token, /userinfo, /logout, /.well-known/openid-configuration, JWKS — are advertised by the realm's discovery document. See the OIDC quickstart.
Discovery additions in 1.1.0-rc.14
/realms/{realm}/.well-known/openid-configuration also states:
scopes_supported (openid, profile, email, address, phone) and address in claims_supported;
request_parameter_supported, request_uri_parameter_supported and require_request_uri_registration (all true), with request_object_signing_alg_values_supported (RS256);
userinfo_signing_alg_values_supported;
response_modes_supported: query and form_post, plus fragment where the implicit and hybrid flows are advertised;
frontchannel_logout_supported and frontchannel_logout_session_supported (true);
check_session_iframe, only in a realm where a client uses session management;
- the implicit and hybrid response types and the
implicit grant, only in a realm where a client has that grant or registration may add it.
See OpenID Connect flows.
See also