Hanzo

Iam

Package iam is Hanzo's identity provider: users, organizations, applications, and the OIDC/OAuth2 endpoints every Hanzo service authenticates against.

Package iam is Hanzo's identity provider: users, organizations, applications, and the OIDC/OAuth2 endpoints every Hanzo service authenticates against.

Base URLhttps://api.hanzo.ai
Operations193
AuthAuthorization: Bearer $HANZO_API_KEY

iam

GET /v1/iam/.well-known/jwks

Publishes the public keys that verify the tokens issued here — the one URL you point a service at so it can check a token itself, offline, without calling back and without holding any secret of ours.

Keys appear here before they start signing and stay after they stop, so a rotation never leaves a live token unverifiable. Nothing private is ever published.

GET /v1/iam/.well-known/oauth-authorization-server

Returns the OpenID Connect discovery document — the one URL you point a standards-compliant client at so it can find every other endpoint on its own, instead of you configuring them by hand.

It advertises only what is actually implemented, so a client that reads it cannot ask for a flow that will fail: the authorization-code flow, PKCE with S256, the supported grants, and the signing algorithms whose public keys the JWKS really publishes.

The issuer is derived from the host you asked on and is the same value the tokens carry, so a client that pins the issuer never sees it change.

GET /v1/iam/.well-known/openid-configuration

Returns the OpenID Connect discovery document — the one URL you point a standards-compliant client at so it can find every other endpoint on its own, instead of you configuring them by hand.

It advertises only what is actually implemented, so a client that reads it cannot ask for a flow that will fail: the authorization-code flow, PKCE with S256, the supported grants, and the signing algorithms whose public keys the JWKS really publishes.

The issuer is derived from the host you asked on and is the same value the tokens carry, so a client that pins the issuer never sees it change.

GET /v1/iam/account

Returns the signed-in person's own account and the organization they belong to — what a console reads to draw the account menu.

Passwords, API secrets and MFA material are stripped. It answers for a session cookie or a bearer token alike.

POST /v1/iam/add-application

Registers an application in your organization — one product or site your people sign in to, with its own client credentials, sign-in methods and allowed redirect URIs.

The older spelling of POST /v1/iam/application. A name already used in the organization is refused rather than overwritten.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
affiliationUrlstring
categorystring
certstring
certObjiam.Cert
certPublicKeystring
clientCertstring
clientIdstringClientId is the OAuth2/OIDC client identifier and the GLOBAL key every confidential-client resolver authenticates…
clientSecretstring
codeResendTimeoutinteger
cookieExpireInHoursinteger
createdAtstring
createdTimestring
customScopesiam.ScopeDescription[]
defaultGroupstring
deletedboolean
descriptionstring
disableSamlAttributesboolean
disableSigninboolean
displayNamestring
domainstring
enableAutoSigninboolean
enableCodeSigninboolean
enableExclusiveSigninboolean
enableLinkWithEmailboolean
enablePasswordboolean
enableSamlAssertionSignatureboolean
enableSamlC14n10boolean
enableSamlCompressboolean
enableSamlPostBindingboolean
enableSignUpboolean
enableSigninSessionboolean
enableWebAuthnboolean
environmentstring
expireInHoursnumber
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
footerHtmlstring
forcedRedirectOriginstring
forgetUrlstring
50 more fields in the schema

POST /v1/iam/add-membership

Lets a person or an application act in an organization. It is the grant behind "add someone to the team", and it is safe to repeat — granting a membership that already exists changes nothing. Granting membership IS the org's authority to give, so it takes the same gate a write to that org's own registry row takes: a SuperAdmin, an admin of the org itself, or an org-admin-capable confidential client. One rule, one place (internal/authz).

POST /v1/iam/add-organization

Creates an organization — the account everything else in your directory hangs from. Users, applications, roles, projects and workspaces are all named inside one organization, so this is the first write in a new tenant.

The older spelling of POST /v1/iam/organizations. Both reach the same create, so a name already taken is refused here too.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accountItemsiam.AccountItem[]
accountMenustring
balanceCreditnumber
balanceCurrencystring
countryCodesstring[]
createdAtstring
createdTimestring
dcrPolicystring
defaultApplicationstring
defaultAvatarstring
defaultPasswordstring
deletedboolean
disableSigninboolean
displayNamestring
enableSoftDeletionboolean
enableTourboolean
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
founderstring
hasPrivilegeConsentboolean
idstring
initScoreinteger
ipRestrictionstring
ipWhiteliststring
isPersonalboolean
isProfilePublicboolean
kerberosKdcHoststring
kerberosKeytabstring
kerberosRealmstring
kerberosServiceNamestring
languagesstring[]
ldapAttributesstring[]
logostring
logoDarkstring
masterPasswordstring
masterVerificationCodestring
mfaItemsiam.MfaItem[]
mfaRememberInHoursinteger
namestring
19 more fields in the schema

POST /v1/iam/add-project

Creates a project inside your organization — the scope people pick between when their work is separated by product or client rather than by team.

The older spelling of POST /v1/iam/projects. Creating one takes an administrator of the owning organization.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
createdTimestring
descriptionstring
displayNamestring
isDefaultboolean
metadatastring
namestring
organizationstring
ownerstring
tagsstring[]
workspacestring

POST /v1/iam/add-provider

Adds an identity provider your people can sign in with, or a service your applications send through — a social or enterprise login, an email or SMS sender, a storage or payment connector.

A provider is configured once here and then switched on per application, so several applications can share one set of credentials.

The older spelling of POST /v1/iam/providers.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
appIdstring
bucketstring
categorystring
certstring
clientIdstring
clientId2string
clientSecretstring
clientSecret2string
contentstring
createdAtstring
createdTimestring
customAuthUrlstring
customLogostring
customTokenUrlstring
customUserInfoUrlstring
deletedboolean
disableSslboolean
displayNamestring
domainstring
emailRegexstring
enablePkceboolean
enableProxyboolean
enableSignAuthnRequestboolean
endpointstring
hoststring
httpHeadersobject
idstring
idPstring
intranetEndpointstring
issuerUrlstring
metadatastring
methodstring
namestring
ownerstring
pathPrefixstring
portinteger
providerUrlstring
receiverstring
regionIdstring
scopesstring
8 more fields in the schema

POST /v1/iam/add-role

Creates a role — a named group of people that permissions are granted to. Granting to a role rather than to each person is what keeps access correct as your team changes: add someone to the role and they inherit everything it can do.

The older spelling of POST /v1/iam/roles.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
createdTimestring
descriptionstring
displayNamestring
domainsstring[]
groupsstring[]
isEnabledboolean
namestring
ownerstring
rolesstring[]
usersstring[]

POST /v1/iam/add-user

Adds a person to your organization and, if you send a password, sets the one they will sign in with. The password is hashed before it is stored and is never returned to you or to anyone else.

Usernames are checked against one rule wherever an account is created — this verb, password signup, a social sign-in, or SCIM — so a name accepted here is a name accepted everywhere.

The older spelling of POST /v1/iam/users, and it posts the user's fields at the top level rather than wrapped in {user, password}.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessKeystring
accessSecretstring
accessSecretHashstring
accessTokenstring
addressstring[]
addressesiam.Address[]
adfsstring
affiliationstring
alipaystring
amazonstring
applestring
applicationScopesiam.ConsentRecord[]
auth0string
avatarstring
avatarTypestring
azureadstring
azureadb2cstring
baidustring
balancenumber
balanceCreditnumber
balanceCurrencystring
battlenetstring
bilibilistring
biostring
birthdaystring
bitbucketstring
boxstring
cartiam.CartItem[]
cloudfoundrystring
countryCodestring
createdAtstring
createdIpstring
createdTimestring
currencystring
customstring
custom2string
custom3string
custom4string
custom5string
custom6string
147 more fields in the schema

POST /v1/iam/add-workspace

Creates a workspace inside your organization — the scope a team works in, alongside projects rather than instead of them.

The older spelling of POST /v1/iam/workspaces. Creating one takes an administrator of the owning organization.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
bucketstring
createdTimestring
descriptionstring
displayNamestring
isDefaultboolean
metadatastring
namestring
organizationstring
ownerstring
tagsstring[]

POST /v1/iam/admin/applications/upsert

Creates an application or updates it in place, so a deployment can declare the applications it needs and run the same declaration on every environment and on every redeploy.

It says which of the two it did. Leave the client secret out and the existing one is kept — so re-running your deployment does not rotate a credential your running services are holding.

ParameterInTypeRequiredDescription
Authorizationheaderstring

Request bodyapplication/json (required)

FieldTypeRequiredDescription
certstring
clientIdstring
clientSecretstring
displayNamestring
enableCodeSigninbooleanEnableCodeSignin offers sign-in by an emailed or texted one-time code beside the password.
expireInHoursnumberExpireInHours and RefreshExpireInHours are the application's token lifetimes.
grantTypesstring[]
isSharedbooleanIsShared declares that this application serves EVERY organization, not only the one named in Organization.
namestring
organizationstring
publicbooleanPublic declares a client that CANNOT hold a credential — a browser SPA, a CLI, a desktop app.
redirectUrisstring[]
refreshExpireInHoursnumber

POST /v1/iam/admin/provision

Sets up an account on someone's behalf — the same onboarding a person gets themselves, driven by one of your own services instead of by them.

It authenticates as your service rather than as a person, which is why the person to provision is named in the request. The setup it performs is identical to self-service onboarding; there is one provisioning path, not two that can drift.

POST /v1/iam/admin/users/upsert

Creates a person or updates them in place, so a deployment can declare the accounts it needs and re-run that declaration safely.

Passwords are hashed before they are stored. Leave the password out and their current one is kept, so a redeploy never locks somebody out.

ParameterInTypeRequiredDescription
Authorizationheaderstring

Request bodyapplication/json (required)

FieldTypeRequiredDescription
displayNamestring
emailstring
isAdminboolean
namestring
ownerstring
passwordstring
passwordTypestring
phonestring

GET /v1/iam/application

Returns one application: its sign-in methods, its allowed redirect URIs and the client credentials your integration authenticates with.

ParameterInTypeRequiredDescription
ownerquerystringyes
namequerystringyes

POST /v1/iam/application

Registers an application in your organization — one product or site your people sign in to, with its own client credentials, sign-in methods and allowed redirect URIs. A name already used in the organization is refused rather than overwritten.

