# Settings & Branches

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

Generated from `apps/api/openapi.json`. HTML version: https://docs.institflow.com/en/reference/tenancy

18 operations.

## GET /api/v1/branches

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

- Operation id: `BranchesController_list_v1`
- Permission: —
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The 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"
  }
]
```

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## POST /api/v1/branches

Create a branch. Names must be unique per tenant.

- Operation id: `BranchesController_create_v1`
- Permission: `branches.manage`
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Request body

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `name` | string | yes | 1–200 chars |
| `code` | enum: "" \| string | no |  |
| `address` | object | no |  |
| `phone` | enum: "" \| string | no |  |
| `isDefault` | boolean | no |  |

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

### Responses

**201** — The newly created branch.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `id` | string (uuid) | yes |  |
| `tenantId` | string (uuid) | yes |  |
| `name` | string | yes |  |
| `code` | string \| null | yes | ≥1 chars |
| `address` | object \| null | yes |  |
| `phone` | string \| null | yes | ≥1 chars |
| `isDefault` | boolean | yes |  |
| `isActive` | boolean | yes |  |
| `createdAt` | string (date-time) | yes |  |
| `updatedAt` | string (date-time) | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

```bash
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
  }'
```

## DELETE /api/v1/branches/{id}

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

- Operation id: `BranchesController_remove_v1`
- Permission: `branches.manage`
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes |  |

### Responses

**200** — The branch was deleted.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `ok` | enum: true | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## PATCH /api/v1/branches/{id}

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

- Operation id: `BranchesController_update_v1`
- Permission: `branches.manage`
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `id` | path | string | yes |  |

### Request body

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `name` | string | no | 1–200 chars |
| `code` | enum: "" \| string \| null | no |  |
| `address` | object \| null | no |  |
| `phone` | enum: "" \| string \| null | no |  |
| `isDefault` | boolean | no |  |
| `isActive` | boolean | no |  |

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

### Responses

**200** — The updated branch.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `id` | string (uuid) | yes |  |
| `tenantId` | string (uuid) | yes |  |
| `name` | string | yes |  |
| `code` | string \| null | yes | ≥1 chars |
| `address` | object \| null | yes |  |
| `phone` | string \| null | yes | ≥1 chars |
| `isDefault` | boolean | yes |  |
| `isActive` | boolean | yes |  |
| `createdAt` | string (date-time) | yes |  |
| `updatedAt` | string (date-time) | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

```bash
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
  }'
```

## GET /api/v1/feature-flags

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

- Operation id: `FeatureFlagsController_get_v1`
- Permission: —
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The tenant’s effective feature flags.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `basic_reports` | boolean | yes |  |
| `advanced_reports` | boolean | yes |  |
| `integration_api` | boolean | yes |  |
| `mcp` | boolean | yes |  |
| `custom_domain` | boolean | yes |  |
| `whatsapp_notifications` | boolean | yes |  |
| `sms_notifications` | boolean | yes |  |
| `byo_email_provider` | boolean | yes |  |
| `byo_push_provider` | boolean | yes |  |
| `courses_video` | boolean | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## 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.

- Operation id: `FeatureFlagsController_patch_v1`
- Permission: —
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Request body

```json
{}
```

### Responses

**200** — The tenant’s new effective feature flags.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `basic_reports` | boolean | yes |  |
| `advanced_reports` | boolean | yes |  |
| `integration_api` | boolean | yes |  |
| `mcp` | boolean | yes |  |
| `custom_domain` | boolean | yes |  |
| `whatsapp_notifications` | boolean | yes |  |
| `sms_notifications` | boolean | yes |  |
| `byo_email_provider` | boolean | yes |  |
| `byo_push_provider` | boolean | yes |  |
| `courses_video` | boolean | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

```bash
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 '{}'
```

## GET /api/v1/license

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

- Operation id: `LicenseController_get_v1`
- Permission: —
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The instance’s license summary.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `plan` | string | yes |  |
| `limits` | object | yes |  |
| `features` | array<string> | yes |  |
| `expiresAt` | string (date-time) | yes |  |
| `state` | enum: "valid" \| "expired" \| "locked" \| "revoked" | yes |  |
| `lockedByCommand` | boolean | yes |  |
| `lastServerContactAt` | string (date-time) \| null | yes |  |
| `lastServerTime` | string (date-time) \| null | yes |  |
| `consecutiveFailures` | integer | yes | 0–9007199254740991 |
| `installId` | string | yes |  |
| `tamperSignals` | array<object> | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## POST /api/v1/license/apply-token

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

- Operation id: `LicenseController_applyToken_v1`
- Permission: `settings.manage`
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Request body

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `token` | string | yes | 1–8192 chars |

```json
{
  "token": "string"
}
```

### Responses

**200** — The instance’s license summary after the token was applied.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `plan` | string | yes |  |
| `limits` | object | yes |  |
| `features` | array<string> | yes |  |
| `expiresAt` | string (date-time) | yes |  |
| `state` | enum: "valid" \| "expired" \| "locked" \| "revoked" | yes |  |
| `lockedByCommand` | boolean | yes |  |
| `lastServerContactAt` | string (date-time) \| null | yes |  |
| `lastServerTime` | string (date-time) \| null | yes |  |
| `consecutiveFailures` | integer | yes | 0–9007199254740991 |
| `installId` | string | yes |  |
| `tamperSignals` | array<object> | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

```bash
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"
  }'
