StabisoDocs

API reference

Company sign-in

Company sign-in: the organization's own identity provider (Okta, Microsoft Entra ID or any OpenID Connect provider), the e-mail domains whose people sign in there, and the sign-in itself, which the passkey step follows.

Operation Summary Scope Idempotency-Key
POST /v1/auth/company/finish Finish a company sign-in
POST /v1/auth/company/start Start a company sign-in
GET /v1/company-sign-in Get the company sign-in admin
PUT /v1/company-sign-in Set up the company sign-in admin
DELETE /v1/company-sign-in Remove the company sign-in admin

POST /v1/auth/company/finish

Finish a company sign-in

Exchange the code the identity provider sent back for its ID token, check it (signature, issuer, audience, expiry, nonce, a verified address of one of the connection's domains) and sign the person in to that organization only. The answer is that of POST /v1/auth/google: passkey (then POST /v1/auth/passkey). Refused with 403 for a state that is too old or not this server's (company_sign_in_state), a token that does not hold (company_sign_in_refused) or an address that does not fit (company_sign_in_email).

Required scope none (public)
Idempotency-Key not used
Operation id finish_v1_auth_company_finish_post

Request body

application/json (required): CompanyFinish

Field Type Required Description
code string yes The code the provider sent the browser back with. (min length 1; max length 4000)
state string yes The state the provider sent the browser back with. (min length 1; max length 4000)

Example request

curl -X POST "$ERP_URL/v1/auth/company/finish" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "code": "c0d3-from-the-provider",
  "state": "eyJjIjoi.c2lnbmF0dXJl"
}'

Responses

Status Meaning Body
200 OK LoginResult
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "status": "choose_organization",
  "organizations": [
    {
      "org_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "org_name": "string",
      "test_organization": false,
      "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "copy_of": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    }
  ],
  "expires_at": "2026-09-21T09:30:00Z",
  "passkey": {
    "setup": true,
    "options": {}
  }
}

POST /v1/auth/company/start

Start a company sign-in

The identity provider's sign-in page for an address whose organization signs in with its own provider. It needs no credential and serves the web UI's sign-in page. The browser goes to url and comes back to the redirect URI with code and state for POST /v1/auth/company/finish. Refused with 403 (company_sign_in_none) when no organization that invited the address covers its domain.

Required scope none (public)
Idempotency-Key not used
Operation id start_v1_auth_company_start_post

Request body

application/json (required): CompanyStart

Field Type Required Description
email string yes The person's address: its domain names their organization's provider. (min length 3; max length 320)
org_id string (uuid) or null The organization to sign in to, when the address may sign in to several through their company's provider.

Example request

curl -X POST "$ERP_URL/v1/auth/company/start" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "lena.meier@acme.com"
}'

Responses

Status Meaning Body
200 OK CompanyStartOut
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "url": "string"
}

GET /v1/company-sign-in

Get the company sign-in

Whether company sign-in can be set up here, the redirect URI to register at the identity provider, and the organization's connection (its secret is never shown).

Required scope admin (admin implies every scope)
Operation id get_company_sign_in_v1_company_sign_in_get

Example request

curl "$ERP_URL/v1/company-sign-in" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
200 OK CompanySignInSetup
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "available": true,
  "redirect_uri": "string",
  "connection": {
    "provider": "entra",
    "issuer": "https://acme.okta.com",
    "client_id": "string",
    "has_secret": true,
    "domains": [
      "string"
    ],
    "required": true,
    "last_used_at": "2026-09-21T09:30:00Z",
    "updated_at": "2026-09-21T09:30:00Z"
  }
}

PUT /v1/company-sign-in

Set up the company sign-in

Connect the organization's identity provider, or change the connection: the provider, its issuer (an Okta domain, an Entra tenant or an issuer URL), the app's client id and secret, the e-mail domains whose people sign in through it and whether they may sign in only through it. The provider's discovery document is read first: refused with 502 (company_sign_in_unreachable) when it does not answer for the issuer. Making it the only way in (required) is refused (company_sign_in_untried, 409) until somebody signed in through it. Every sign-in through it still ends with the person's passkey.

Required scope admin (admin implies every scope)
Idempotency-Key not used
Operation id put_company_sign_in_v1_company_sign_in_put

Request body

application/json (required): ConnectionInput