Exported so the legacy add-application alias reuses this exact path — one create, two spellings.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
affiliationUrlstring
categorystring
certstring
certObjiam.Cert
certPublicKeystring
clientCertstring
clientIdstringClientId is the OAuth2/OIDC client identifier and the GLOBAL key every confidential-client resolver authenticates…
clientSecretstring
codeResendTimeoutinteger
cookieExpireInHoursinteger
createdAtstring
createdTimestring
customScopesiam.ScopeDescription[]
defaultGroupstring
deletedboolean
descriptionstring
disableSamlAttributesboolean
disableSigninboolean
displayNamestring
domainstring
enableAutoSigninboolean
enableCodeSigninboolean
enableExclusiveSigninboolean
enableLinkWithEmailboolean
enablePasswordboolean
enableSamlAssertionSignatureboolean
enableSamlC14n10boolean
enableSamlCompressboolean
enableSamlPostBindingboolean
enableSignUpboolean
enableSigninSessionboolean
enableWebAuthnboolean
environmentstring
expireInHoursnumber
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
footerHtmlstring
forcedRedirectOriginstring
forgetUrlstring
50 more fields in the schema

PUT /v1/iam/application

Changes an application's display, its sign-in methods and the redirect URIs it may return to — the call that makes login work from a new host. Which organization it belongs to and what it is named are fixed when it is created and are not editable here.

Exported so the legacy update-application alias reuses this exact path — one update, two spellings.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
affiliationUrlstring
categorystring
certstring
certObjiam.Cert
certPublicKeystring
clientCertstring
clientIdstringClientId is the OAuth2/OIDC client identifier and the GLOBAL key every confidential-client resolver authenticates…
clientSecretstring
codeResendTimeoutinteger
cookieExpireInHoursinteger
createdAtstring
createdTimestring
customScopesiam.ScopeDescription[]
defaultGroupstring
deletedboolean
descriptionstring
disableSamlAttributesboolean
disableSigninboolean
displayNamestring
domainstring
enableAutoSigninboolean
enableCodeSigninboolean
enableExclusiveSigninboolean
enableLinkWithEmailboolean
enablePasswordboolean
enableSamlAssertionSignatureboolean
enableSamlC14n10boolean
enableSamlCompressboolean
enableSamlPostBindingboolean
enableSignUpboolean
enableSigninSessionboolean
enableWebAuthnboolean
environmentstring
expireInHoursnumber
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
footerHtmlstring
forcedRedirectOriginstring
forgetUrlstring
50 more fields in the schema

DELETE /v1/iam/application

Removes an application. Anyone mid-sign-in through it is turned away and its client credentials stop working, so retire the integration before deleting it.

ParameterInTypeRequiredDescription
ownerquerystringyes
namequerystringyes

POST /v1/iam/applications/delete

Removes an application. Anyone mid-sign-in through it is turned away and its client credentials stop working, so retire the integration before deleting it.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

GET /v1/iam/applications/get

Returns one application: its sign-in methods, its allowed redirect URIs and the client credentials your integration authenticates with.

ParameterInTypeRequiredDescription
ownerquerystringyes
namequerystringyes

POST /v1/iam/applications/update

Changes an application's display, its sign-in methods and the redirect URIs it may return to — the call that makes login work from a new host. Which organization it belongs to and what it is named are fixed when it is created and are not editable here.

Exported so the legacy update-application alias reuses this exact path — one update, two spellings.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
affiliationUrlstring
categorystring
certstring
certObjiam.Cert
certPublicKeystring
clientCertstring
clientIdstringClientId is the OAuth2/OIDC client identifier and the GLOBAL key every confidential-client resolver authenticates…
clientSecretstring
codeResendTimeoutinteger
cookieExpireInHoursinteger
createdAtstring
createdTimestring
customScopesiam.ScopeDescription[]
defaultGroupstring
deletedboolean
descriptionstring
disableSamlAttributesboolean
disableSigninboolean
displayNamestring
domainstring
enableAutoSigninboolean
enableCodeSigninboolean
enableExclusiveSigninboolean
enableLinkWithEmailboolean
enablePasswordboolean
enableSamlAssertionSignatureboolean
enableSamlC14n10boolean
enableSamlCompressboolean
enableSamlPostBindingboolean
enableSignUpboolean
enableSigninSessionboolean
enableWebAuthnboolean
environmentstring
expireInHoursnumber
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
footerHtmlstring
forcedRedirectOriginstring
forgetUrlstring
50 more fields in the schema

GET /v1/iam/applications

Returns the applications in one organization, newest first — each product or site your people sign in to, with the sign-in methods and redirect URIs it allows.

ParameterInTypeRequiredDescription
ownerquerystringyes

POST /v1/iam/applications

Registers an application in your organization — one product or site your people sign in to, with its own client credentials, sign-in methods and allowed redirect URIs. A name already used in the organization is refused rather than overwritten.

Exported so the legacy add-application alias reuses this exact path — one create, two spellings.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
affiliationUrlstring
categorystring
certstring
certObjiam.Cert
certPublicKeystring
clientCertstring
clientIdstringClientId is the OAuth2/OIDC client identifier and the GLOBAL key every confidential-client resolver authenticates…
clientSecretstring
codeResendTimeoutinteger
cookieExpireInHoursinteger
createdAtstring
createdTimestring
customScopesiam.ScopeDescription[]
defaultGroupstring
deletedboolean
descriptionstring
disableSamlAttributesboolean
disableSigninboolean
displayNamestring
domainstring
enableAutoSigninboolean
enableCodeSigninboolean
enableExclusiveSigninboolean
enableLinkWithEmailboolean
enablePasswordboolean
enableSamlAssertionSignatureboolean
enableSamlC14n10boolean
enableSamlCompressboolean
enableSamlPostBindingboolean
enableSignUpboolean
enableSigninSessionboolean
enableWebAuthnboolean
environmentstring
expireInHoursnumber
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
footerHtmlstring
forcedRedirectOriginstring
forgetUrlstring
50 more fields in the schema

POST /v1/iam/audit-logs/delete

Removes an audit entry. Retention policy is normally what should expire a trail; deleting by hand leaves a gap a reviewer will notice.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/audit-logs/get

Returns one audit entry in full: the action, the person or key behind it, and the request it came in on.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/audit-logs/update

Corrects an audit entry. The trail is append-only in normal operation and nothing in the Hanzo Cloud rewrites it — this exists for an administrator to correct an entry their own systems recorded wrongly.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
actionstring
clientIpstring
createdTimestring
isTriggeredboolean
languagestring
methodstring
namestring
objectstring
organizationstring
ownerstring
requestUristring
responsestring
statusCodeinteger
userstring

GET /v1/iam/audit-logs

Returns your organization's audit trail, newest first — who did what, when, and from where. It is the record you reach for during a security review or an incident.

You see your own organization's audit trail and no one else's; which organization that is comes from your credentials, not from the request.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/audit-logs

Records an audit entry, so activity from your own systems lands in the same trail as everything the Hanzo Cloud records for you.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
actionstring
clientIpstring
createdTimestring
isTriggeredboolean
languagestring
methodstring
namestring
objectstring
organizationstring
ownerstring
requestUristring
responsestring
statusCodeinteger
userstring

GET /v1/iam/auth/application

Returns everything a login screen needs to draw itself for one application: its branding, and each sign-in method it offers with the provider details that method needs.

The client secret is masked. Read before anyone has signed in, so it carries only what is safe for a browser to see.

ParameterInTypeRequiredDescription
clientIdquerystringClientId is the application's OAuth client id — the one field that selects which login screen this is.
responseTypequerystringResponseType is the OAuth response type the screen will ask for.

GET /v1/iam/auth/methods

Returns the sign-in methods one application actually has switched on, so a login screen can render the right buttons for it without you hard-coding a list that drifts the moment you add a provider.

Public by design: it is read before anyone has signed in, and it exposes only which methods exist, never their credentials.

ParameterInTypeRequiredDescription
clientIdquerystringClientId is the application's OAuth client id.

POST /v1/iam/certs/delete

Removes a signing certificate. Tokens signed with it can no longer be verified, so retire it only once nothing is still presenting them.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/certs/get

Returns one signing certificate — its algorithm, its validity window and its public half. The private key is masked.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/certs/update

Changes a signing certificate's settings. What it is called does not change, and neither does when it was added.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessKeystring
accessSecretstring
accountstring
bitSizeinteger
certificatestring
createdAtstring
createdTimestring
cryptoAlgorithmstring
deletedboolean
displayNamestring
domainExpireTimestring
expireInYearsinteger
expireTimestring
idstring
namestring
ownerstring
privateKeystring
providerstring
scopestring
typestring
updatedAtstring

GET /v1/iam/certs

Returns your organization's signing certificates, newest first — the keys the tokens your applications verify are signed with. Private key material is masked.

You see your own organization's certificates and no one else's; which organization that is comes from your credentials, not from the request, so a query parameter can never widen the listing.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/certs

Adds a signing certificate your applications can verify tokens against — the call you make to bring your own key, or to stage the next one before a rotation. A name already used in your organization is refused.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessKeystring
accessSecretstring
accountstring
bitSizeinteger
certificatestring
createdAtstring
createdTimestring
cryptoAlgorithmstring
deletedboolean
displayNamestring
domainExpireTimestring
expireInYearsinteger
expireTimestring
idstring
namestring
ownerstring
privateKeystring
providerstring
scopestring
typestring
updatedAtstring

GET /v1/iam/consent

Returns the calling person's own privacy and communication choices. Somebody who has never set them gets the defaults rather than nothing, so a consent screen always has something to show — insights on, and training UNANSWERED, which is the state that means the screen still has to ask.

PUT /v1/iam/consent

Records the calling person's privacy and communication choices. Only their own — there is no way to set consent for somebody else.

Send only the answers you are changing. A question you leave out keeps the answer it already had, so a screen that saves one switch never revokes the other, and two screens saving at once do not undo each other.

An answer this version does not recognize is refused here rather than stored, so nothing is ever persisted for a later reader to have to interpret.

POST /v1/iam/delete-application

Deletes an application. Anyone mid-sign-in through it is turned away and its client credentials stop working, so retire the integration first.

The older spelling of DELETE /v1/iam/application.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
affiliationUrlstring
categorystring
certstring
certObjiam.Cert
certPublicKeystring
clientCertstring
clientIdstringClientId is the OAuth2/OIDC client identifier and the GLOBAL key every confidential-client resolver authenticates…
clientSecretstring
codeResendTimeoutinteger
cookieExpireInHoursinteger
createdAtstring
createdTimestring
customScopesiam.ScopeDescription[]
defaultGroupstring
deletedboolean
descriptionstring
disableSamlAttributesboolean
disableSigninboolean
displayNamestring
domainstring
enableAutoSigninboolean
enableCodeSigninboolean
enableExclusiveSigninboolean
enableLinkWithEmailboolean
enablePasswordboolean
enableSamlAssertionSignatureboolean
enableSamlC14n10boolean
enableSamlCompressboolean
enableSamlPostBindingboolean
enableSignUpboolean
enableSigninSessionboolean
enableWebAuthnboolean
environmentstring
expireInHoursnumber
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
footerHtmlstring
forcedRedirectOriginstring
forgetUrlstring
50 more fields in the schema

