tenancy

Settings & Branches

Branches, tenant settings, feature flags, license status, and subscription status.

18 endpoints

GET /api/v1/branches

List every branch in the active tenant (any member may read).

Requires authenticationScopeNo additional permission

curl example

curl
curl -X GET "https://your-institute.example/api/v1/branches" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The tenant’s branches.
json
[
  {
    "id": "37386ae0-3738-7738-8386-37386ae03738",
    "tenantId": "4332af8b-4332-7332-832a-4332af8b4332",
    "name": "Algebra I",
    "code": "string",
    "address": {},
    "phone": "+15551234567",
    "isDefault": true,
    "isActive": true,
    "createdAt": "2026-03-02T09:00:00.000Z",
    "updatedAt": "2026-03-02T09:00:00.000Z"
  }
]
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

POST /api/v1/branches

Create a branch. Names must be unique per tenant.

Requires authenticationScopebranches.manage

Request body

NameTypeConstraints
namerequired
string1–200 chars
code
enum: "" | string—
address
object—
phone
enum: "" | string—
isDefault
boolean—

Example

json
{
  "name": "Algebra I",
  "code": "",
  "address": {},
  "phone": "",
  "isDefault": true
}

curl example

curl
curl -X POST "https://your-institute.example/api/v1/branches" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Algebra I",
    "code": "",
    "address": {},
    "phone": "",
    "isDefault": true
  }'

Responses

201The newly created branch.
NameTypeConstraints
idrequired
string (uuid)—
tenantIdrequired
string (uuid)—
namerequired
string—
coderequired
string | null≥1 chars
addressrequired
object | null—
phonerequired
string | null≥1 chars
isDefaultrequired
boolean—
isActiverequired
boolean—
createdAtrequired
string (date-time)—
updatedAtrequired
string (date-time)—
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "tenantId": "4332af8b-4332-7332-832a-4332af8b4332",
  "name": "Algebra I",
  "code": "string",
  "address": {},
  "phone": "+15551234567",
  "isDefault": true,
  "isActive": true,
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z"
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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.

DELETE /api/v1/branches/{id}

Delete a branch. The default branch, and any branch with role assignments, cannot be deleted (409).

Requires authenticationScopebranches.manage

Path & query parameters

NameInTypeConstraints
idrequired
pathstring—

curl example

curl
curl -X DELETE "https://your-institute.example/api/v1/branches/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The branch was deleted.
NameTypeConstraints
okrequired
enum: true—
json
{
  "ok": 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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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.

PATCH /api/v1/branches/{id}

Update a branch. Setting `isDefault: true` clears the previous default branch.

Requires authenticationScopebranches.manage

Path & query parameters

NameInTypeConstraints
idrequired
pathstring—

Request body

NameTypeConstraints
name
string1–200 chars
code
enum: "" | string | null—
address
object | null—
phone
enum: "" | string | null—
isDefault
boolean—
isActive
boolean—

Example

json
{
  "name": "Algebra I",
  "code": "",
  "address": {},
  "phone": "",
  "isDefault": true,
  "isActive": true
}

curl example

curl
curl -X PATCH "https://your-institute.example/api/v1/branches/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Algebra I",
    "code": "",
    "address": {},
    "phone": "",
    "isDefault": true,
    "isActive": true
  }'

Responses

200The updated branch.
NameTypeConstraints
idrequired
string (uuid)—
tenantIdrequired
string (uuid)—
namerequired
string—
coderequired
string | null≥1 chars
addressrequired
object | null—
phonerequired
string | null≥1 chars
isDefaultrequired
boolean—
isActiverequired
boolean—
createdAtrequired
string (date-time)—
updatedAtrequired
string (date-time)—
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "tenantId": "4332af8b-4332-7332-832a-4332af8b4332",
  "name": "Algebra I",
  "code": "string",
  "address": {},
  "phone": "+15551234567",
  "isDefault": true,
  "isActive": true,
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z"
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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/feature-flags

Effective feature flags for the active tenant (registry defaults merged with the plan and tenant overrides).

Requires authenticationScopeNo additional permission

curl example