```

## GET /api/v1/license/updates

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

- Operation id: `TenantUpdatesController_get_v1`
- Permission: `settings.manage`
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The install’s update status.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `autoUpdate` | boolean | yes |  |
| `channel` | enum: "stable" \| "beta" | yes |  |
| `currentVersion` | string | yes |  |
| `checkRequestedAt` | string (date-time) \| null | yes |  |
| `updatesBlocked` | boolean | yes |  |
| `blockedReason` | string \| null | yes |  |
| `lastCheckAt` | string (date-time) \| null | yes |  |
| `lastResult` | enum: "up_to_date" \| "updated" \| "rolled_back" \| "failed" \| "skipped" \| null \| null | yes |  |
| `reason` | 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 | yes |  |
| `targetVersion` | string \| null | yes |  |
| `detail` | string \| null | yes |  |
| `updaterPresent` | boolean | yes |  |
| `storageUpgradeNeeded` | boolean | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## POST /api/v1/license/updates/check

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

- Operation id: `TenantUpdatesController_check_v1`
- Permission: `settings.manage`
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Responses

**200** — The install’s update status, with the check request recorded.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `autoUpdate` | boolean | yes |  |
| `channel` | enum: "stable" \| "beta" | yes |  |
| `currentVersion` | string | yes |  |
| `checkRequestedAt` | string (date-time) \| null | yes |  |
| `updatesBlocked` | boolean | yes |  |
| `blockedReason` | string \| null | yes |  |
| `lastCheckAt` | string (date-time) \| null | yes |  |
| `lastResult` | enum: "up_to_date" \| "updated" \| "rolled_back" \| "failed" \| "skipped" \| null \| null | yes |  |
| `reason` | 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 | yes |  |
| `targetVersion` | string \| null | yes |  |
| `detail` | string \| null | yes |  |
| `updaterPresent` | boolean | yes |  |
| `storageUpgradeNeeded` | boolean | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## 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.

- Operation id: `OnboardingController_get_v1`
- Permission: `settings.manage`
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The tenant’s onboarding progress.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `steps` | array<object> | yes |  |
| `completedSteps` | integer | yes | 0–9007199254740991 |
| `totalSteps` | integer | yes | 0–9007199254740991 |
| `isComplete` | boolean | yes |  |
| `counts` | object | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## 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.

- Operation id: `RelayStatusController_requestSenderName_v1`
- Permission: `settings.manage`
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Request body

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `displayName` | string | yes | 1–70 chars |

```json
{
  "displayName": "string"
}
```

### Responses

**200** — The relay status after the request was recorded.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `enrolmentStatus` | enum: "unenrolled" \| "pending" \| "approved" \| "blocked" | yes |  |
| `requestedSenderDisplayName` | string \| null | yes | ≥1 chars |
| `lastErrorMessage` | string \| null | yes | ≥1 chars |
| `lastErrorAt` | string (date-time) \| null | yes |  |
| `account` | object \| null | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

```bash
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"
  }'