POST /v1/iam/delete-membership

Takes away a person's or an application's right to act in an organization. Their account survives; what ends is their access to that organization. Revoking a membership that is already gone reports that nothing was removed rather than failing, so a retry is safe. It is the mirror of ensure and takes the SAME gate: revoking membership is the org's authority to give or take, so a SuperAdmin, an admin of the org itself, or an org-admin-capable confidential client. Idempotent through the store — deleting an absent membership reports removed=false, never an error — so a retried revoke is safe.

POST /v1/iam/delete-mfa

Turns off the authenticator app for an account, so sign-in stops asking for a code. People may do this for themselves; doing it for somebody else takes an administrator, which is what makes it the reset path when a phone is lost.

POST /v1/iam/delete-organization

Deletes an organization and everything named inside it — its users, applications, roles, projects and workspaces. There is no undo, and every session issued under it stops working.

The older spelling of POST /v1/iam/organizations/delete.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/delete-project

Deletes a project. The people and roles in your organization are unchanged; what goes is the scope itself, so anything addressed by it must move first.

The older spelling of POST /v1/iam/projects/delete.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/delete-provider

Removes a provider. Sign-in through it stops for every application that used it, so detach those applications first if they have no other method.

The older spelling of POST /v1/iam/providers/delete.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
appIdstring
bucketstring
categorystring
certstring
clientIdstring
clientId2string
clientSecretstring
clientSecret2string
contentstring
createdAtstring
createdTimestring
customAuthUrlstring
customLogostring
customTokenUrlstring
customUserInfoUrlstring
deletedboolean
disableSslboolean
displayNamestring
domainstring
emailRegexstring
enablePkceboolean
enableProxyboolean
enableSignAuthnRequestboolean
endpointstring
hoststring
httpHeadersobject
idstring
idPstring
intranetEndpointstring
issuerUrlstring
metadatastring
methodstring
namestring
ownerstring
pathPrefixstring
portinteger
providerUrlstring
receiverstring
regionIdstring
scopesstring
8 more fields in the schema

POST /v1/iam/delete-role

Deletes a role. Everyone in it loses the access it carried; their accounts and any other roles they hold are untouched.

The older spelling of POST /v1/iam/roles/delete.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/delete-user

Removes a person from your organization. Their sessions stop working and the account is gone, not suspended — to keep the record and only stop sign-in, update the user instead.

The older spelling of POST /v1/iam/users/delete.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessKeystring
accessSecretstring
accessSecretHashstring
accessTokenstring
addressstring[]
addressesiam.Address[]
adfsstring
affiliationstring
alipaystring
amazonstring
applestring
applicationScopesiam.ConsentRecord[]
auth0string
avatarstring
avatarTypestring
azureadstring
azureadb2cstring
baidustring
balancenumber
balanceCreditnumber
balanceCurrencystring
battlenetstring
bilibilistring
biostring
birthdaystring
bitbucketstring
boxstring
cartiam.CartItem[]
cloudfoundrystring
countryCodestring
createdAtstring
createdIpstring
createdTimestring
currencystring
customstring
custom2string
custom3string
custom4string
custom5string
custom6string
147 more fields in the schema

POST /v1/iam/delete-workspace

Deletes a workspace. The people and roles in your organization are unchanged; what goes is the scope itself.

The older spelling of POST /v1/iam/workspaces/delete.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

GET /v1/iam/get-account

Returns the signed-in person's own account and the organization they belong to — what a console reads to draw the account menu.

Passwords, API secrets and MFA material are stripped. It answers for a session cookie or a bearer token alike.

GET /v1/iam/get-app-login

Returns everything a login screen needs to draw itself for one application: its branding, and each sign-in method it offers with the provider details that method needs.

The client secret is masked. Read before anyone has signed in, so it carries only what is safe for a browser to see.

ParameterInTypeRequiredDescription
clientIdquerystringClientId is the application's OAuth client id — the one field that selects which login screen this is.
responseTypequerystringResponseType is the OAuth response type the screen will ask for.

GET /v1/iam/get-application

Reads one record — the older spelling of the single reads on the REST surface, over the same data and the same permissions.

Secrets are stripped. Naming a record in another organization does not reach it, however the request spells it.

GET /v1/iam/get-applications

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-cert

Reads one record — the older spelling of the single reads on the REST surface, over the same data and the same permissions.

Secrets are stripped. Naming a record in another organization does not reach it, however the request spells it.

GET /v1/iam/get-certs

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-global-users

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-invitations

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-memberships

Answers either question about who belongs where: which organizations one person can act in, or who can act in one organization.

Both are org-scoped: a non-SuperAdmin may ask about ITS OWN org's roster, or about a user whose home org is its own, and nothing else. The bound comes from the verified credential via authz.Scope, so a request parameter can never widen it — a membership row names who may act and spend in an org, so a cross-tenant read is a customer roster leak.

ParameterInTypeRequiredDescription
userquerystringUser is "<homeOrg>/<username>" — which organizations that identity may act in.
orgquerystringOrg is an organization — who may act in it.

GET /v1/iam/get-organization-projects

Returns one organization's projects — what a scope switcher lists so somebody can move between them.

You see your own organization and no other, whatever the request asks for.

GET /v1/iam/get-organization-workspaces

Returns one organization's workspaces — what a scope switcher lists so somebody can move between them.

You see your own organization and no other, whatever the request asks for.

GET /v1/iam/get-organization

Reads one record — the older spelling of the single reads on the REST surface, over the same data and the same permissions.

Secrets are stripped. Naming a record in another organization does not reach it, however the request spells it.

GET /v1/iam/get-organizations

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-permission

Reads one record — the older spelling of the single reads on the REST surface, over the same data and the same permissions.

Secrets are stripped. Naming a record in another organization does not reach it, however the request spells it.

GET /v1/iam/get-permissions

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-provider

Reads one record — the older spelling of the single reads on the REST surface, over the same data and the same permissions.

Secrets are stripped. Naming a record in another organization does not reach it, however the request spells it.

GET /v1/iam/get-providers

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-records

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-role

Reads one record — the older spelling of the single reads on the REST surface, over the same data and the same permissions.

Secrets are stripped. Naming a record in another organization does not reach it, however the request spells it.

GET /v1/iam/get-roles

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

GET /v1/iam/get-user

Reads one person, two ways.

Name them and it is an ordinary read, with secrets stripped. Or hand it a SECRET API key and it answers with the person that key belongs to — how a service of yours turns a credential on an incoming request into an identity.

A publishable key resolves to nobody here, deliberately: it is safe to ship in a browser precisely because it names an organization and never a person.

get-user is handler-authorized (authz.handlerAuthorizedExact) because the key variant carries no owner/name for the Guard to authorize; so the owner/name variant reinstates the SAME read authorization the Guard applies, through the ONE policy function (authz.Can) — identical behavior, a cross-tenant or non-self read still refused 403 — then reuses the generic getHandler verbatim for resolution and redaction. No authz and no CRUD is reimplemented.

GET /v1/iam/get-users

Lists one kind of record in your organization — the older spelling of the collection reads on the REST surface, over the same data and the same permissions.

Secrets are stripped from every row. Send both a page number and a page size to page, and the total comes back alongside; send neither and you get the whole set. You see your own organization and no other, whatever the request asks for.

Scoping note (intentional, fail-closed): iam's ownership model is mixed — users/roles/permissions are owned by their tenant org, while organizations/ applications/providers/certs are platform-owned (Owner "admin"). A SuperAdmin (Scope → the requested owner, empty = all) therefore lists every entity, which is the console-admin path. A non-super is pinned by Scope to its own org, so it lists its tenant-owned entities correctly and is refused the platform-owned lists at the Guard (owner "" or "admin" both deny) — a safe 403, never another tenant's rows. Non-super, membership-scoped views of the platform-owned entities (e.g. an org console's own app list keyed on Application.Organization) are a separate, additive surface, not a silent behavior of this generic lister.

POST /v1/iam/invitations/delete

Withdraws an invitation. It stops being redeemable at once; anyone who already joined through it keeps their account.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/invitations/get

Returns one invitation: who it is for, what it grants on acceptance, and when it expires.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/invitations/update

Changes an invitation's terms — the role it grants, how many may redeem it, or when it expires. What it is called does not change.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
applicationstring
codestring
createdTimestring
defaultCodestring
displayNamestring
emailstring
isRegexpboolean
namestring
ownerstring
phonestring
quotainteger
signupGroupstring
statestring
updatedTimestring
usedCountinteger
usernamestring

GET /v1/iam/invitations

Returns your organization's invitations, newest first — who has been asked to join, on what terms, and how many seats each invitation still has left.

You see your own organization's invitations and no one else's; which organization that is comes from your credentials, not from the request.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/invitations

Issues an invitation to join your organization — the code or link a new member redeems, with the role they arrive holding and the date it stops working. A name already used in the organization is refused.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
applicationstring
codestring
createdTimestring
defaultCodestring
displayNamestring
emailstring
isRegexpboolean
namestring
ownerstring
phonestring
quotainteger
signupGroupstring
statestring
updatedTimestring
usedCountinteger
usernamestring

POST /v1/iam/issue-user-token

Mints an access token for the ?id=<owner>/<name> target user (optional ?aud= resource, RFC 8707), issued by the authenticated + allow-listed confidential client. The token's subject + owner are the TARGET USER's, so a resource server scopes on the validated owner claim to the user's tenant — indistinguishable from a token the user obtained directly. Response is the camelCase {accessToken, expiresIn} body identity.ts consumes. Equivalent to the RFC 8693 token-exchange grant, minus the subject_token proof (the console has the user's id, not a token) — the reason this compat shim exists.

POST /v1/iam/keys/delete

Revokes an API key. Anything still presenting it stops being authorized at once, so roll the replacement out before you revoke.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

GET /v1/iam/keys/get

Returns one API key: what it is called, what it may reach, and when it was issued.

ParameterInTypeRequiredDescription
ownerquerystring
namequerystring

POST /v1/iam/keys/mint

