Sintj API (1.34.0)

Download OpenAPI specification:

Sintj Rails 8.1 API — spec-first, contract-validated.

Auth

Stytch B2B OAuth login (start/callback/session exchange) and session identity (auth_engine pack)

Return the authenticated account's identity

Returns the account id and email for the caller identified by the _sintj_session cookie.

Authorizations:
SessionCookie

Responses

Response samples

Content type
application/json
{
  • "account": {
    }
}

Start a Stytch B2B OAuth login for a tenant

Redirects the browser to Stytch's hosted OAuth start URL for the given tenant (identified by slug) and provider. Not JSON — a 302 browser redirect.

path Parameters
provider
required
string
Enum: "google" "microsoft"
Example: google
query Parameters
org
required
string
Example: org=acme

Tenant slug

return_to
string
Example: return_to=/tenant/dashboard

Path within the tenant app to land on after login completes

Responses

Response samples

Content type
application/json
{
  • "error_code": "auth.provider_not_allowed",
  • "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Stytch OAuth callback — fixed host first, then the tenant's own host

Reached twice in sequence for a single login: first at the fixed Stytch-registered redirect URI (shared across every tenant and region, since OAuth providers don't allow per-tenant redirect URIs), where the Cloudflare Worker rewrites the request into a 302 to this same path on the tenant's own host (subdomain or custom domain) — that hop is Worker-side and not a Rails request. Carries only token — Stytch validates redirect URLs by exact match including query string, so no other params can ride on it. The tenant is resolved from the organization_id in Stytch's authenticated response, and return_to (captured at /{provider}/start) travels in a short-lived cookie, not a query param. On the tenant's own host, Rails verifies the OAuth token via Stytch, finds-or-creates the local account, sets the real session cookie, and redirects to return_to. Not JSON — a 302 browser redirect.

query Parameters
token
required
string
Example: token=rTPQqcSuKpjbUhqWahYNVLbZzUE6hHMPRB6qxvExeGYy

Stytch OAuth token appended by Stytch after the provider completes

Responses

Response samples

Content type
application/json
{
  • "error_code": "auth.unauthorized",
  • "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Log in with email and password

Verifies the password against Stytch (not a locally-stored hash) for the given tenant's Organization. On success, sets the _sintj_session cookie and returns 204.

Request Body schema: application/json
required
required
object (PasswordLoginInput)

Responses

Request samples

Content type
application/json
{
  • "session": {
    }
}

Response samples

Content type
application/json
{
  • "error_code": "auth.unauthorized",
  • "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Log out

Clears the _sintj_session cookie. Idempotent — returns 204 whether or not a session cookie was present.

Responses

Health

Service health and liveness

Health check

Returns 200 when the service is running. No authentication required.

Responses

Response samples

Content type
application/json
{
  • "status": "ok"
}

Tenants

Tenant provisioning (internal admin API)

Get tenant detail

Returns a tenant's full record including per-step onboarding status. Requires an internal service key — not exposed to end users.

Authorizations:
ServiceJWT
path Parameters
id
required
string <uuid>
Example: 7c9e6679-7425-40de-944b-e07fc1f90ae7

Responses

Response samples

Content type
application/json
{
  • "tenant": {
    }
}

Soft-delete a tenant

Soft-deletes a tenant by setting deleted_at. Only disabled tenants may be deleted; attempting to delete an active tenant returns 422. Requires an internal service key — not exposed to end users.

Authorizations:
ServiceJWT
path Parameters
id
required
string <uuid>
Example: 7c9e6679-7425-40de-944b-e07fc1f90ae7

Responses

Response samples

Content type
application/json
{
  • "error_code": "auth.unauthorized",
  • "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Provision a new tenant

Creates a tenant record and seeds pending onboarding status rows. Requires an internal service key — not exposed to end users.

Authorizations:
ServiceJWT
Request Body schema: application/json
required
required
object (TenantInput)

Responses

Request samples

Content type
application/json
{
  • "tenant": {
    }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "id": "550e8400-e29b-41d4-a716-446655440000"
}

Enable a tenant

Sets a tenant's status to active. Idempotent — enabling an already-active tenant is a no-op and still returns 200. Requires an internal service key.

Authorizations:
ServiceJWT
path Parameters
id
required
string <uuid>
Example: 7c9e6679-7425-40de-944b-e07fc1f90ae7

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}

Disable a tenant

Sets a tenant's status to disabled. Idempotent — disabling an already-disabled tenant is a no-op and still returns 200. Requires an internal service key.

Authorizations:
ServiceJWT
path Parameters
id
required
string <uuid>
Example: 7c9e6679-7425-40de-944b-e07fc1f90ae7

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}

Local-dev mirror of a tenant's Cloudflare KV routing record

Returns the same {tenant_id, slug, host, region, allowed_auth_methods} record normally pushed to Cloudflare KV (Platform::SyncTenantKvService), so a local frontend/Worker (e.g. wrangler dev without --remote) can resolve tenant routing without real remote KV credentials. Public and unauthenticated, but development-environment only — returns 404 in every other environment. Never available in production.

path Parameters
slug
required
string
Example: acme

Responses

Response samples

Content type
application/json
{
  • "tenant_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  • "slug": "acme",
  • "host": "acme.sintj.com",
  • "region": "us",
  • "allowed_auth_methods": [
    ]
}

List and search tenants

Returns a paginated, filterable, full-text-searchable list of tenants. Filter payload is in the request body to avoid URL length limits. Requires an internal service key — not exposed to end users.

Authorizations:
ServiceJWT
Request Body schema: application/json
optional
q
string

Full-text search query

after_id
string <uuid>

Forward cursor — return records after this ID (exclusive)

before_id
string <uuid>

Backward cursor — return records before this ID (exclusive)

limit
integer [ 1 .. 100 ]
Default: 25

Number of records per page (1–100, default 25)

order_by
string

Column to sort by — resource-specific allowlist enforced server-side

order
string
Default: "desc"
Enum: "asc" "desc"
fields
Array of strings

Columns to project — resource-specific allowlist enforced server-side. Omit for all allowed fields.

object (FilterOperand)

Top-level Apollo-style filter — groups of conditions combined by AND/OR.

Responses

Request samples

Content type
application/json
{
  • "q": "acme",
  • "limit": 25,
  • "order_by": "created_at",
  • "order": "desc",
  • "filter": {
    }
}

Response samples

Content type
application/json
{
  • "tenants": [
    ],
  • "meta": {
    }
}

List available zones

Returns zone codes read from the ZONES environment variable. Config-driven — no pagination or filtering. Requires an internal service key.

Authorizations:
ServiceJWT

Responses

Response samples

Content type
application/json
{
  • "zones": [
    ]
}

Workspaces

Workspace management within a tenant (internal admin API)

Create a workspace for a tenant

Creates a new workspace under an existing tenant. Requires a valid X-Schema-Name header identifying the tenant schema.

header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Request Body schema: application/json
required
required
object (WorkspaceInput)

Responses

Request samples

Content type
application/json
{
  • "workspace": {
    }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

Assign a user to a workspace

Assigns an existing user to a workspace with a given role. Duplicate assignments are rejected with a 422 validation error. Requires a valid X-Schema-Name header.

header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Request Body schema: application/json
required
required
object (WorkspaceUserInput)

Responses

Request samples

Content type
application/json
{
  • "workspace_user": {
    }
}

Response samples

Content type
application/json
{
  • "success": true
}

List and search workspaces

Returns a paginated, filterable, full-text-searchable list of workspaces within a tenant schema. Filter payload is in the request body. Requires a valid session cookie and X-Schema-Name header identifying the tenant schema.

Authorizations:
SessionCookie
header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Request Body schema: application/json
optional
q
string

Full-text search query

after_id
string <uuid>

Forward cursor — return records after this ID (exclusive)

before_id
string <uuid>

Backward cursor — return records before this ID (exclusive)

limit
integer [ 1 .. 100 ]
Default: 25

Number of records per page (1–100, default 25)

order_by
string

Column to sort by — resource-specific allowlist enforced server-side

order
string
Default: "desc"
Enum: "asc" "desc"
fields
Array of strings

Columns to project — resource-specific allowlist enforced server-side. Omit for all allowed fields.

object (FilterOperand)

Top-level Apollo-style filter — groups of conditions combined by AND/OR.

Responses

Request samples

Content type
application/json
{
  • "q": "engineering",
  • "limit": 25,
  • "order_by": "name",
  • "order": "asc",
  • "filter": {
    }
}

Response samples

Content type
application/json
{
  • "workspaces": [
    ],
  • "meta": {
    }
}

WorkspaceUsers

Assign users to workspaces within a tenant (internal admin API)

Users

Customer user management within a tenant schema (internal admin API)

Invite a user to the tenant (stub — SIN-1329)

Initiates the invitation flow for a new tenant user: creates a Stytch member, seeds a Tenant::User record with status "invited", and sends an invitation email. Not yet implemented — returns 501 until SIN-1329 is complete. Full contract (200 success + 422 validation error) added when SIN-1329 ships. Requires a valid X-Schema-Name header identifying the tenant schema.

header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Request Body schema: application/json
required
required
object (UserInput)

Responses

Request samples

Content type
application/json
{
  • "user": {
    }
}

Response samples

Content type
application/json
{
  • "error_code": "api.not_implemented",
  • "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Enable a tenant user

Sets a tenant user's status to "active". Idempotent — enabling an already-active user succeeds. Requires a valid X-Schema-Name header identifying the tenant schema.

path Parameters
id
required
string <uuid>
Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

Disable a tenant user

Sets a tenant user's status to "disabled", preventing login. Idempotent. Requires a valid X-Schema-Name header identifying the tenant schema.

path Parameters
id
required
string <uuid>
Example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

List and search tenant users

Returns a paginated, filterable, full-text-searchable list of users within a tenant schema. Filter payload is in the request body. auth_linkage_id and tenant_id are never included in the response. Requires a valid session cookie and X-Schema-Name header identifying the tenant schema.

Authorizations:
SessionCookie
header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Request Body schema: application/json
optional
q
string

Full-text search query

after_id
string <uuid>

Forward cursor — return records after this ID (exclusive)

before_id
string <uuid>

Backward cursor — return records before this ID (exclusive)

limit
integer [ 1 .. 100 ]
Default: 25

Number of records per page (1–100, default 25)

order_by
string

Column to sort by — resource-specific allowlist enforced server-side

order
string
Default: "desc"
Enum: "asc" "desc"
fields
Array of strings

Columns to project — resource-specific allowlist enforced server-side. Omit for all allowed fields.

object (FilterOperand)

Top-level Apollo-style filter — groups of conditions combined by AND/OR.

Responses

Request samples

Content type
application/json
{
  • "q": "jane",
  • "limit": 25,
  • "order_by": "created_at",
  • "order": "desc",
  • "filter": {
    }
}

Response samples

Content type
application/json
{
  • "users": [
    ],
  • "meta": {
    }
}

Invitations

Owner invitation flow — invite (platform_engine) and accept (tenant_engine)

Invite the tenant owner

Creates a Platform::User record (status: invited) and a mirrored Tenant::User in the tenant's Apartment schema, then sends an invitation email with an accept link. Guards: schema_provisioning step must be completed; no Platform::User may exist yet for this tenant. Requires an internal service key.

Authorizations:
ServiceJWT
path Parameters
id
required
string <uuid>
Example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
Request Body schema: application/json
required
required
object (InvitationInput)

Responses

Request samples

Content type
application/json
{
  • "invitation": {
    }
}

Response samples

Content type
application/json
{
  • "success": true,
  • "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}

Accept an owner invitation

Validates the invitation token, sets the owner's password and name, flips both the Platform::User and Tenant::User to status active, and records invitation_accepted_at. No authentication header required — the token in the URL is the auth factor.

path Parameters
token
required
string
Example: a3f8b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1
Request Body schema: application/json
required
required
object (AcceptInvitationInput)

Responses

Request samples

Content type
application/json
{
  • "invitation": {
    }
}

Response samples

Content type
application/json
{
  • "success": true
}

OrgSettings

Tenant-level authentication policy settings (tenant_engine)

Update tenant org settings

Partial update of the tenant's authentication policy settings. Only keys present in the request body are written; omitted keys are left unchanged. Unknown keys are silently ignored. The legacy mfa_required key is never written by this endpoint. Requires a valid X-Schema-Name header identifying the tenant schema.

header Parameters
X-Schema-Name
required
string
Example: acme_1234

Stable Apartment schema name of the tenant

Request Body schema: application/json
required
required
object (OrgSettingsInput)

Partial update — only keys present in the request body are written. Unknown keys are silently ignored. Allowed values are strings only (the OrgSettings table is a key-value store). The legacy mfa_required key must not be sent; use mfa_mode instead.

Responses

Request samples

Content type
application/json
{
  • "org_settings": {
    }
}

Response samples

Content type
application/json
{
  • "success": true
}

Internal

Service-to-service endpoints, authenticated via X-Service-JWT (never exposed to end users)

Provision an Apartment schema in this zone

Internal endpoint called by the central provisioning service to create an Apartment PostgreSQL schema for a tenant in this zone's database and seed OrgSettings defaults. Idempotent — returns 200 if the schema already exists. Authenticated via X-Service-JWT — never exposed to end users.

Authorizations:
ServiceJWT
path Parameters
tenant_id
required
string <uuid>
Example: 7c9e6679-7425-40de-944b-e07fc1f90ae7
Request Body schema: application/json
required
required
object (ProvisionSchemaInput)

Responses

Request samples

Content type
application/json
{
  • "schema": {
    }
}

Response samples

Content type
application/json
{
  • "success": true
}

ObjectCodes

Acronym suggestion and object code engine — stateless acronym candidates for tenant/workspace naming; sequential code assignment is model-layer only (core_acronym pack)

Suggest acronym candidates for a tenant or workspace name

Pure stateless suggestion — returns ranked acronym candidates for the given name and object type. No database reads or writes. The caller presents these to the user, who picks one (or types their own) before saving the entity. Once saved, the code is immutable (enforced by Acronymize::Suggestable on the model). Authenticated via X-Service-JWT only — no X-Schema-Name needed (no DB access).

Authorizations:
ServiceJWT
Request Body schema: application/json
required
required
object (SuggestAcronymInput)

Name and object type to generate acronym candidates for.

Responses

Request samples

Content type
application/json
{
  • "acronym": {
    }
}

Response samples

Content type
application/json
{
  • "acronym": {
    }
}