curl
curl -X GET "https://your-institute.example/api/v1/feature-flags" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The tenant’s effective feature flags.
NameTypeConstraints
basic_reportsrequired
boolean—
advanced_reportsrequired
boolean—
integration_apirequired
boolean—
mcprequired
boolean—
custom_domainrequired
boolean—
whatsapp_notificationsrequired
boolean—
sms_notificationsrequired
boolean—
byo_email_providerrequired
boolean—
byo_push_providerrequired
boolean—
courses_videorequired
boolean—
json
{
  "basic_reports": true,
  "advanced_reports": true,
  "integration_api": true,
  "mcp": true,
  "custom_domain": true,
  "whatsapp_notifications": true,
  "sms_notifications": true,
  "byo_email_provider": true,
  "byo_push_provider": true,
  "courses_video": 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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

PATCH /api/v1/feature-flags

Toggle feature flags. Platform-managed in cloud deployments (403 here); in self_hosted deployments the tenant owner may toggle self-manageable flags only.

Requires authenticationScopeNo additional permission

Request body

None.

Example

json
{}

curl example

curl
curl -X PATCH "https://your-institute.example/api/v1/feature-flags" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'

Responses

200The tenant’s new effective feature flags.
NameTypeConstraints
basic_reportsrequired
boolean—
advanced_reportsrequired
boolean—
integration_apirequired
boolean—
mcprequired
boolean—
custom_domainrequired
boolean—
whatsapp_notificationsrequired
boolean—
sms_notificationsrequired
boolean—
byo_email_providerrequired
boolean—
byo_push_providerrequired
boolean—
courses_videorequired
boolean—
json
{
  "basic_reports": true,
  "advanced_reports": true,
  "integration_api": true,
  "mcp": true,
  "custom_domain": true,
  "whatsapp_notifications": true,
  "sms_notifications": true,
  "byo_email_provider": true,
  "byo_push_provider": true,
  "courses_video": 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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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/license

This self-hosted instance’s license state (self_hosted deployments only).

Requires authenticationScopeNo additional permission

curl example

curl
curl -X GET "https://your-institute.example/api/v1/license" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The instance’s license summary.
NameTypeConstraints
planrequired
string—
limitsrequired
object—
featuresrequired
array<string>—
expiresAtrequired
string (date-time)—
staterequired
enum: "valid" | "expired" | "locked" | "revoked"—
lockedByCommandrequired
boolean—
lastServerContactAtrequired
string (date-time) | null—
lastServerTimerequired
string (date-time) | null—
consecutiveFailuresrequired
integer0–9007199254740991
installIdrequired
string—
tamperSignalsrequired
array<object>—
json
{
  "plan": "string",
  "limits": {},
  "features": [
    "string"
  ],
  "expiresAt": "2026-03-02T09:00:00.000Z",
  "state": "valid",
  "lockedByCommand": true,
  "lastServerContactAt": "2026-03-02T09:00:00.000Z",
  "lastServerTime": "2026-03-02T09:00:00.000Z",
  "consecutiveFailures": 0,
  "installId": "2472867d-2472-7472-8728-2472867d2472",
  "tamperSignals": [
    {
      "kind": "state_signature_invalid",
      "detectedAt": "2026-03-02T09:00:00.000Z",
      "detail": "string"
    }
  ]
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

POST /api/v1/license/apply-token

Apply a signed offline unlock token issued by the license server (self_hosted only).

Requires authenticationScopesettings.manage

Request body

NameTypeConstraints
tokenrequired
string1–8192 chars

Example

json
{
  "token": "string"
}

curl example

curl
curl -X POST "https://your-institute.example/api/v1/license/apply-token" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "token": "string"
  }'

Responses

200The instance’s license summary after the token was applied.
NameTypeConstraints
planrequired
string—
limitsrequired
object—
featuresrequired
array<string>—
expiresAtrequired
string (date-time)—
staterequired
enum: "valid" | "expired" | "locked" | "revoked"—
lockedByCommandrequired
boolean—
lastServerContactAtrequired
string (date-time) | null—
lastServerTimerequired
string (date-time) | null—
consecutiveFailuresrequired
integer0–9007199254740991
installIdrequired
string—
tamperSignalsrequired
array<object>—
json
{
  "plan": "string",
  "limits": {},
  "features": [
    "string"
  ],
  "expiresAt": "2026-03-02T09:00:00.000Z",
  "state": "valid",
  "lockedByCommand": true,
  "lastServerContactAt": "2026-03-02T09:00:00.000Z",
  "lastServerTime": "2026-03-02T09:00:00.000Z",
  "consecutiveFailures": 0,
  "installId": "2472867d-2472-7472-8728-2472867d2472",
  "tamperSignals": [
    {
      "kind": "state_signature_invalid",
      "detectedAt": "2026-03-02T09:00:00.000Z",
      "detail": "string"
    }
  ]
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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/license/updates

This install’s update channel status (self_hosted deployments only).

Requires authenticationScopesettings.manage

curl example

curl
curl -X GET "https://your-institute.example/api/v1/license/updates" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The install’s update status.
NameTypeConstraints
autoUpdaterequired
boolean—
channelrequired
enum: "stable" | "beta"—
currentVersionrequired
string—
checkRequestedAtrequired
string (date-time) | null—
updatesBlockedrequired
boolean—
blockedReasonrequired
string | null—
lastCheckAtrequired
string (date-time) | null—
lastResultrequired
enum: "up_to_date" | "updated" | "rolled_back" | "failed" | "skipped" | null | null—
reasonrequired
enum: "none" | "auto_update_off" | "min_from_version" | "locked" | "migration_running" | "manifest_unreachable" | "bad_signature" | "channel_mismatch" | "digest_mismatch" | "docker_error" | "health_check_failed" | "api_unreachable" | "setup_pending" | null | null—
targetVersionrequired
string | null—
detailrequired
string | null—
updaterPresentrequired
boolean—
storageUpgradeNeededrequired
boolean—
json
{
  "autoUpdate": true,
  "channel": "stable",
  "currentVersion": "string",
  "checkRequestedAt": "2026-03-02T09:00:00.000Z",
  "updatesBlocked": true,
  "blockedReason": "string",
  "lastCheckAt": "2026-03-02T09:00:00.000Z",
  "lastResult": "up_to_date",
  "reason": "none",
  "targetVersion": "string",
  "detail": "string",
  "updaterPresent": true,
  "storageUpgradeNeeded": 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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

POST /api/v1/license/updates/check

Ask the updater to check for a new release now instead of waiting for its next interval.

Requires authenticationScopesettings.manage

curl example

curl
curl -X POST "https://your-institute.example/api/v1/license/updates/check" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The install’s update status, with the check request recorded.
NameTypeConstraints
autoUpdaterequired
boolean—
channelrequired
enum: "stable" | "beta"—
currentVersionrequired
string—
checkRequestedAtrequired
string (date-time) | null—
updatesBlockedrequired
boolean—
blockedReasonrequired
string | null—
lastCheckAtrequired
string (date-time) | null—
lastResultrequired
enum: "up_to_date" | "updated" | "rolled_back" | "failed" | "skipped" | null | null—
reasonrequired
enum: "none" | "auto_update_off" | "min_from_version" | "locked" | "migration_running" | "manifest_unreachable" | "bad_signature" | "channel_mismatch" | "digest_mismatch" | "docker_error" | "health_check_failed" | "api_unreachable" | "setup_pending" | null | null—
targetVersionrequired
string | null—
detailrequired
string | null—
updaterPresentrequired
boolean—
storageUpgradeNeededrequired
boolean—
json
{
  "autoUpdate": true,
  "channel": "stable",
  "currentVersion": "string",
  "checkRequestedAt": "2026-03-02T09:00:00.000Z",
  "updatesBlocked": true,
  "blockedReason": "string",
  "lastCheckAt": "2026-03-02T09:00:00.000Z",
  "lastResult": "up_to_date",
  "reason": "none",
  "targetVersion": "string",
  "detail": "string",
  "updaterPresent": true,
  "storageUpgradeNeeded": 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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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/onboarding

First-run checklist for the active tenant: per-step done/count for the institute profile, branches, courses, groups, students, fees, notification channels and team. Cached 60s.

Requires authenticationScopesettings.manage

curl example

curl
curl -X GET "https://your-institute.example/api/v1/onboarding" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The tenant’s onboarding progress.
NameTypeConstraints
stepsrequired
array<object>—
completedStepsrequired
integer0–9007199254740991
totalStepsrequired
integer0–9007199254740991
isCompleterequired
boolean—
countsrequired
object—
json
{
  "steps": [
    {
      "key": "institute",
      "done": true,
      "count": 0
    }
  ],
  "completedSteps": 0,
  "totalSteps": 0,
  "isComplete": true,
  "counts": {
    "branches": 0,
    "courses": 0,
    "groups": 0,
    "students": 0,
    "feeSchedules": 0,
    "invoices": 0,
    "staff": 0,
    "members": 0,
    "notificationChannels": 0
  }
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

POST /api/v1/relay/sender-name

Submit this institute’s requested display name for institute-mode email, for the vendor to approve. self_hosted only.

Requires authenticationScopesettings.manage

Request body

NameTypeConstraints
displayNamerequired
string1–70 chars

Example

json
{
  "displayName": "string"
}

curl example

curl
curl -X POST "https://your-institute.example/api/v1/relay/sender-name" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "displayName": "string"
  }'

Responses

200The relay status after the request was recorded.
NameTypeConstraints
enrolmentStatusrequired
enum: "unenrolled" | "pending" | "approved" | "blocked"—
requestedSenderDisplayNamerequired
string | null≥1 chars
lastErrorMessagerequired
string | null≥1 chars
lastErrorAtrequired
string (date-time) | null—
accountrequired
object | null—
json
{
  "enrolmentStatus": "unenrolled",
  "requestedSenderDisplayName": "string",
  "lastErrorMessage": "string",
  "lastErrorAt": "2026-03-02T09:00:00.000Z",
  "account": {
    "balanceUnits": -9007199254740991,
    "overdraftUnits": -9007199254740991,
    "status": "active",
    "reputationHold": true,
    "relayEmailEnabled": true,
    "installStatus": "approved",
    "prices": [
      {
        "senderMode": "platform",
        "priceUnits": -9007199254740991
      }
    ],
    "senderName": {
      "displayName": "string",
      "state": "none"
    },
    "asOf": "2026-03-02T09:00:00.000Z"
  }
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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/relay/status

This install’s relay enrolment and last known account snapshot (balance, overdraft, prices, sender-name state). self_hosted only.

Requires authenticationScopenotifications.manage

curl example

curl
curl -X GET "https://your-institute.example/api/v1/relay/status" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The relay status.
NameTypeConstraints
enrolmentStatusrequired
enum: "unenrolled" | "pending" | "approved" | "blocked"—
requestedSenderDisplayNamerequired
string | null≥1 chars
lastErrorMessagerequired
string | null≥1 chars
lastErrorAtrequired
string (date-time) | null—
accountrequired
object | null—
json
{
  "enrolmentStatus": "unenrolled",
  "requestedSenderDisplayName": "string",
  "lastErrorMessage": "string",
  "lastErrorAt": "2026-03-02T09:00:00.000Z",
  "account": {
    "balanceUnits": -9007199254740991,
    "overdraftUnits": -9007199254740991,
    "status": "active",
    "reputationHold": true,
    "relayEmailEnabled": true,
    "installStatus": "approved",
    "prices": [
      {
        "senderMode": "platform",
        "priceUnits": -9007199254740991
      }
    ],
    "senderName": {
      "displayName": "string",
      "state": "none"
    },
    "asOf": "2026-03-02T09:00:00.000Z"
  }
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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/settings

Effective settings for the active tenant (registry defaults merged with stored overrides). With `settings.manage` the whole registry; for any other member or key only the member view (institute name, default locale, timezone, currency, SMS enabled). The 18 per-type notification keys are deprecated aliases derived from the notification rules (GET /notification-rules).

Requires authenticationScopeNo additional permission

curl example

curl
curl -X GET "https://your-institute.example/api/v1/settings" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The tenant’s effective settings — the full registry, or the member view without `settings.manage`.
NameTypeConstraints
general.name
string1–200 chars
general.timezone
string1–100 chars
general.currency
string3–3 chars
general.defaultLocale
enum: "ar" | "en" | "he"—
general.logoFileId
string (uuid) | null—
general.contactEmail
string (email) | null0–320 chars
general.contactPhone
string | null1–50 chars
general.address
string | null1–500 chars
attendance.lateThresholdMinutes
integer0–120
attendance.notifyGuardianOnAbsence
boolean—
attendance.warnBelowRate
integer0–100
attendance.criticalBelowRate
integer0–100
grading.scale
enum: "percentage" | "letter" | "custom"—
assessment.autoSendOnPublish
boolean—
billing.invoiceDueDays
integer0–365
billing.allowOverpayment
boolean—
billing.invoicePrefix
string1–10 chars
billing.autoInvoiceOnEnrollment
boolean—
notifications.smsEnabled
boolean—
notifications.digestHourLocal
integer0–23
notifications.quietHours
object | null—
notifications.email.senderMode
enum: "platform" | "institute"—
notifications.email.displayName
string | null1–70 chars
notifications.email.replyTo
string (email) | null0–320 chars
notifications.paidEmail.invoiceIssued
boolean—
notifications.paidEmail.invoiceOverdue
boolean—
notifications.paidEmail.paymentReceipt
boolean—
notifications.paidEmail.enrollmentWelcome
boolean—
notifications.paidEmail.examPublished
boolean—
notifications.paidEmail.courseCompleted
boolean—
notifications.paidEmail.assignmentPublished
boolean—
notifications.paidEmail.assignmentSubmitted
boolean—
notifications.paidEmail.assignmentGraded
boolean—
notifications.paidEmail.quizPublished
boolean—
notifications.paidEmail.quizSubmitted
boolean—
notifications.paidEmail.quizGraded
boolean—
notifications.paidEmail.digestEnabled
boolean—
notifications.channelLadder
array<enum: "push" | "whatsapp" | "email" | "sms" | "in_app">—
curriculum.autoCompleteThresholdPercent
integer50–100
curriculum.notifyOnLessonPublished
boolean—
reminders.classStartsSoon
boolean—
reminders.workDueTomorrow
boolean—
reminders.emailEnabled
boolean—
updates.autoUpdate
boolean—
updates.channel
enum: "stable" | "beta"—
updates.repairMode
enum: "repair" | "report"—
integration.publicCatalogueEnabled
boolean—
integration.captchaSiteKey
string | null1–200 chars
integration.registrationsToLeads
boolean—
loginDiscovery.staffEmails
array<string (email)>—
json
{
  "general.name": "string",
  "general.timezone": "string",
  "general.currency": "USD",
  "general.defaultLocale": "ar",
  "general.logoFileId": "5987666b-5987-7987-8876-5987666b5987",
  "general.contactEmail": "ada.lovelace@example.com",
  "general.contactPhone": "string",
  "general.address": "string",
  "attendance.lateThresholdMinutes": 0,
  "attendance.notifyGuardianOnAbsence": true,
  "attendance.warnBelowRate": 0,
  "attendance.criticalBelowRate": 0,
  "grading.scale": "percentage",
  "assessment.autoSendOnPublish": true,
  "billing.invoiceDueDays": 0,
  "billing.allowOverpayment": true,
  "billing.invoicePrefix": "string",
  "billing.autoInvoiceOnEnrollment": true,
  "notifications.smsEnabled": true,
  "notifications.digestHourLocal": 0,
  "notifications.quietHours": {
    "start": "string",
    "end": "string"
  },
  "notifications.email.senderMode": "platform",
  "notifications.email.displayName": "string",
  "notifications.email.replyTo": "ada.lovelace@example.com",
  "notifications.paidEmail.invoiceIssued": true,
  "notifications.paidEmail.invoiceOverdue": true,
  "notifications.paidEmail.paymentReceipt": true,
  "notifications.paidEmail.enrollmentWelcome": true,
  "notifications.paidEmail.examPublished": true,
  "notifications.paidEmail.courseCompleted": true,
  "notifications.paidEmail.assignmentPublished": true,
  "notifications.paidEmail.assignmentSubmitted": true,
  "notifications.paidEmail.assignmentGraded": true,
  "notifications.paidEmail.quizPublished": true,
  "notifications.paidEmail.quizSubmitted": true,
  "notifications.paidEmail.quizGraded": true,
  "notifications.paidEmail.digestEnabled": true,
  "notifications.channelLadder": [
    "push"
  ],
  "curriculum.autoCompleteThresholdPercent": 50,
  "curriculum.notifyOnLessonPublished": true,
  "reminders.classStartsSoon": true,
  "reminders.workDueTomorrow": true,
  "reminders.emailEnabled": true,
  "updates.autoUpdate": true,
  "updates.channel": "stable",
  "updates.repairMode": "repair",
  "integration.publicCatalogueEnabled": true,
  "integration.captchaSiteKey": "string",
  "integration.registrationsToLeads": true,
  "loginDiscovery.staffEmails": [
    "ada.lovelace@example.com"
  ]
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

PATCH /api/v1/settings

Update one or more settings. An unknown key, or an invalid value, is rejected (422). A write to a deprecated per-type notification key is translated into the matching notification rule and answered with a `Deprecation` header; a write that would raise what the institute pays for (a paid channel or a type switched on, a wider audience) is refused with 422 `legacy_write_raises_paid_exposure` — use `PUT /notification-rules/{typeKey}` with `confirmCost` instead.

Requires authenticationScopesettings.manage

Request body

None.

Example

json
{}

curl example

curl
curl -X PATCH "https://your-institute.example/api/v1/settings" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{}'

Responses

200The tenant’s new effective settings.
NameTypeConstraints
general.namerequired
string1–200 chars
general.timezonerequired
string1–100 chars
general.currencyrequired
string3–3 chars
general.defaultLocalerequired
enum: "ar" | "en" | "he"—
general.logoFileIdrequired
string (uuid) | null—
general.contactEmailrequired
string (email) | null0–320 chars
general.contactPhonerequired
string | null1–50 chars
general.addressrequired
string | null1–500 chars
attendance.lateThresholdMinutesrequired
integer0–120
attendance.notifyGuardianOnAbsencerequired
boolean—
attendance.warnBelowRaterequired
integer0–100
attendance.criticalBelowRaterequired
integer0–100
grading.scalerequired
enum: "percentage" | "letter" | "custom"—
assessment.autoSendOnPublishrequired
boolean—
billing.invoiceDueDaysrequired
integer0–365
billing.allowOverpaymentrequired
boolean—
billing.invoicePrefixrequired
string1–10 chars
billing.autoInvoiceOnEnrollmentrequired
boolean—
notifications.smsEnabledrequired
boolean—
notifications.digestHourLocalrequired
integer0–23
notifications.quietHoursrequired
object | null—
notifications.email.senderModerequired
enum: "platform" | "institute"—
notifications.email.displayNamerequired
string | null1–70 chars
notifications.email.replyTorequired
string (email) | null0–320 chars
notifications.paidEmail.invoiceIssuedrequired
boolean—
notifications.paidEmail.invoiceOverduerequired
boolean—
notifications.paidEmail.paymentReceiptrequired
boolean—
notifications.paidEmail.enrollmentWelcomerequired
boolean—
notifications.paidEmail.examPublishedrequired
boolean—
notifications.paidEmail.courseCompletedrequired
boolean—
notifications.paidEmail.assignmentPublishedrequired
boolean—
notifications.paidEmail.assignmentSubmittedrequired
boolean—
notifications.paidEmail.assignmentGradedrequired
boolean—
notifications.paidEmail.quizPublishedrequired
boolean—
notifications.paidEmail.quizSubmittedrequired
boolean—
notifications.paidEmail.quizGradedrequired
boolean—
notifications.paidEmail.digestEnabledrequired
boolean—
notifications.channelLadderrequired
array<enum: "push" | "whatsapp" | "email" | "sms" | "in_app">—
curriculum.autoCompleteThresholdPercentrequired
integer50–100
curriculum.notifyOnLessonPublishedrequired
boolean—
reminders.classStartsSoonrequired
boolean—
reminders.workDueTomorrowrequired
boolean—
reminders.emailEnabledrequired
boolean—
updates.autoUpdaterequired
boolean—
updates.channelrequired
enum: "stable" | "beta"—
updates.repairModerequired
enum: "repair" | "report"—
integration.publicCatalogueEnabledrequired
boolean—
integration.captchaSiteKeyrequired
string | null1–200 chars
integration.registrationsToLeadsrequired
boolean—
loginDiscovery.staffEmailsrequired
array<string (email)>—
json
{
  "general.name": "string",
  "general.timezone": "string",
  "general.currency": "USD",
  "general.defaultLocale": "ar",
  "general.logoFileId": "5987666b-5987-7987-8876-5987666b5987",
  "general.contactEmail": "ada.lovelace@example.com",
  "general.contactPhone": "string",
  "general.address": "string",
  "attendance.lateThresholdMinutes": 0,
  "attendance.notifyGuardianOnAbsence": true,
  "attendance.warnBelowRate": 0,
  "attendance.criticalBelowRate": 0,
  "grading.scale": "percentage",
  "assessment.autoSendOnPublish": true,
  "billing.invoiceDueDays": 0,
  "billing.allowOverpayment": true,
  "billing.invoicePrefix": "string",
  "billing.autoInvoiceOnEnrollment": true,
  "notifications.smsEnabled": true,
  "notifications.digestHourLocal": 0,
  "notifications.quietHours": {
    "start": "string",
    "end": "string"
  },
  "notifications.email.senderMode": "platform",
  "notifications.email.displayName": "string",
  "notifications.email.replyTo": "ada.lovelace@example.com",
  "notifications.paidEmail.invoiceIssued": true,
  "notifications.paidEmail.invoiceOverdue": true,
  "notifications.paidEmail.paymentReceipt": true,
  "notifications.paidEmail.enrollmentWelcome": true,
  "notifications.paidEmail.examPublished": true,
  "notifications.paidEmail.courseCompleted": true,
  "notifications.paidEmail.assignmentPublished": true,
  "notifications.paidEmail.assignmentSubmitted": true,
  "notifications.paidEmail.assignmentGraded": true,
  "notifications.paidEmail.quizPublished": true,
  "notifications.paidEmail.quizSubmitted": true,
  "notifications.paidEmail.quizGraded": true,
  "notifications.paidEmail.digestEnabled": true,
  "notifications.channelLadder": [
    "push"
  ],
  "curriculum.autoCompleteThresholdPercent": 50,
  "curriculum.notifyOnLessonPublished": true,
  "reminders.classStartsSoon": true,
  "reminders.workDueTomorrow": true,
  "reminders.emailEnabled": true,
  "updates.autoUpdate": true,
  "updates.channel": "stable",
  "updates.repairMode": "repair",
  "integration.publicCatalogueEnabled": true,
  "integration.captchaSiteKey": "string",
  "integration.registrationsToLeads": true,
  "loginDiscovery.staffEmails": [
    "ada.lovelace@example.com"
  ]
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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.

428An API-key caller must send an `Idempotency-Key` header (`IDEMPOTENCY_KEY_REQUIRED`).

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/subscription

This tenant’s subscription: plan, status, current period, lock timestamp, and plan limits. Always readable, even while locked.

Requires authenticationScopeNo additional permission

curl example

curl
curl -X GET "https://your-institute.example/api/v1/subscription" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The tenant’s subscription.
NameTypeConstraints
planrequired
object—
statusrequired
enum: "trialing" | "active" | "expired" | "suspended" | "cancelled"—
currentPeriodStartrequired
string (date-time)—
currentPeriodEndrequired
string (date-time)—
lockedAtrequired
string (date-time) | null—
limitsrequired
PlanLimits—
json
{
  "plan": {
    "id": "37386ae0-3738-7738-8386-37386ae03738",
    "code": "string",
    "name": "Algebra I"
  },
  "status": "trialing",
  "currentPeriodStart": "2026-03-02T09:00:00.000Z",
  "currentPeriodEnd": "2026-03-02T09:00:00.000Z",
  "lockedAt": "2026-03-02T09:00:00.000Z",
  "limits": {
    "maxStudents": -9007199254740991,
    "maxBranches": -9007199254740991,
    "maxVideoCourses": -9007199254740991,
    "maxLessonsPerCourse": -9007199254740991,
    "notificationQuota": {
      "whatsapp": -9007199254740991,
      "sms": -9007199254740991,
      "email": "ada.lovelace@example.com"
    }
  }
}
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.

402The tenant’s subscription or license is locked (`PAYMENT_REQUIRED`, `SUBSCRIPTION_SUSPENDED`).

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/tenants/{tenantId}/branding

The institute's public branding for the installable app: display name, default language and whether it has a logo. Anonymous; an unknown or inactive institute is a 404.

No authenticationScopePublic

Path & query parameters

NameInTypeConstraints
tenantIdrequired
pathstring—

curl example

curl
curl -X GET "https://your-institute.example/api/v1/tenants/4332af8b-4332-7332-832a-4332af8b4332/branding" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
namerequired
string—
defaultLocalerequired
enum: "ar" | "en" | "he"—
hasLogorequired
boolean—
json
{
  "name": "Algebra I",
  "defaultLocale": "ar",
  "hasLogo": 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.

The institute's logo bytes (PNG, JPEG or WebP, at most 5 MB). Anonymous; 404 when the institute is unknown or inactive or has no logo.

No authenticationScopePublic

Path & query parameters

NameInTypeConstraints
tenantIdrequired
pathstring—

curl example

curl
curl -X GET "https://your-institute.example/api/v1/tenants/4332af8b-4332-7332-832a-4332af8b4332/branding/logo" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The logo image.

The API's OpenAPI spec doesn't declare a typed schema for this response yet — it's still JSON, just not documented here.

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.