(re)generates the target user's key of the requested TYPE and returns it once, over the shared authorizeMinter + mintTarget seam. ?type=secret (the default) yields the confidential sk-; ?type=publishable yields the pk- that is safe to ship in client JS and resolves to an org, never a principal.

It writes the schema.Key row that the resolvers actually read. schema.User.AccessKey is not a credential and nothing resolves it, so a key stamped there would authenticate nobody.

POST /v1/iam/keys/revoke

Clears the target user's key of the requested TYPE (immediate revoke). Scoped by the same ?type field mint takes, so revoking the browser key leaves the server key working. A secret key's stored value is the sk- in its schema.Key row.

POST /v1/iam/keys/update

Changes what a key is called or what it may reach. The credential itself is not reissued — the key in your deployment keeps working.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessKeystringAccessKey (pk-) is the publishable identifier and lookup index; AccessSecret (sk-) is the confidential secret.
accessSecretstring
applicationstring
createdAtstring
createdTimestringCreatedTime and UpdatedTime are RFC3339 audit stamps carried as strings for byte-parity with the v1 row (orm.Model…
deletedboolean
displayNamestringDisplayName is the human-facing label.
expireTimestringExpireTime is when the key stops being honored (empty = never).
idstring
namestring
organizationstring
ownerstringOwner is the tenant that holds the key; Name is unique within Owner.
scopestringScope is the key's ACCESS CLASS, orthogonal to Type (which names the bound principal).
statestring
typestringType is the scope the key is bound to — "Organization", "Application", "User", or "General" — and Organization /…
updatedAtstring
updatedTimestring
userstring

GET /v1/iam/keys

Returns your organization's API keys, newest first — what each is called, what it may reach, and its publishable half. Secret halves are never listed.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/keys

Issues an API key. A standard key comes back as a publishable half you may ship in client code and a secret half you must not — the secret is shown once, at creation, and cannot be retrieved afterwards. A publish-scoped key is issued with the publishable half only, so there is no secret to leak.

A name already used in your organization is refused rather than reissued, so creating twice never silently invalidates a key that is in production.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessKeystringAccessKey (pk-) is the publishable identifier and lookup index; AccessSecret (sk-) is the confidential secret.
accessSecretstring
applicationstring
createdAtstring
createdTimestringCreatedTime and UpdatedTime are RFC3339 audit stamps carried as strings for byte-parity with the v1 row (orm.Model…
deletedboolean
displayNamestringDisplayName is the human-facing label.
expireTimestringExpireTime is when the key stops being honored (empty = never).
idstring
namestring
organizationstring
ownerstringOwner is the tenant that holds the key; Name is unique within Owner.
scopestringScope is the key's ACCESS CLASS, orthogonal to Type (which names the bound principal).
statestring
typestringType is the scope the key is bound to — "Organization", "Application", "User", or "General" — and Organization /…
updatedAtstring
updatedTimestring
userstring

GET /v1/iam/linked-accounts

Returns the sign-in identities linked to the calling person's account — every provider they can currently sign in with. It is what a security page lists next to the option to disconnect one.

POST /v1/iam/login

Signs a person in with the credential they typed, and — when the request is part of an OAuth flow — hands back the one-time code that finishes it. A second factor, if the account has one, is asked for and required here.

The password is compared against a stored one-way hash and is never logged, echoed or stored as typed.

GET /v1/iam/memberships

Answers either question about who belongs where: which organizations one person can act in, or who can act in one organization.

Both are org-scoped: a non-SuperAdmin may ask about ITS OWN org's roster, or about a user whose home org is its own, and nothing else. The bound comes from the verified credential via authz.Scope, so a request parameter can never widen it — a membership row names who may act and spend in an org, so a cross-tenant read is a customer roster leak.

ParameterInTypeRequiredDescription
userquerystringUser is "<homeOrg>/<username>" — which organizations that identity may act in.
orgquerystringOrg is an organization — who may act in it.

POST /v1/iam/memberships

Lets a person or an application act in an organization. It is the grant behind "add someone to the team", and it is safe to repeat — granting a membership that already exists changes nothing. Granting membership IS the org's authority to give, so it takes the same gate a write to that org's own registry row takes: a SuperAdmin, an admin of the org itself, or an org-admin-capable confidential client. One rule, one place (internal/authz).

POST /v1/iam/mfa/disable

Turns off the authenticator app for an account, so sign-in stops asking for a code. People may do this for themselves; doing it for somebody else takes an administrator, which is what makes it the reset path when a phone is lost.

POST /v1/iam/mfa/preferred

Picks which second factor an account is asked for first when it has more than one enrolled.

POST /v1/iam/mfa/setup/enable

Finishes the enrolment: from here the account's sign-ins ask for a code from the authenticator app. Repeating it re-enrols rather than failing.

POST /v1/iam/mfa/setup/initiate

Starts enrolling an authenticator app: it returns a fresh secret, a URL to render as a QR code, and one recovery code to keep somewhere safe.

Nothing is switched on yet. The enrolment counts only once it is confirmed with a code from the app, so abandoning this step leaves the account exactly as it was. Response: {status:"ok", data:{secret, url, recoveryCodes:[code]}}.

POST /v1/iam/mfa/setup/verify

Checks a six-digit code against an enrolment in progress, so somebody can confirm their authenticator app is set up correctly before it starts being required. Clocks a step out either way are accepted. A valid code → {status:"ok"}; an invalid one → 200 {status:"error"} (the casibase convention: clients branch on status, not the HTTP code).

POST /v1/iam/mint-user-keys

(re)generates the target user's key of the requested TYPE and returns it once, over the shared authorizeMinter + mintTarget seam. ?type=secret (the default) yields the confidential sk-; ?type=publishable yields the pk- that is safe to ship in client JS and resolves to an org, never a principal.

It writes the schema.Key row that the resolvers actually read. schema.User.AccessKey is not a credential and nothing resolves it, so a key stamped there would authenticate nobody.

GET /v1/iam/oauth/authorize

Starts a sign-in — the address you send a browser to, and the beginning of every OAuth and OpenID Connect flow.

If the person is ALREADY signed in here, it does not ask them again: it returns them to the application with a one-time code and they never see this page. Otherwise it shows the right way to sign in for the application they are signing in to, or hands off to another identity provider if that is what they pick.

A client can say what it wants with prompt: none means answer without any screen at all — with the code if a session exists, with an error if not, but never with a page; login means ask for the password again even if a session exists; select_account means let the person choose which identity to use.

It returns only to an address the application has registered. That check happens before anything else, so a request naming an unregistered address is refused where the person can see it rather than being bounced onwards.

POST /v1/iam/oauth/authorize

Starts a sign-in — the address you send a browser to, and the beginning of every OAuth and OpenID Connect flow.

If the person is ALREADY signed in here, it does not ask them again: it returns them to the application with a one-time code and they never see this page. Otherwise it shows the right way to sign in for the application they are signing in to, or hands off to another identity provider if that is what they pick.

A client can say what it wants with prompt: none means answer without any screen at all — with the code if a session exists, with an error if not, but never with a page; login means ask for the password again even if a session exists; select_account means let the person choose which identity to use.

It returns only to an address the application has registered. That check happens before anything else, so a request naming an unregistered address is refused where the person can see it rather than being bounced onwards.

GET /v1/iam/oauth/callback

Completes the round-trip: it resolves and burns the single-use transaction (checking expiry + browser binding), exchanges and verifies the IdP response, links or provisions the local user, and mints the iam authorization code the relying party expects — then redirects to the original redirect_uri with code + state.

POST /v1/iam/oauth/device/info

Name the application a pending device code is asking to sign in.

Answers "what am I approving?" for a pending user_code, so the approval page can name the application a human is about to authorize. Both fields come off the pending code's OWN application — never off the portal the browser happens to be on — so the screen cannot name one application while the code belongs to another.

Requires a signed-in session, resolved from the browser's session cookie exactly as the approval itself resolves it. Not signed in is not a refusal to explain: it carries the stable login-required code the approval page branches on to sign the human in first.

POST for a read, deliberately, for the same reason RFC 7662 introspection beside it is POST: the argument is a SECRET. A user_code in a request line is copied into ingress and proxy access logs, which a POST body is not.

Unknown, expired, already used and already approved all get ONE opaque refusal — the same one the approval attempt would get. The user_code carries only 40 bits, so an answer that distinguished those states would be an oracle for hunting live codes; gated and opaque, this reveals strictly less than the approval the same caller could already attempt.

POST /v1/iam/oauth/device

Starts a sign-in on a device with no browser and no keyboard — a TV, a CLI, a headless box. It returns a short code to show the person and the address to send them to on a phone or laptop.

Nothing is granted until a human approves it there; until then the code is just a pending request.

POST /v1/iam/oauth/federation/mfa

Completes a sign-in that came in through another identity provider and still owes a second factor. The person supplies the factor here and the login finishes.

The account is fixed when the challenge is issued, not by the request, so no one can redirect a half-finished login onto somebody else's account. A wrong factor uses the challenge up: retrying means starting the sign-in again, the same as a mistyped password.

POST /v1/iam/oauth/introspect

Answers whether an access token is still good, and what it is good for — the check a resource server of yours makes before honouring a token it did not mint.

A token counts as active only if it verifies AND has not been revoked, so a revoked token reads as dead here immediately rather than until it expires. A token that is unknown, expired or revoked answers simply that it is not active, and nothing more — the endpoint is not a way to learn about tokens you were not given.

GET /v1/iam/oauth/logout

Ends a sign-in and sends the browser somewhere sensible. Accepts GET or POST, so it works as a plain link.

It ACTUALLY signs you out, which is worth stating because the endpoint spent a release not doing it: the whole body computed a redirect and answered {"status":"ok"} unconditionally — no session ended, no token revoked. A logout that reports success while leaving the session live is worse than no logout at all, because the person on the shared machine believes it worked. Three things happen here now, in this order:

  1. The browser session dies — sid revoked server-side AND the cookie expired (sessions.Clear). Server-side revocation is the load-bearing half: a copy of the cookie taken before logout must not still resolve.
  2. The relying party's tokens are revoked when an id_token_hint names it, so the refresh token cannot mint a fresh access token after the human left. Revocation state is authoritative — a JWT's exp still reads valid for days, so expiry is necessary but never sufficient.
  3. Only then is a redirect considered, and only to a REGISTERED uri.

The open-redirect guard is unchanged: a redirect happens only when a VERIFIED id_token_hint identifies the application and that application has registered the target. Anything else refuses to redirect — nobody can turn your logout link into a redirect to a site of their choosing.

POST /v1/iam/oauth/logout

Ends a sign-in and sends the browser somewhere sensible. Accepts GET or POST, so it works as a plain link.

It ACTUALLY signs you out, which is worth stating because the endpoint spent a release not doing it: the whole body computed a redirect and answered {"status":"ok"} unconditionally — no session ended, no token revoked. A logout that reports success while leaving the session live is worse than no logout at all, because the person on the shared machine believes it worked. Three things happen here now, in this order:

  1. The browser session dies — sid revoked server-side AND the cookie expired (sessions.Clear). Server-side revocation is the load-bearing half: a copy of the cookie taken before logout must not still resolve.
  2. The relying party's tokens are revoked when an id_token_hint names it, so the refresh token cannot mint a fresh access token after the human left. Revocation state is authoritative — a JWT's exp still reads valid for days, so expiry is necessary but never sufficient.
  3. Only then is a redirect considered, and only to a REGISTERED uri.

The open-redirect guard is unchanged: a redirect happens only when a VERIFIED id_token_hint identifies the application and that application has registered the target. Anything else refuses to redirect — nobody can turn your logout link into a redirect to a site of their choosing.

POST /v1/iam/oauth/revoke

Retires a token before it expires — what you call when someone signs out or a credential may have leaked.

Revoking an access token kills that token. Revoking a REFRESH token kills the whole chain it belongs to, so no further access tokens can be minted from it and every token already minted from it dies with it.

A token that is not yours, or that never existed, answers success and does nothing — so the endpoint cannot be used to discover which tokens are real.

PUBLIC clients revoke too, and must: sign-out is the only control a long-lived refresh token has. hanzo-cli is a public PKCE client holding a 30-day rotating refresh token, so a confidential-only revocation endpoint made hanzo auth logout a LOCAL DELETE — the credential it dropped stayed spendable at hanzo.id for the rest of the month, with nothing able to kill it. Measured 2026-08-01: revoke answered 401 invalid_client and the refresh token went on minting access tokens.

Widening authentication does not widen authority. The caller must still POSSESS the token — and possession already permits USE, of which revocation is the strict opposite — and the row must belong to the client that presents it, so a public client_id buys the ability to destroy exactly what its holder could otherwise spend. RFC 6749 §3.2.1 is the same reading: a client with no credentials identifies itself with client_id.

POST /v1/iam/oauth/token

Exchanges what your application is holding for the tokens it needs — the one-time code from a finished sign-in, a refresh token, or your own client credentials when the caller is a program rather than a person.

A refresh returns a NEW refresh token and retires the one you sent. If a retired one is ever presented again the whole chain is revoked, on the assumption that a token which came back from the dead was copied — so a stolen refresh token buys an attacker one use and costs them the session.

Responses are never cached, by any hop.

GET /v1/iam/oauth/userinfo

Returns the profile claims for whoever the access token belongs to — the standard OpenID Connect way to find out who is calling you without your application storing anything itself.

The token must still be live: revoke it and this stops answering.

POST /v1/iam/oauth/userinfo

Returns the profile claims for whoever the access token belongs to — the standard OpenID Connect way to find out who is calling you without your application storing anything itself.

The token must still be live: revoke it and this stops answering.

POST /v1/iam/onboard

Finishes setting up the account of whoever is calling — it creates their organization if they have none and puts them in it, so a person who has just signed up lands somewhere they can work.

It always acts on the caller and never on somebody named in the request, so there is no way to onboard another person's account through it.

POST /v1/iam/organizations/delete

Removes an organization and everything named inside it. There is no undo, and every session issued under it stops working.

The built-in admin organization cannot be deleted — losing it would leave the account with no way back in.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

GET /v1/iam/organizations/get

Returns one organization: its display, its defaults and the sign-in rules everyone in it inherits.

ParameterInTypeRequiredDescription
ownerquerystring
namequerystring

POST /v1/iam/organizations/update

Changes an organization's display, its defaults and the sign-in rules everyone in it inherits. Which organization it is does not change, and neither does when it was created.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accountItemsiam.AccountItem[]
accountMenustring
balanceCreditnumber
balanceCurrencystring
countryCodesstring[]
createdAtstring
createdTimestring
dcrPolicystring
defaultApplicationstring
defaultAvatarstring
defaultPasswordstring
deletedboolean
disableSigninboolean
displayNamestring
enableSoftDeletionboolean
enableTourboolean
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
founderstring
hasPrivilegeConsentboolean
idstring
initScoreinteger
ipRestrictionstring
ipWhiteliststring
isPersonalboolean
isProfilePublicboolean
kerberosKdcHoststring
kerberosKeytabstring
kerberosRealmstring
kerberosServiceNamestring
languagesstring[]
ldapAttributesstring[]
logostring
logoDarkstring
masterPasswordstring
masterVerificationCodestring
mfaItemsiam.MfaItem[]
mfaRememberInHoursinteger
namestring
19 more fields in the schema

GET /v1/iam/organizations

Returns the organizations you can see, newest first. Narrow it to one parent account, and set a limit and offset to page through the rest.

ParameterInTypeRequiredDescription
ownerquerystring
limitqueryinteger
offsetqueryinteger

POST /v1/iam/organizations

Makes a new organization — the account your users, applications, roles, projects and workspaces are all named inside. It is the first write in a new tenant, and a name already in use is refused rather than taken over.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accountItemsiam.AccountItem[]
accountMenustring
balanceCreditnumber
balanceCurrencystring
countryCodesstring[]
createdAtstring
createdTimestring
dcrPolicystring
defaultApplicationstring
defaultAvatarstring
defaultPasswordstring
deletedboolean
disableSigninboolean
displayNamestring
enableSoftDeletionboolean
enableTourboolean
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
founderstring
hasPrivilegeConsentboolean
idstring
initScoreinteger
ipRestrictionstring
ipWhiteliststring
isPersonalboolean
isProfilePublicboolean
kerberosKdcHoststring
kerberosKeytabstring
kerberosRealmstring
kerberosServiceNamestring
languagesstring[]
ldapAttributesstring[]
logostring
logoDarkstring
masterPasswordstring
masterVerificationCodestring
mfaItemsiam.MfaItem[]
mfaRememberInHoursinteger
namestring
19 more fields in the schema

POST /v1/iam/permissions/delete

Revokes a permission. Everyone who held access only through it loses that access immediately; grants they hold by another route are untouched.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

GET /v1/iam/permissions/get

Returns one permission: who it grants to, what it allows, and the resources it covers.

ParameterInTypeRequiredDescription
ownerquerystring
namequerystring

POST /v1/iam/permissions/update

Changes who a permission grants to, what it allows, or the resources it covers. Access changes as soon as the write lands. What the permission is called does not change, and neither does when it was created.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
actionsstring[]
adapterstring
approveTimestring
approverstring
createdAtstring
createdTimestringDescriptive metadata.
deletedboolean
descriptionstring
displayNamestring
domainsstring[]
effectstring
groupsstring[]
idstring
isEnabledboolean
modelstringAuthorization model, targets, and decision.
namestring
ownerstringIdentity — the (owner, name) natural key.
resourceTypestring
resourcesstring[]
rolesstring[]
statestring
submitterstringSubmission / approval workflow.
updatedAtstring
usersstring[]Subjects the grant is evaluated for.

GET /v1/iam/permissions

Returns the permissions in one organization, newest first — each one a grant saying which people or roles may do what, and to which resources.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/permissions

Grants a permission — the call that gives a person or a role the ability to do something. Adding refuses to overwrite a grant that already exists, so widening an existing one is an update, never an accident.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
actionsstring[]
adapterstring
approveTimestring
approverstring
createdAtstring
createdTimestringDescriptive metadata.
deletedboolean
descriptionstring
displayNamestring
domainsstring[]
effectstring
groupsstring[]
idstring
isEnabledboolean
modelstringAuthorization model, targets, and decision.
namestring
ownerstringIdentity — the (owner, name) natural key.
resourceTypestring
resourcesstring[]
rolesstring[]
statestring
submitterstringSubmission / approval workflow.
updatedAtstring
usersstring[]Subjects the grant is evaluated for.

POST /v1/iam/preferences

Saves the calling person's own settings and returns the full set afterwards. Send only the settings you are changing — the rest are kept, so two screens can save at once without one undoing the other.

POST /v1/iam/projects/delete

Removes a project. The people and roles in your organization are unchanged; what goes is the scope itself, so move anything addressed by it first.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/projects/get

Returns one project: what it is called and how it is set up.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/projects/update

Changes a project's settings. What it is called does not change, and neither does when it was created.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
createdTimestring
descriptionstring
displayNamestring
isDefaultboolean
metadatastring
namestring
organizationstring
ownerstring
tagsstring[]
workspacestring

GET /v1/iam/projects

Returns your organization's projects, newest first — the scope people pick between when their work is separated by product or client rather than by team.

You see your own organization's projects and no one else's; which organization that is comes from your credentials, not from the request.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/projects

Makes a project inside your organization — the scope people pick between when their work is separated by product or client rather than by team. A name already used in the organization is refused.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
createdTimestring
descriptionstring
displayNamestring
isDefaultboolean
metadatastring
namestring
organizationstring
ownerstring
tagsstring[]
workspacestring

POST /v1/iam/providers/delete

Removes a provider. Sign-in through it stops for every application that used it, so give those applications another method first.

A provider that is already gone answers "nothing changed" rather than an error, so the call is safe to repeat.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

POST /v1/iam/providers/get

Returns one provider: what it connects to and how it is configured. Its credentials come back masked.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

POST /v1/iam/providers/update

Changes a provider's settings or rotates the credentials it holds. The change takes effect on the next sign-in through it — sessions already issued are unaffected.

A provider that is not there answers "nothing changed" rather than an error, so the call is safe to repeat.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
appIdstring
bucketstring
categorystring
certstring
clientIdstring
clientId2string
clientSecretstring
clientSecret2string
contentstring
createdAtstring
createdTimestring
customAuthUrlstring
customLogostring
customTokenUrlstring
customUserInfoUrlstring
deletedboolean
disableSslboolean
displayNamestring
domainstring
emailRegexstring
enablePkceboolean
enableProxyboolean
enableSignAuthnRequestboolean
endpointstring
hoststring
httpHeadersobject
idstring
idPstring
intranetEndpointstring
issuerUrlstring
metadatastring
methodstring
namestring
ownerstring
pathPrefixstring
portinteger
providerUrlstring
receiverstring
regionIdstring
scopesstring
8 more fields in the schema

GET /v1/iam/providers

Returns your organization's providers, newest first — the identity providers your people sign in with, and the senders and connectors your applications go through.

You see your own organization's providers and no one else's; which organization that is comes from your credentials, not from the request.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/providers

Adds an identity provider your people can sign in with, or a service your applications send through — a social or enterprise login, an email or SMS sender, a storage or payment connector.

A provider is configured once and then switched on per application, so several applications can share one set of credentials.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
appIdstring
bucketstring
categorystring
certstring
clientIdstring
clientId2string
clientSecretstring
clientSecret2string
contentstring
createdAtstring
createdTimestring
customAuthUrlstring
customLogostring
customTokenUrlstring
customUserInfoUrlstring
deletedboolean
disableSslboolean
displayNamestring
domainstring
emailRegexstring
enablePkceboolean
enableProxyboolean
enableSignAuthnRequestboolean
endpointstring
hoststring
httpHeadersobject
idstring
idPstring
intranetEndpointstring
issuerUrlstring
metadatastring
methodstring
namestring
ownerstring
pathPrefixstring
portinteger
providerUrlstring
receiverstring
regionIdstring
scopesstring
8 more fields in the schema

GET /v1/iam/registry/jwks

Publishes the public key your registry uses to verify the tokens issued above — the one URL to configure so the registry trusts logins without holding any secret of its own.

If no signing key is available it refuses rather than publishing an empty set, because a registry that trusts nothing looks identical to one that trusts everything until somebody tries to push.

GET /v1/iam/registry/token

Signs a container client in to your registry. docker login, and every build tool that pushes or pulls images, lands here: it exchanges the credential for a short-lived token scoped to exactly the repositories that credential may touch.

Both of the shapes container tooling uses are accepted, so the same login works whichever client your pipeline runs.

POST /v1/iam/registry/token

Signs a container client in to your registry. docker login, and every build tool that pushes or pulls images, lands here: it exchanges the credential for a short-lived token scoped to exactly the repositories that credential may touch.

Both of the shapes container tooling uses are accepted, so the same login works whichever client your pipeline runs.

GET /v1/iam/resolve-key

Answers which organization a PUBLISHABLE key belongs to — what a service of yours calls to attribute a request that arrived carrying a key shipped in a browser.

It names an organization and never a person: no path through it can load or return a user, so a key you put in client code cannot become a way to learn who anyone is. A key that is expired, secret rather than publishable, or simply unknown all answer with the same sentence, and with a code saying which of those it was. Only a confidential service that already proved it may resolve keys at all ever reads that code — there is no anonymous caller here to probe for which keys exist — and telling it apart is what lets the holder be told to re-mint an expired key instead of hunting a configuration error.

POST /v1/iam/revoke-user-keys

Clears the target user's key of the requested TYPE (immediate revoke). Scoped by the same ?type field mint takes, so revoking the browser key leaves the server key working. A secret key's stored value is the sk- in its schema.Key row.

POST /v1/iam/roles/delete

Removes a role. Everyone in it loses the access it carried; their accounts, and any other role they hold, are untouched.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/roles/get

Returns one role: who is in it, and the roles it includes.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/roles/update

Changes who is in a role, or which roles it includes. Access changes for everyone in it as soon as the write lands. What the role is called does not change, and neither does when it was created.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
createdTimestring
descriptionstring
displayNamestring
domainsstring[]
groupsstring[]
isEnabledboolean
namestring
ownerstring
rolesstring[]
usersstring[]

GET /v1/iam/roles

Returns your organization's roles, newest first — each a named group of people that permissions are granted to.

You see your own organization's roles and no one else's; which organization that is comes from your credentials, not from the request.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/roles

Makes a role — a named group of people that permissions are granted to. Granting to a role rather than to each person is what keeps access correct as your team changes: add someone to the role and they inherit everything it can do. A name already used in your organization is refused.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
createdTimestring
descriptionstring
displayNamestring
domainsstring[]
groupsstring[]
isEnabledboolean
namestring
ownerstring
rolesstring[]
usersstring[]

GET /v1/iam/scim/v2/ResourceTypes/{name}

Returns one provisionable record kind in full.

ParameterInTypeRequiredDescription
namepathstringyes

GET /v1/iam/scim/v2/ResourceTypes

Returns the kinds of record this directory provisions and the address of each, so your identity provider discovers them rather than having them configured by hand.

GET /v1/iam/scim/v2/Schemas/{id}

Returns one attribute definition in full.

ParameterInTypeRequiredDescription
idpathstringyes

GET /v1/iam/scim/v2/Schemas

Returns the attribute definitions this directory understands, so your identity provider knows which fields it may send and what they mean before it sends any.

GET /v1/iam/scim/v2/ServiceProviderConfig

Tells your identity provider which parts of SCIM this directory supports, so it configures itself instead of you filling in a form.

Filtering and partial updates are supported. Bulk operations, sorting and entity tags are not — an IdP that reads this will not attempt them.

GET /v1/iam/scim/v2/Users/{owner}/{name}

Returns one person in the standard SCIM shape. An administrator may read anyone in the organization; everyone else may read only themselves.

ParameterInTypeRequiredDescription
ownerpathstringyes
namepathstringyes

PUT /v1/iam/scim/v2/Users/{owner}/{name}

Overwrites a person's SCIM attributes with what your identity provider sends — how a change made there lands here.

Only the attributes SCIM describes are replaced. Anything the standard does not cover — their multi-factor enrolment above all — survives untouched, so a routine sync from your IdP can never quietly strip someone's second factor or bring a deleted account back.

ParameterInTypeRequiredDescription
ownerpathstringyes
namepathstringyes

PATCH /v1/iam/scim/v2/Users/{owner}/{name}

Applies a partial change from your identity provider — one attribute moved, not the whole record resent.

The change is applied onto the person as they currently are, so everything you did not mention keeps its value, including the parts SCIM does not describe.

ParameterInTypeRequiredDescription
ownerpathstringyes
namepathstringyes

DELETE /v1/iam/scim/v2/Users/{owner}/{name}

Deprovisions a person — how removing someone in your identity provider removes their access here. Their sessions stop working immediately. Takes an administrator.

ParameterInTypeRequiredDescription
ownerpathstringyes
namepathstringyes

GET /v1/iam/scim/v2/Users

Returns the people in your organization to your identity provider, in the standard SCIM shape, so an IdP can reconcile its directory against ours. Searchable by username or email address, and paged.

Reading the whole list takes an administrator; an ordinary person is refused.

POST /v1/iam/scim/v2/Users

Provisions a person from your identity provider — how a new hire gets an account here automatically when they are added over there.

Takes an administrator. Making someone an administrator takes more than that, so an IdP integration cannot escalate anyone by setting a flag.

POST /v1/iam/send-verification-code

Validates the request, mints + persists an OTP, and reports success. The request fields are read via fiber's FormValue — the escape hatch zip exposes for form bodies (multipart or urlencoded) — since the typed JSON Bind does not apply here. v1 also accepts countryCode/method/ checkUser/captchaType; iam ignores them (the captcha/forget/MFA flows those drive are not ported), and CAPTCHA verification is likewise not enforced — iam models no captcha provider — so the code is issued once the destination and application validate.

POST /v1/iam/service-accounts/{name}/keys

Serves POST /v1/iam/service-accounts/:name/keys: mint a fresh key, invalidating the prior one, and return the new raw secret exactly once.

ParameterInTypeRequiredDescription
namepathstringyes

DELETE /v1/iam/service-accounts/{name}

Serves DELETE /v1/iam/service-accounts/:name.

ParameterInTypeRequiredDescription
namepathstringyes

GET /v1/iam/service-accounts

Returns your organization's service accounts — what each is called and when it was created. Never their secrets: a key's secret half exists in a response exactly once, when it is minted. Paginated in memory over the already org-scoped slice — the set per org is small, so a dedicated count query is overkill (v1 service_account.go:296-307).

ParameterInTypeRequiredDescription
organizationquerystringOrganization is the organization whose service accounts to list.
pqueryintegerP is the 1-indexed page to return. Paging takes both p and pageSize — leave either out, or send something that is not a…
pageSizequeryintegerSize is how many accounts a page holds.

POST /v1/iam/service-accounts

Makes a service account — an identity for a program rather than a person, for a script, a bot or a deployment that has to authenticate on its own.

It comes back with its first key, and the secret half is shown ONCE, here. There is no way to read it again; if you lose it, rotate.

POST /v1/iam/sessions/create

Records a sign-in. Signing in again from another browser adds to the session rather than replacing it, so one person can be signed in from a laptop and a phone at once.

Ask for an exclusive sign-in and the opposite holds: the new sign-in is the only one left and every other browser is signed out. That is the setting to use when one person may hold only one live session at a time.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
applicationstringyes
exclusiveSigninboolean
namestringyes
ownerstringyes
sessionIdstring[]

POST /v1/iam/sessions/delete

Signs a person out of one application — the session ends and every browser carrying it stops being authenticated.

A session that is already gone reports that nothing was deleted rather than an error, so the call is safe to repeat.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
applicationstringyes
namestringyes
ownerstringyes

POST /v1/iam/sessions/get

Returns one person's session in one application — when it began and which browsers or devices are still carrying it.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
applicationstringyes
namestringyes
ownerstringyes

POST /v1/iam/sessions/list

Returns who is currently signed in to your organization, newest first, and can be narrowed to one person or one application. It is what you read before signing someone out.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
applicationstring
namestring
ownerstringyes

POST /v1/iam/sessions/update

Replaces the set of browsers a session covers — signing out the ones you leave off while the session itself stays live. A session that does not exist is reported as missing rather than created.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
applicationstringyes
namestringyes
ownerstringyes
sessionIdstring[]

POST /v1/iam/set-preferred-mfa

Picks which second factor an account is asked for first when it has more than one enrolled.

POST /v1/iam/signin

Completes a sign-in: it exchanges the one-time code your application was handed at the end of the login flow for a live session, and returns the signed-in account.

The code works once. This is the call that turns a finished login into something your application can act on.

POST /v1/iam/signup

Creates an account from the sign-up form and applies the application's own sign-up rules — whether self-service registration is open at all, and which fields it requires.

The password is hashed before it is stored and is never returned.

POST /v1/iam/tokens/delete

Revokes an access token. Whatever was using it stops being authorized at once.

A token that is already gone answers "nothing changed" rather than an error, so the call is safe to repeat.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

POST /v1/iam/tokens/get

Returns one access token: who and what it was issued to, and when it expires.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

POST /v1/iam/tokens/issue

Mints an access token for the ?id=<owner>/<name> target user (optional ?aud= resource, RFC 8707), issued by the authenticated + allow-listed confidential client. The token's subject + owner are the TARGET USER's, so a resource server scopes on the validated owner claim to the user's tenant — indistinguishable from a token the user obtained directly. Response is the camelCase {accessToken, expiresIn} body identity.ts consumes. Equivalent to the RFC 8693 token-exchange grant, minus the subject_token proof (the console has the user's id, not a token) — the reason this compat shim exists.

POST /v1/iam/tokens/update

Changes an access token's scope or expiry.

A token that is not there answers "nothing changed" rather than an error, so the call is safe to repeat.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessTokenstring
accessTokenHashstring
applicationstring
codestring
codeChallengestring
codeChallengeMethodstring
codeExpireIninteger
codeIsUsedboolean
createdAtstring
createdTimestring
deletedboolean
expiresIninteger
idstring
namestring
noncestringNonce is the OIDC authorize nonce, stored on the code and echoed into the id_token minted at the exchange (OIDC Core…
organizationstring
ownerstring
publicGrantbooleanPublicGrant records that this grant was established WITHOUT client authentication — a PKCE code exchange from a client…
redirectUristringRedirectUri binds the authorization code to the exact redirect URI of the authorize request (RFC 6749 §4.1.3): the…
refreshConsumedboolean
refreshExpireIninteger
refreshFamilystringRefresh-token rotation state (v2). Each refresh belongs to a family (the grant); rotation mints a new row in the same…
refreshTokenstring
refreshTokenHashstring
resourcestringRFC 8707 resource indicator
scopestring
tokenTypestring
updatedAtstring
userstring
userCodestring

GET /v1/iam/tokens

Returns the access tokens issued in your organization, newest first, and can be narrowed to one organization. Use it to see what is currently authorized before revoking anything.

ParameterInTypeRequiredDescription
ownerquerystring
organizationquerystring

POST /v1/iam/tokens

Records an access token — the credential an application or integration presents on a caller's behalf.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessTokenstring
accessTokenHashstring
applicationstring
codestring
codeChallengestring
codeChallengeMethodstring
codeExpireIninteger
codeIsUsedboolean
createdAtstring
createdTimestring
deletedboolean
expiresIninteger
idstring
namestring
noncestringNonce is the OIDC authorize nonce, stored on the code and echoed into the id_token minted at the exchange (OIDC Core…
organizationstring
ownerstring
publicGrantbooleanPublicGrant records that this grant was established WITHOUT client authentication — a PKCE code exchange from a client…
redirectUristringRedirectUri binds the authorization code to the exact redirect URI of the authorize request (RFC 6749 §4.1.3): the…
refreshConsumedboolean
refreshExpireIninteger
refreshFamilystringRefresh-token rotation state (v2). Each refresh belongs to a family (the grant); rotation mints a new row in the same…
refreshTokenstring
refreshTokenHashstring
resourcestringRFC 8707 resource indicator
scopestring
tokenTypestring
updatedAtstring
userstring
userCodestring

POST /v1/iam/unlink

Disconnects one sign-in identity from an account, so that provider can no longer be used to sign in as that person. Their account and every other way they sign in are untouched. Two principals may do it, and only two: the account holder itself, and a SuperAdmin (a member of the reserved admin org, the one predicate). An ORG ADMIN deliberately may NOT — unlinking is not tenant administration, it is unpicking someone's own sign-in method, so the generic org-admin rule is the wrong answer here.

A holder unlinking itself must also be permitted by the application — the provider link's CanUnlink flag — so an organization that mandates federated sign-in cannot have its users strand themselves. A SuperAdmin is not bound by that flag; it is the platform's own recovery path. Fail-closed throughout.

POST /v1/iam/update-application

Updates one of your applications — its display, its sign-in methods and the redirect URIs it is allowed to return to. Which organization and name the application has are fixed when it is created and are not editable here.

A redirect URI you add becomes an allowed sign-in origin, so this is the call that makes login work from a new host.

The older spelling of PUT /v1/iam/application.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
affiliationUrlstring
categorystring
certstring
certObjiam.Cert
certPublicKeystring
clientCertstring
clientIdstringClientId is the OAuth2/OIDC client identifier and the GLOBAL key every confidential-client resolver authenticates…
clientSecretstring
codeResendTimeoutinteger
cookieExpireInHoursinteger
createdAtstring
createdTimestring
customScopesiam.ScopeDescription[]
defaultGroupstring
deletedboolean
descriptionstring
disableSamlAttributesboolean
disableSigninboolean
displayNamestring
domainstring
enableAutoSigninboolean
enableCodeSigninboolean
enableExclusiveSigninboolean
enableLinkWithEmailboolean
enablePasswordboolean
enableSamlAssertionSignatureboolean
enableSamlC14n10boolean
enableSamlCompressboolean
enableSamlPostBindingboolean
enableSignUpboolean
enableSigninSessionboolean
enableWebAuthnboolean
environmentstring
expireInHoursnumber
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
footerHtmlstring
forcedRedirectOriginstring
forgetUrlstring
50 more fields in the schema

POST /v1/iam/update-organization

Updates your organization — its display, its default settings and the sign-in rules everyone in it inherits.

The older spelling of POST /v1/iam/organizations/update.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accountItemsiam.AccountItem[]
accountMenustring
balanceCreditnumber
balanceCurrencystring
countryCodesstring[]
createdAtstring
createdTimestring
dcrPolicystring
defaultApplicationstring
defaultAvatarstring
defaultPasswordstring
deletedboolean
disableSigninboolean
displayNamestring
enableSoftDeletionboolean
enableTourboolean
failedSigninFrozenTimeinteger
failedSigninLimitinteger
faviconstring
founderstring
hasPrivilegeConsentboolean
idstring
initScoreinteger
ipRestrictionstring
ipWhiteliststring
isPersonalboolean
isProfilePublicboolean
kerberosKdcHoststring
kerberosKeytabstring
kerberosRealmstring
kerberosServiceNamestring
languagesstring[]
ldapAttributesstring[]
logostring
logoDarkstring
masterPasswordstring
masterVerificationCodestring
mfaItemsiam.MfaItem[]
mfaRememberInHoursinteger
namestring
19 more fields in the schema

POST /v1/iam/update-preferences

Saves the calling person's own settings and returns the full set afterwards. Send only the settings you are changing — the rest are kept, so two screens can save at once without one undoing the other.

POST /v1/iam/update-provider

Updates a provider's settings or rotates the credentials it holds. The change takes effect on the next sign-in through it — sessions already issued are unaffected.

The older spelling of POST /v1/iam/providers/update.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
appIdstring
bucketstring
categorystring
certstring
clientIdstring
clientId2string
clientSecretstring
clientSecret2string
contentstring
createdAtstring
createdTimestring
customAuthUrlstring
customLogostring
customTokenUrlstring
customUserInfoUrlstring
deletedboolean
disableSslboolean
displayNamestring
domainstring
emailRegexstring
enablePkceboolean
enableProxyboolean
enableSignAuthnRequestboolean
endpointstring
hoststring
httpHeadersobject
idstring
idPstring
intranetEndpointstring
issuerUrlstring
metadatastring
methodstring
namestring
ownerstring
pathPrefixstring
portinteger
providerUrlstring
receiverstring
regionIdstring
scopesstring
8 more fields in the schema

POST /v1/iam/update-role

Updates a role's members or the roles it includes. Access changes for everyone in it as soon as the write lands.

The older spelling of POST /v1/iam/roles/update.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
createdTimestring
descriptionstring
displayNamestring
domainsstring[]
groupsstring[]
isEnabledboolean
namestring
ownerstring
rolesstring[]
usersstring[]

POST /v1/iam/update-user

Updates one of your users' profile, roles or credentials. Send a password to reset it; leave it out and the current one stands.

The older spelling of POST /v1/iam/users/update, with the user's fields at the top level rather than wrapped in {user, password}.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
accessKeystring
accessSecretstring
accessSecretHashstring
accessTokenstring
addressstring[]
addressesiam.Address[]
adfsstring
affiliationstring
alipaystring
amazonstring
applestring
applicationScopesiam.ConsentRecord[]
auth0string
avatarstring
avatarTypestring
azureadstring
azureadb2cstring
baidustring
balancenumber
balanceCreditnumber
balanceCurrencystring
battlenetstring
bilibilistring
biostring
birthdaystring
bitbucketstring
boxstring
cartiam.CartItem[]
cloudfoundrystring
countryCodestring
createdAtstring
createdIpstring
createdTimestring
currencystring
customstring
custom2string
custom3string
custom4string
custom5string
custom6string
147 more fields in the schema

POST /v1/iam/users/delete

Removes a person from your organization. Their sessions stop working immediately and the account is gone rather than suspended — to keep the record and only stop sign-in, update the user instead.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

GET /v1/iam/users/get

Returns one person in your organization, by the organization they belong to and their username. Passwords, API secrets and MFA material are stripped from the response.

ParameterInTypeRequiredDescription
ownerquerystringyes
namequerystringyes

POST /v1/iam/users/update

Changes a person's profile, their roles, or the credentials they sign in with. Send a password to reset it; leave it out and their current one keeps working.

Who they are does not change: their organization, username and the identifier their existing sessions are keyed on all survive the write, so an update never signs anyone out.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
passwordstring
useriam.User

GET /v1/iam/users

Returns a page of the people in your organization, with the total so you can page through the rest. Passwords, API secrets and MFA material are stripped from every entry.

ParameterInTypeRequiredDescription
ownerquerystringyes
limitqueryinteger
offsetqueryinteger

POST /v1/iam/users

Adds a person to your organization. Send a password and it becomes the one they sign in with; it is hashed before it is stored and never comes back in any response.

The username is checked against the same rule every account in the Hanzo Cloud is held to, whichever way it was created — this call, password signup, a social sign-in, or SCIM — so a name accepted here works everywhere.

A name already taken in your organization is refused rather than overwritten.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
passwordstring
useriam.User

POST /v1/iam/verification-codes

Validates the request, mints + persists an OTP, and reports success. The request fields are read via fiber's FormValue — the escape hatch zip exposes for form bodies (multipart or urlencoded) — since the typed JSON Bind does not apply here. v1 also accepts countryCode/method/ checkUser/captchaType; iam ignores them (the captcha/forget/MFA flows those drive are not ported), and CAPTCHA verification is likewise not enforced — iam models no captcha provider — so the code is issued once the destination and application validate.

GET /v1/iam/web3/nonce

Starts a wallet sign-in: it returns a one-time challenge for the wallet to sign. The challenge is good once and is tied to the site that asked for it, so a signature collected elsewhere cannot be replayed here.

POST /v1/iam/web3/verify

Completes a wallet sign-in: it verifies the signed challenge and, if it holds, signs the wallet's owner in.

This IS the login — it answers exactly as a password sign-in does, so the rest of your flow does not branch on how somebody arrived.

POST /v1/iam/webauthn-credentials/delete

Removes a passkey or security key — what you call when a device is lost. Make sure the person has another way to sign in first.

A credential that is already gone answers "nothing changed" rather than an error, so the call is safe to repeat.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

POST /v1/iam/webauthn-credentials/get

Returns one passkey or security key: whose it is, what device it lives on, and when it was registered.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestringyes
ownerstringyes

POST /v1/iam/webauthn-credentials/update

Renames a registered passkey or security key, so a person can tell their devices apart.

A credential that is not there answers "nothing changed" rather than an error, so the call is safe to repeat.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
aaguidstring
attachmentstring
attestationTypestring
backupEligibleboolean
backupStateboolean
cloneWarningboolean
createdAtstring
createdTimestring
credentialIdstring
deletedboolean
idstring
namestring
ownerstring
publicKeystring
signCountinteger
transportstring[]
updatedAtstring
userstring
userPresentboolean
userVerifiedboolean

GET /v1/iam/webauthn-credentials

Returns the passkeys and security keys registered in your organization, newest first — which device each belongs to and when it was last used.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/webauthn-credentials

Registers a passkey or security key for a person, so they can sign in with their device instead of a password.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
aaguidstring
attachmentstring
attestationTypestring
backupEligibleboolean
backupStateboolean
cloneWarningboolean
createdAtstring
createdTimestring
credentialIdstring
deletedboolean
idstring
namestring
ownerstring
publicKeystring
signCountinteger
transportstring[]
updatedAtstring
userstring
userPresentboolean
userVerifiedboolean

GET /v1/iam/whoami

Tells you who the current caller is — the lightweight check a page makes on load to decide whether to render signed-in or signed-out.

It answers for a session cookie or a bearer token alike, and says plainly when nobody is signed in rather than failing.

POST /v1/iam/workspaces/delete

Removes a workspace. The people and roles in your organization are unchanged; what goes is the scope itself.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/workspaces/get

Returns one workspace: what it is called and how it is set up.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
namestring
ownerstring

POST /v1/iam/workspaces/update

Changes a workspace's settings. What it is called does not change, and neither does when it was created.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
bucketstring
createdTimestring
descriptionstring
displayNamestring
isDefaultboolean
metadatastring
namestring
organizationstring
ownerstring
tagsstring[]

GET /v1/iam/workspaces

Returns your organization's workspaces, newest first — the scope a team works in, alongside projects rather than instead of them.

You see your own organization's workspaces and no one else's; which organization that is comes from your credentials, not from the request.

ParameterInTypeRequiredDescription
ownerquerystring

POST /v1/iam/workspaces

Makes a workspace inside your organization — the scope a team works in, alongside projects rather than instead of them. A name already used in the organization is refused.

Request bodyapplication/json (required)

FieldTypeRequiredDescription
bucketstring
createdTimestring
descriptionstring
displayNamestring
isDefaultboolean
metadatastring
namestring
organizationstring
ownerstring
tagsstring[]

Iam guide · All Hanzo APIs · Interactive reference

How is this guide?

On this page

iamGET /v1/iam/.well-known/jwksGET /v1/iam/.well-known/oauth-authorization-serverGET /v1/iam/.well-known/openid-configurationGET /v1/iam/accountPOST /v1/iam/add-applicationPOST /v1/iam/add-membershipPOST /v1/iam/add-organizationPOST /v1/iam/add-projectPOST /v1/iam/add-providerPOST /v1/iam/add-rolePOST /v1/iam/add-userPOST /v1/iam/add-workspacePOST /v1/iam/admin/applications/upsertPOST /v1/iam/admin/provisionPOST /v1/iam/admin/users/upsertGET /v1/iam/applicationPOST /v1/iam/applicationPUT /v1/iam/applicationDELETE /v1/iam/applicationPOST /v1/iam/applications/deleteGET /v1/iam/applications/getPOST /v1/iam/applications/updateGET /v1/iam/applicationsPOST /v1/iam/applicationsPOST /v1/iam/audit-logs/deletePOST /v1/iam/audit-logs/getPOST /v1/iam/audit-logs/updateGET /v1/iam/audit-logsPOST /v1/iam/audit-logsGET /v1/iam/auth/applicationGET /v1/iam/auth/methodsPOST /v1/iam/certs/deletePOST /v1/iam/certs/getPOST /v1/iam/certs/updateGET /v1/iam/certsPOST /v1/iam/certsGET /v1/iam/consentPUT /v1/iam/consentPOST /v1/iam/delete-applicationPOST /v1/iam/delete-membershipPOST /v1/iam/delete-mfaPOST /v1/iam/delete-organizationPOST /v1/iam/delete-projectPOST /v1/iam/delete-providerPOST /v1/iam/delete-rolePOST /v1/iam/delete-userPOST /v1/iam/delete-workspaceGET /v1/iam/get-accountGET /v1/iam/get-app-loginGET /v1/iam/get-applicationGET /v1/iam/get-applicationsGET /v1/iam/get-certGET /v1/iam/get-certsGET /v1/iam/get-global-usersGET /v1/iam/get-invitationsGET /v1/iam/get-membershipsGET /v1/iam/get-organization-projectsGET /v1/iam/get-organization-workspacesGET /v1/iam/get-organizationGET /v1/iam/get-organizationsGET /v1/iam/get-permissionGET /v1/iam/get-permissionsGET /v1/iam/get-providerGET /v1/iam/get-providersGET /v1/iam/get-recordsGET /v1/iam/get-roleGET /v1/iam/get-rolesGET /v1/iam/get-userGET /v1/iam/get-usersPOST /v1/iam/invitations/deletePOST /v1/iam/invitations/getPOST /v1/iam/invitations/updateGET /v1/iam/invitationsPOST /v1/iam/invitationsPOST /v1/iam/issue-user-tokenPOST /v1/iam/keys/deleteGET /v1/iam/keys/getPOST /v1/iam/keys/mintPOST /v1/iam/keys/revokePOST /v1/iam/keys/updateGET /v1/iam/keysPOST /v1/iam/keysGET /v1/iam/linked-accountsPOST /v1/iam/loginGET /v1/iam/membershipsPOST /v1/iam/membershipsPOST /v1/iam/mfa/disablePOST /v1/iam/mfa/preferredPOST /v1/iam/mfa/setup/enablePOST /v1/iam/mfa/setup/initiatePOST /v1/iam/mfa/setup/verifyPOST /v1/iam/mint-user-keysGET /v1/iam/oauth/authorizePOST /v1/iam/oauth/authorizeGET /v1/iam/oauth/callbackPOST /v1/iam/oauth/device/infoPOST /v1/iam/oauth/devicePOST /v1/iam/oauth/federation/mfaPOST /v1/iam/oauth/introspectGET /v1/iam/oauth/logoutPOST /v1/iam/oauth/logoutPOST /v1/iam/oauth/revokePOST /v1/iam/oauth/tokenGET /v1/iam/oauth/userinfoPOST /v1/iam/oauth/userinfoPOST /v1/iam/onboardPOST /v1/iam/organizations/deleteGET /v1/iam/organizations/getPOST /v1/iam/organizations/updateGET /v1/iam/organizationsPOST /v1/iam/organizationsPOST /v1/iam/permissions/deleteGET /v1/iam/permissions/getPOST /v1/iam/permissions/updateGET /v1/iam/permissionsPOST /v1/iam/permissionsPOST /v1/iam/preferencesPOST /v1/iam/projects/deletePOST /v1/iam/projects/getPOST /v1/iam/projects/updateGET /v1/iam/projectsPOST /v1/iam/projectsPOST /v1/iam/providers/deletePOST /v1/iam/providers/getPOST /v1/iam/providers/updateGET /v1/iam/providersPOST /v1/iam/providersGET /v1/iam/registry/jwksGET /v1/iam/registry/tokenPOST /v1/iam/registry/tokenGET /v1/iam/resolve-keyPOST /v1/iam/revoke-user-keysPOST /v1/iam/roles/deletePOST /v1/iam/roles/getPOST /v1/iam/roles/updateGET /v1/iam/rolesPOST /v1/iam/rolesGET /v1/iam/scim/v2/ResourceTypes/{name}GET /v1/iam/scim/v2/ResourceTypesGET /v1/iam/scim/v2/Schemas/{id}GET /v1/iam/scim/v2/SchemasGET /v1/iam/scim/v2/ServiceProviderConfigGET /v1/iam/scim/v2/Users/{owner}/{name}PUT /v1/iam/scim/v2/Users/{owner}/{name}PATCH /v1/iam/scim/v2/Users/{owner}/{name}DELETE /v1/iam/scim/v2/Users/{owner}/{name}GET /v1/iam/scim/v2/UsersPOST /v1/iam/scim/v2/UsersPOST /v1/iam/send-verification-codePOST /v1/iam/service-accounts/{name}/keysDELETE /v1/iam/service-accounts/{name}GET /v1/iam/service-accountsPOST /v1/iam/service-accountsPOST /v1/iam/sessions/createPOST /v1/iam/sessions/deletePOST /v1/iam/sessions/getPOST /v1/iam/sessions/listPOST /v1/iam/sessions/updatePOST /v1/iam/set-preferred-mfaPOST /v1/iam/signinPOST /v1/iam/signupPOST /v1/iam/tokens/deletePOST /v1/iam/tokens/getPOST /v1/iam/tokens/issuePOST /v1/iam/tokens/updateGET /v1/iam/tokensPOST /v1/iam/tokensPOST /v1/iam/unlinkPOST /v1/iam/update-applicationPOST /v1/iam/update-organizationPOST /v1/iam/update-preferencesPOST /v1/iam/update-providerPOST /v1/iam/update-rolePOST /v1/iam/update-userPOST /v1/iam/users/deleteGET /v1/iam/users/getPOST /v1/iam/users/updateGET /v1/iam/usersPOST /v1/iam/usersPOST /v1/iam/verification-codesGET /v1/iam/web3/noncePOST /v1/iam/web3/verifyPOST /v1/iam/webauthn-credentials/deletePOST /v1/iam/webauthn-credentials/getPOST /v1/iam/webauthn-credentials/updateGET /v1/iam/webauthn-credentialsPOST /v1/iam/webauthn-credentialsGET /v1/iam/whoamiPOST /v1/iam/workspaces/deletePOST /v1/iam/workspaces/getPOST /v1/iam/workspaces/updateGET /v1/iam/workspacesPOST /v1/iam/workspaces