setup

First-run Setup

Unauthenticated first-run bootstrap of a self-hosted install: whether this deployment still needs setup, and the one call that creates its institute and owner account. Both answer 404 on the cloud platform and once an institute exists.

2 endpoints

POST /api/v1/setup/bootstrap

Create this self-hosted install's institute and its owner account, and sign the owner in. 404 in cloud mode or once an institute exists.

No authenticationScopePublic

Request body

NameTypeConstraints
setupTokenrequired
string≥1 chars
instituterequired
object
ownerrequired
object

Example

json
{
  "setupToken": "string",
  "institute": {
    "slug": "string",
    "name": "Algebra I",
    "defaultLocale": "ar",
    "timezone": "string",
    "currency": "USD"
  },
  "owner": {
    "email": "ada.lovelace@example.com",
    "password": "string",
    "firstName": "Ada",
    "lastName": "Lovelace"
  }
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/setup/bootstrap" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "setupToken": "string",
    "institute": {
      "slug": "string",
      "name": "Algebra I",
      "defaultLocale": "ar",
      "timezone": "string",
      "currency": "USD"
    },
    "owner": {
      "email": "ada.lovelace@example.com",
      "password": "string",
      "firstName": "Ada",
      "lastName": "Lovelace"
    }
  }'

Responses

201An access token for the new owner, their membership, and the institute's id.
NameTypeConstraints
accessTokenrequired
string
refreshToken
string
userrequired
object
membershipsrequired
array<MembershipSummary>
activeTenantIdrequired
string (uuid) | null
json
{
  "accessToken": "string",
  "refreshToken": "string",
  "user": {
    "id": "37386ae0-3738-7738-8386-37386ae03738",
    "email": "ada.lovelace@example.com",
    "fullName": "Ada Lovelace",
    "locale": "ar",
    "status": "active",
    "emailVerified": true
  },
  "memberships": [
    {
      "membershipId": "e34c26d7-e34c-734c-84c2-e34c26d7e34c",
      "tenantId": "4332af8b-4332-7332-832a-4332af8b4332",
      "tenantSlug": "string",
      "tenantName": "string",
      "status": "invited",
      "roles": [
        {
          "roleId": "5b007a17-5b00-7b00-8007-5b007a175b00",
          "roleName": "string",
          "roleKey": "string"
        }
      ]
    }
  ],
  "activeTenantId": "f056e4d2-f056-7056-856e-f056e4d2f056"
}
400The request could not be read at all — unparseable body, unusable content type, oversized payload (`MALFORMED_REQUEST`). Never a schema failure: those are 422.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

401Missing, expired or invalid credentials (`UNAUTHORIZED`, `TOKEN_INVALID`, `SESSION_REVOKED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

403Authenticated, but not allowed (`FORBIDDEN`, `FEATURE_DISABLED`, `QUOTA_EXCEEDED`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

404No such resource, or it is not visible to this tenant (`NOT_FOUND`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

409Conflicts with current state (`CONFLICT`, `VERSION_CONFLICT`, `IDEMPOTENCY_KEY_REUSED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

422The request was read but its content is not acceptable: body/query/path/header failed schema validation (`VALIDATION_ERROR`, with `details.issues`), or a domain rule rejected a well-formed value (`VIDEO_URL_INVALID`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

429Rate limit exceeded — see the `RateLimit-*` and `Retry-After` headers (`RATE_LIMITED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

500Unexpected server error (`INTERNAL_ERROR`). Never carries a stack trace or SQL.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

GET /api/v1/setup/status

Whether this deployment still needs first-run setup. Public: the login page reads it before any session exists.

No authenticationScopePublic

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/setup/status" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The deployment mode and whether an institute has been created yet.
NameTypeConstraints
deploymentModerequired
enum: "cloud" | "self_hosted"
needsSetuprequired
boolean
json
{
  "deploymentMode": "cloud",
  "needsSetup": true
}
400The request could not be read at all — unparseable body, unusable content type, oversized payload (`MALFORMED_REQUEST`). Never a schema failure: those are 422.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

401Missing, expired or invalid credentials (`UNAUTHORIZED`, `TOKEN_INVALID`, `SESSION_REVOKED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

403Authenticated, but not allowed (`FORBIDDEN`, `FEATURE_DISABLED`, `QUOTA_EXCEEDED`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

404No such resource, or it is not visible to this tenant (`NOT_FOUND`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

409Conflicts with current state (`CONFLICT`, `VERSION_CONFLICT`, `IDEMPOTENCY_KEY_REUSED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

422The request was read but its content is not acceptable: body/query/path/header failed schema validation (`VALIDATION_ERROR`, with `details.issues`), or a domain rule rejected a well-formed value (`VIDEO_URL_INVALID`, …).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

429Rate limit exceeded — see the `RateLimit-*` and `Retry-After` headers (`RATE_LIMITED`).

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.

500Unexpected server error (`INTERNAL_ERROR`). Never carries a stack trace or SQL.

Returns the shared `ErrorEnvelope` — `{ error: { code, message, requestId, details? } }`. Every code is listed in the Conventions guide.