```

## GET /api/v1/relay/status

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

- Operation id: `RelayStatusController_status_v1`
- Permission: `notifications.manage`
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The relay status.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `enrolmentStatus` | enum: "unenrolled" \| "pending" \| "approved" \| "blocked" | yes |  |
| `requestedSenderDisplayName` | string \| null | yes | ≥1 chars |
| `lastErrorMessage` | string \| null | yes | ≥1 chars |
| `lastErrorAt` | string (date-time) \| null | yes |  |
| `account` | object \| null | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## 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).

- Operation id: `SettingsController_get_v1`
- Permission: —
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The tenant’s effective settings — the full registry, or the member view without `settings.manage`.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `general.name` | string | no | 1–200 chars |
| `general.timezone` | string | no | 1–100 chars |
| `general.currency` | string | no | 3–3 chars |
| `general.defaultLocale` | enum: "ar" \| "en" \| "he" | no |  |
| `general.logoFileId` | string (uuid) \| null | no |  |
| `general.contactEmail` | string (email) \| null | no | 0–320 chars |
| `general.contactPhone` | string \| null | no | 1–50 chars |
| `general.address` | string \| null | no | 1–500 chars |
| `attendance.lateThresholdMinutes` | integer | no | 0–120 |
| `attendance.notifyGuardianOnAbsence` | boolean | no |  |
| `attendance.warnBelowRate` | integer | no | 0–100 |
| `attendance.criticalBelowRate` | integer | no | 0–100 |
| `grading.scale` | enum: "percentage" \| "letter" \| "custom" | no |  |
| `assessment.autoSendOnPublish` | boolean | no |  |
| `billing.invoiceDueDays` | integer | no | 0–365 |
| `billing.allowOverpayment` | boolean | no |  |
| `billing.invoicePrefix` | string | no | 1–10 chars |
| `billing.autoInvoiceOnEnrollment` | boolean | no |  |
| `notifications.smsEnabled` | boolean | no |  |
| `notifications.digestHourLocal` | integer | no | 0–23 |
| `notifications.quietHours` | object \| null | no |  |
| `notifications.email.senderMode` | enum: "platform" \| "institute" | no |  |
| `notifications.email.displayName` | string \| null | no | 1–70 chars |
| `notifications.email.replyTo` | string (email) \| null | no | 0–320 chars |
| `notifications.paidEmail.invoiceIssued` | boolean | no |  |
| `notifications.paidEmail.invoiceOverdue` | boolean | no |  |
| `notifications.paidEmail.paymentReceipt` | boolean | no |  |
| `notifications.paidEmail.enrollmentWelcome` | boolean | no |  |
| `notifications.paidEmail.examPublished` | boolean | no |  |
| `notifications.paidEmail.courseCompleted` | boolean | no |  |
| `notifications.paidEmail.assignmentPublished` | boolean | no |  |
| `notifications.paidEmail.assignmentSubmitted` | boolean | no |  |
| `notifications.paidEmail.assignmentGraded` | boolean | no |  |
| `notifications.paidEmail.quizPublished` | boolean | no |  |
| `notifications.paidEmail.quizSubmitted` | boolean | no |  |
| `notifications.paidEmail.quizGraded` | boolean | no |  |
| `notifications.paidEmail.digestEnabled` | boolean | no |  |
| `notifications.channelLadder` | array<enum: "push" \| "whatsapp" \| "email" \| "sms" \| "in_app"> | no |  |
| `curriculum.autoCompleteThresholdPercent` | integer | no | 50–100 |
| `curriculum.notifyOnLessonPublished` | boolean | no |  |
| `reminders.classStartsSoon` | boolean | no |  |
| `reminders.workDueTomorrow` | boolean | no |  |
| `reminders.emailEnabled` | boolean | no |  |
| `updates.autoUpdate` | boolean | no |  |
| `updates.channel` | enum: "stable" \| "beta" | no |  |
| `updates.repairMode` | enum: "repair" \| "report" | no |  |
| `integration.publicCatalogueEnabled` | boolean | no |  |
| `integration.captchaSiteKey` | string \| null | no | 1–200 chars |
| `integration.registrationsToLeads` | boolean | no |  |
| `loginDiscovery.staffEmails` | array<string (email)> | no |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## 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.

- Operation id: `SettingsController_patch_v1`
- Permission: `settings.manage`
- Auth: credential required
- `Idempotency-Key`: required for API-key callers

### Request body

```json
{}
```

### Responses

**200** — The tenant’s new effective settings.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `general.name` | string | yes | 1–200 chars |
| `general.timezone` | string | yes | 1–100 chars |
| `general.currency` | string | yes | 3–3 chars |
| `general.defaultLocale` | enum: "ar" \| "en" \| "he" | yes |  |
| `general.logoFileId` | string (uuid) \| null | yes |  |
| `general.contactEmail` | string (email) \| null | yes | 0–320 chars |
| `general.contactPhone` | string \| null | yes | 1–50 chars |
| `general.address` | string \| null | yes | 1–500 chars |
| `attendance.lateThresholdMinutes` | integer | yes | 0–120 |
| `attendance.notifyGuardianOnAbsence` | boolean | yes |  |
| `attendance.warnBelowRate` | integer | yes | 0–100 |
| `attendance.criticalBelowRate` | integer | yes | 0–100 |
| `grading.scale` | enum: "percentage" \| "letter" \| "custom" | yes |  |
| `assessment.autoSendOnPublish` | boolean | yes |  |
| `billing.invoiceDueDays` | integer | yes | 0–365 |
| `billing.allowOverpayment` | boolean | yes |  |
| `billing.invoicePrefix` | string | yes | 1–10 chars |
| `billing.autoInvoiceOnEnrollment` | boolean | yes |  |
| `notifications.smsEnabled` | boolean | yes |  |
| `notifications.digestHourLocal` | integer | yes | 0–23 |
| `notifications.quietHours` | object \| null | yes |  |
| `notifications.email.senderMode` | enum: "platform" \| "institute" | yes |  |
| `notifications.email.displayName` | string \| null | yes | 1–70 chars |
| `notifications.email.replyTo` | string (email) \| null | yes | 0–320 chars |
| `notifications.paidEmail.invoiceIssued` | boolean | yes |  |
| `notifications.paidEmail.invoiceOverdue` | boolean | yes |  |
| `notifications.paidEmail.paymentReceipt` | boolean | yes |  |
| `notifications.paidEmail.enrollmentWelcome` | boolean | yes |  |
| `notifications.paidEmail.examPublished` | boolean | yes |  |
| `notifications.paidEmail.courseCompleted` | boolean | yes |  |
| `notifications.paidEmail.assignmentPublished` | boolean | yes |  |
| `notifications.paidEmail.assignmentSubmitted` | boolean | yes |  |
| `notifications.paidEmail.assignmentGraded` | boolean | yes |  |
| `notifications.paidEmail.quizPublished` | boolean | yes |  |
| `notifications.paidEmail.quizSubmitted` | boolean | yes |  |
| `notifications.paidEmail.quizGraded` | boolean | yes |  |
| `notifications.paidEmail.digestEnabled` | boolean | yes |  |
| `notifications.channelLadder` | array<enum: "push" \| "whatsapp" \| "email" \| "sms" \| "in_app"> | yes |  |
| `curriculum.autoCompleteThresholdPercent` | integer | yes | 50–100 |
| `curriculum.notifyOnLessonPublished` | boolean | yes |  |
| `reminders.classStartsSoon` | boolean | yes |  |
| `reminders.workDueTomorrow` | boolean | yes |  |
| `reminders.emailEnabled` | boolean | yes |  |
| `updates.autoUpdate` | boolean | yes |  |
| `updates.channel` | enum: "stable" \| "beta" | yes |  |
| `updates.repairMode` | enum: "repair" \| "report" | yes |  |
| `integration.publicCatalogueEnabled` | boolean | yes |  |
| `integration.captchaSiteKey` | string \| null | yes | 1–200 chars |
| `integration.registrationsToLeads` | boolean | yes |  |
| `loginDiscovery.staffEmails` | array<string (email)> | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

```bash
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 '{}'
```

## GET /api/v1/subscription

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

- Operation id: `SubscriptionController_get_v1`
- Permission: —
- Auth: credential required
- `Idempotency-Key`: not required

### Responses

**200** — The tenant’s subscription.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `plan` | object | yes |  |
| `status` | enum: "trialing" \| "active" \| "expired" \| "suspended" \| "cancelled" | yes |  |
| `currentPeriodStart` | string (date-time) | yes |  |
| `currentPeriodEnd` | string (date-time) | yes |  |
| `lockedAt` | string (date-time) \| null | yes |  |
| `limits` | PlanLimits | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## 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.

- Operation id: `BrandingController_get_v1`
- Permission: —
- Auth: public (no credential)
- `Idempotency-Key`: not required

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `tenantId` | path | string | yes |  |

### Responses

**200** — Success.

| Property | Type | Required | Constraints |
| --- | --- | --- | --- |
| `name` | string | yes |  |
| `defaultLocale` | enum: "ar" \| "en" \| "he" | yes |  |
| `hasLogo` | boolean | yes |  |

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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

## GET /api/v1/tenants/{tenantId}/branding/logo

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.

- Operation id: `BrandingController_logo_v1`
- Permission: —
- Auth: public (no credential)
- `Idempotency-Key`: not required

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `tenantId` | path | string | yes |  |

### Responses

**200** — The logo image.

Every other status answers with the shared `ErrorEnvelope` — see
https://docs.institflow.com/md/en/error-codes.md

### Example request

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