Field Type Required Description
provider "entra" | "oidc" | "okta" yes The identity provider: okta (Okta), entra (Microsoft Entra ID, the former Azure AD) or oidc (any other OpenID Connect provider).
issuer string yes Where the provider is: for Okta the Okta domain (acme.okta.com) or an authorization server's issuer; for Microsoft Entra ID the tenant id or the tenant's primary domain (acme.onmicrosoft.com); otherwise the issuer URL (https://...). (min length 3; max length 300)
client_id string yes The client id (Entra: application id) of the app registered at the provider for this sign-in. (min length 1; max length 200)
client_secret string or null The app's client secret. Left out on a change: the one kept stays; an empty string removes it (an app without a secret, which signs in with PKCE alone). (max length 500)
domains array of string or null The e-mail domains whose people sign in through it. Left out: the domain of the administrator's own address. (max items 20)
required boolean Whether those people may sign in only through it: Google and a password no longer open the organization for them. (default false)

Example request

curl -X PUT "$ERP_URL/v1/company-sign-in" \
  -H "Authorization: Bearer $ERP_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "client_id": "0oa1b2c3d4e5f6g7h8i9",
  "client_secret": "s3cr3t-of-the-okta-app",
  "domains": [
    "acme.com"
  ],
  "issuer": "acme.okta.com",
  "provider": "okta",
  "required": false
}'

Responses

Status Meaning Body
200 OK ConnectionOut
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Example response (shape)

{
  "provider": "entra",
  "issuer": "https://acme.okta.com",
  "client_id": "string",
  "has_secret": true,
  "domains": [
    "string"
  ],
  "required": true,
  "last_used_at": "2026-09-21T09:30:00Z",
  "updated_at": "2026-09-21T09:30:00Z"
}

DELETE /v1/company-sign-in

Remove the company sign-in

Remove the connection and its sealed secret: its people sign in with Google or a password again.

Required scope admin (admin implies every scope)
Idempotency-Key not used
Operation id delete_company_sign_in_v1_company_sign_in_delete

Example request

curl -X DELETE "$ERP_URL/v1/company-sign-in" \
  -H "Authorization: Bearer $ERP_KEY"

Responses

Status Meaning Body
204 No content
401 Missing or invalid API key (unauthorized). ErrorEnvelope
403 The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). ErrorEnvelope
409 The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). ErrorEnvelope
422 Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. HTTPValidationError

Schemas

CompanyFinish

Field Type Required Description
code string yes The code the provider sent the browser back with. (min length 1; max length 4000)
state string yes The state the provider sent the browser back with. (min length 1; max length 4000)

CompanySignInSetup

Field Type Required Description
available boolean yes Whether company sign-in can be set up on this server (it needs the key that seals client secrets and the address people reach the app at).
redirect_uri string or null yes The sign-in redirect URI to register in the app at the identity provider.
connection ConnectionOut or null yes The connection; null: none yet.

CompanyStart

Field Type Required Description
email string yes The person's address: its domain names their organization's provider. (min length 3; max length 320)
org_id string (uuid) or null The organization to sign in to, when the address may sign in to several through their company's provider.

CompanyStartOut

Field Type Required Description
url string yes The identity provider's sign-in page: the browser goes there, and comes back to the redirect URI with code and state.

ConnectionInput

Field Type Required Description
provider "entra" | "oidc" | "okta" yes The identity provider: okta (Okta), entra (Microsoft Entra ID, the former Azure AD) or oidc (any other OpenID Connect provider).
issuer string yes Where the provider is: for Okta the Okta domain (acme.okta.com) or an authorization server's issuer; for Microsoft Entra ID the tenant id or the tenant's primary domain (acme.onmicrosoft.com); otherwise the issuer URL (https://...). (min length 3; max length 300)
client_id string yes The client id (Entra: application id) of the app registered at the provider for this sign-in. (min length 1; max length 200)
client_secret string or null The app's client secret. Left out on a change: the one kept stays; an empty string removes it (an app without a secret, which signs in with PKCE alone). (max length 500)
domains array of string or null The e-mail domains whose people sign in through it. Left out: the domain of the administrator's own address. (max items 20)
required boolean Whether those people may sign in only through it: Google and a password no longer open the organization for them. (default false)

ConnectionOut

Field Type Required Description
provider "entra" | "oidc" | "okta" yes The identity provider: okta (Okta), entra (Microsoft Entra ID, the former Azure AD) or oidc (any other OpenID Connect provider).
issuer string yes The provider's issuer, which its ID tokens name and its discovery document is read from.
client_id string yes The client id of the app registered at the provider.
has_secret boolean yes Whether the app's client secret is kept (sealed; it is never shown).
domains array of string yes The e-mail domains whose people sign in through it.
required boolean yes Whether those people may sign in only through it, not with Google or a password.
last_used_at string (date-time) or null yes The last sign-in through it (UTC).
updated_at string (date-time) yes When it was last changed (UTC).
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 20b7dd5b0c4d