academics

Academics

Course categories, courses, teaching groups, weekly schedules, generated sessions, and enrollments.

28 endpoints

GET /api/v1/course-categories

The tenant’s course categories, nested as a tree under their parent.

Requires authenticationScopecourses.read

curl example

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

Responses

200
json
[
  {
    "id": "37386ae0-3738-7738-8386-37386ae03738",
    "parentId": "06523528-0652-7652-8523-065235280652",
    "name": "Algebra I",
    "slug": "string",
    "sortOrder": -9007199254740991,
    "isActive": true,
    "createdAt": "2026-03-02T09:00:00.000Z",
    "updatedAt": "2026-03-02T09:00:00.000Z",
    "children": [
      null
    ]
  }
]
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/course-categories

Create a course category.

Requires authenticationScopecourses.write

Request body

NameTypeConstraints
parentId
string (uuid)
namerequired
string1–150 chars
slugrequired
string1–150 chars
sortOrder
integer-9007199254740991–9007199254740991 · default: 0
isActive
booleandefault: true

Example

json
{
  "parentId": "06523528-0652-7652-8523-065235280652",
  "name": "Algebra I",
  "slug": "string",
  "sortOrder": 0,
  "isActive": true
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/course-categories" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "parentId": "06523528-0652-7652-8523-065235280652",
    "name": "Algebra I",
    "slug": "string",
    "sortOrder": 0,
    "isActive": true
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
parentIdrequired
string (uuid) | null
namerequired
string
slugrequired
string
sortOrderrequired
integer-9007199254740991–9007199254740991
isActiverequired
boolean
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "parentId": "06523528-0652-7652-8523-065235280652",
  "name": "Algebra I",
  "slug": "string",
  "sortOrder": -9007199254740991,
  "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/course-categories/{id}

Delete a course category. Fails with 409 if it has child categories or courses.

Requires authenticationScopecourses.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X DELETE "https://api.yourdomain.com/api/v1/course-categories/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The category 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.

GET /api/v1/course-categories/{id}

Get one course category.

Requires authenticationScopecourses.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/course-categories/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
idrequired
string (uuid)
parentIdrequired
string (uuid) | null
namerequired
string
slugrequired
string
sortOrderrequired
integer-9007199254740991–9007199254740991
isActiverequired
boolean
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "parentId": "06523528-0652-7652-8523-065235280652",
  "name": "Algebra I",
  "slug": "string",
  "sortOrder": -9007199254740991,
  "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.

PATCH /api/v1/course-categories/{id}

Update a course category (name, parent, sort order, active flag).

Requires authenticationScopecourses.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
parentId
string (uuid) | null
name
string1–150 chars
slug
string1–150 chars
sortOrder
integer-9007199254740991–9007199254740991 · default: 0
isActive
booleandefault: true

Example

json
{
  "parentId": "06523528-0652-7652-8523-065235280652",
  "name": "Algebra I",
  "slug": "string",
  "sortOrder": 0,
  "isActive": true
}

curl example

curl
curl -X PATCH "https://api.yourdomain.com/api/v1/course-categories/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "parentId": "06523528-0652-7652-8523-065235280652",
    "name": "Algebra I",
    "slug": "string",
    "sortOrder": 0,
    "isActive": true
  }'

Responses

200
NameTypeConstraints
idrequired
string (uuid)
parentIdrequired
string (uuid) | null
namerequired
string
slugrequired
string
sortOrderrequired
integer-9007199254740991–9007199254740991
isActiverequired
boolean
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "parentId": "06523528-0652-7652-8523-065235280652",
  "name": "Algebra I",
  "slug": "string",
  "sortOrder": -9007199254740991,
  "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/courses

List courses (cursor-paginated, filter by category/active).

Requires authenticationScopecourses.read

Path & query parameters

NameInTypeConstraints
cursor
querystring
limit
queryinteger1–100 · default: 25
categoryId
querystring (uuid)
isActive
queryboolean

curl example

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

Responses

200
NameTypeConstraints
datarequired
array<object>
nextCursorrequired
string | null
json
{
  "data": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "categoryId": "786111a4-7861-7861-8611-786111a47861",
      "code": "string",
      "name": "Algebra I",
      "description": "A short, human-readable description.",
      "level": "string",
      "defaultFeeMinor": -9007199254740991,
      "currency": "ILS",
      "defaultCapacity": -9007199254740991,
      "color": "string",
      "isActive": true,
      "isPublic": true,
      "language": "string",
      "deliveryMode": "group",
      "createdAt": "2026-03-02T09:00:00.000Z",
      "updatedAt": "2026-03-02T09:00:00.000Z"
    }
  ],
  "nextCursor": null
}
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/courses

Create a course.

Requires authenticationScopecourses.write

Request body

NameTypeConstraints
categoryId
string (uuid)
code
string | string
namerequired
string1–200 chars
description
string | string
level
string | string
defaultFeeMinor
integer0–9007199254740991
currency
enum: "ILS" | "USD" | "EUR"default: "ILS"
defaultCapacity
integer1–9007199254740991
color
string | string
isActive
booleandefault: true
isPublic
booleandefault: false
language
string | string
deliveryMode
enum: "group" | "self_paced"default: "group"

Example

json
{
  "categoryId": "786111a4-7861-7861-8611-786111a47861",
  "code": "string",
  "name": "Algebra I",
  "description": "A short, human-readable description.",
  "level": "string",
  "defaultFeeMinor": 0,
  "currency": "ILS",
  "defaultCapacity": 1,
  "color": "string",
  "isActive": true,
  "isPublic": false,
  "language": "string",
  "deliveryMode": "group"
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/courses" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "categoryId": "786111a4-7861-7861-8611-786111a47861",
    "code": "string",
    "name": "Algebra I",
    "description": "A short, human-readable description.",
    "level": "string",
    "defaultFeeMinor": 0,
    "currency": "ILS",
    "defaultCapacity": 1,
    "color": "string",
    "isActive": true,
    "isPublic": false,
    "language": "string",
    "deliveryMode": "group"
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
categoryIdrequired
string (uuid) | null
coderequired
string | null≥1 chars
namerequired
string
descriptionrequired
string | null≥1 chars
levelrequired
string | null≥1 chars
defaultFeeMinorrequired
integer | null-9007199254740991–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
defaultCapacityrequired
integer | null-9007199254740991–9007199254740991
colorrequired
string | null≥1 chars
isActiverequired
boolean
isPublicrequired
boolean
languagerequired
string | null≥1 chars
deliveryModerequired
enum: "group" | "self_paced"
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "categoryId": "786111a4-7861-7861-8611-786111a47861",
  "code": "string",
  "name": "Algebra I",
  "description": "A short, human-readable description.",
  "level": "string",
  "defaultFeeMinor": -9007199254740991,
  "currency": "ILS",
  "defaultCapacity": -9007199254740991,
  "color": "string",
  "isActive": true,
  "isPublic": true,
  "language": "string",
  "deliveryMode": "group",
  "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/courses/{id}

Delete a course. If any group references it, it is deactivated instead of deleted.

Requires authenticationScopecourses.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X DELETE "https://api.yourdomain.com/api/v1/courses/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The course was deleted or deactivated.
NameTypeConstraints
okrequired
enum: true
deactivatedrequired
boolean
json
{
  "ok": true,
  "deactivated": 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/courses/{id}

Get one course.

Requires authenticationScopecourses.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/courses/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
idrequired
string (uuid)
categoryIdrequired
string (uuid) | null
coderequired
string | null≥1 chars
namerequired
string
descriptionrequired
string | null≥1 chars
levelrequired
string | null≥1 chars
defaultFeeMinorrequired
integer | null-9007199254740991–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
defaultCapacityrequired
integer | null-9007199254740991–9007199254740991
colorrequired
string | null≥1 chars
isActiverequired
boolean
isPublicrequired
boolean
languagerequired
string | null≥1 chars
deliveryModerequired
enum: "group" | "self_paced"
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "categoryId": "786111a4-7861-7861-8611-786111a47861",
  "code": "string",
  "name": "Algebra I",
  "description": "A short, human-readable description.",
  "level": "string",
  "defaultFeeMinor": -9007199254740991,
  "currency": "ILS",
  "defaultCapacity": -9007199254740991,
  "color": "string",
  "isActive": true,
  "isPublic": true,
  "language": "string",
  "deliveryMode": "group",
  "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.

PATCH /api/v1/courses/{id}

Update a course.

Requires authenticationScopecourses.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
categoryId
string (uuid) | null
code
enum: "" | string | null
name
string1–200 chars
description
enum: "" | string | null
level
enum: "" | string | null
defaultFeeMinor
integer0–9007199254740991
currency
enum: "ILS" | "USD" | "EUR"default: "ILS"
defaultCapacity
integer1–9007199254740991
color
enum: "" | string | null
isActive
booleandefault: true
isPublic
booleandefault: false
language
enum: "" | string | null
deliveryMode
enum: "group" | "self_paced"default: "group"

Example

json
{
  "categoryId": "786111a4-7861-7861-8611-786111a47861",
  "code": "",
  "name": "Algebra I",
  "description": "",
  "level": "",
  "defaultFeeMinor": 0,
  "currency": "ILS",
  "defaultCapacity": 1,
  "color": "",
  "isActive": true,
  "isPublic": false,
  "language": "",
  "deliveryMode": "group"
}

curl example

curl
curl -X PATCH "https://api.yourdomain.com/api/v1/courses/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "categoryId": "786111a4-7861-7861-8611-786111a47861",
    "code": "",
    "name": "Algebra I",
    "description": "",
    "level": "",
    "defaultFeeMinor": 0,
    "currency": "ILS",
    "defaultCapacity": 1,
    "color": "",
    "isActive": true,
    "isPublic": false,
    "language": "",
    "deliveryMode": "group"
  }'

Responses

200
NameTypeConstraints
idrequired
string (uuid)
categoryIdrequired
string (uuid) | null
coderequired
string | null≥1 chars
namerequired
string
descriptionrequired
string | null≥1 chars
levelrequired
string | null≥1 chars
defaultFeeMinorrequired
integer | null-9007199254740991–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
defaultCapacityrequired
integer | null-9007199254740991–9007199254740991
colorrequired
string | null≥1 chars
isActiverequired
boolean
isPublicrequired
boolean
languagerequired
string | null≥1 chars
deliveryModerequired
enum: "group" | "self_paced"
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "categoryId": "786111a4-7861-7861-8611-786111a47861",
  "code": "string",
  "name": "Algebra I",
  "description": "A short, human-readable description.",
  "level": "string",
  "defaultFeeMinor": -9007199254740991,
  "currency": "ILS",
  "defaultCapacity": -9007199254740991,
  "color": "string",
  "isActive": true,
  "isPublic": true,
  "language": "string",
  "deliveryMode": "group",
  "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.

POST /api/v1/enrollments

Enroll a student into a group: capacity-checked, price snapshotted from the group/course fee, emits `enrollment.created`.

Requires authenticationScopeenrollments.write

Request body

NameTypeConstraints
studentIdrequired
string (uuid)
groupIdrequired
string (uuid)
priceMinor
integer0–9007199254740991
currency
enum: "ILS" | "USD" | "EUR"
discountMinor
integer0–9007199254740991 · default: 0
discountReason
string | string

Example

json
{
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "priceMinor": 12000,
  "currency": "ILS",
  "discountMinor": 0,
  "discountReason": "string"
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/enrollments" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
    "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
    "priceMinor": 12000,
    "currency": "ILS",
    "discountMinor": 0,
    "discountReason": "string"
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
studentIdrequired
string (uuid)
groupIdrequired
string (uuid)
statusrequired
enum: "pending" | "active" | "completed" | "dropped"
enrolledAtrequired
string (date-time)
endedAtrequired
string (date-time) | null
priceMinorrequired
integer-9007199254740991–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
discountMinorrequired
integer-9007199254740991–9007199254740991
discountReasonrequired
string | null≥1 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "status": "pending",
  "enrolledAt": "2026-03-02T09:00:00.000Z",
  "endedAt": "2026-03-02T09:00:00.000Z",
  "priceMinor": 12000,
  "currency": "ILS",
  "discountMinor": -9007199254740991,
  "discountReason": "string",
  "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.

POST /api/v1/enrollments/{id}/complete

Mark an enrollment as completed.

Requires authenticationScopeenrollments.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/enrollments/37386ae0-3738-7738-8386-37386ae03738/complete" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
idrequired
string (uuid)
studentIdrequired
string (uuid)
groupIdrequired
string (uuid)
statusrequired
enum: "pending" | "active" | "completed" | "dropped"
enrolledAtrequired
string (date-time)
endedAtrequired
string (date-time) | null
priceMinorrequired
integer-9007199254740991–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
discountMinorrequired
integer-9007199254740991–9007199254740991
discountReasonrequired
string | null≥1 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "status": "pending",
  "enrolledAt": "2026-03-02T09:00:00.000Z",
  "endedAt": "2026-03-02T09:00:00.000Z",
  "priceMinor": 12000,
  "currency": "ILS",
  "discountMinor": -9007199254740991,
  "discountReason": "string",
  "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.

POST /api/v1/enrollments/{id}/drop

Drop an enrollment. Emits `enrollment.dropped`.

Requires authenticationScopeenrollments.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
reason
string0–500 chars

Example

json
{
  "reason": "Requested by guardian."
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/enrollments/37386ae0-3738-7738-8386-37386ae03738/drop" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "reason": "Requested by guardian."
  }'

Responses

200
NameTypeConstraints
idrequired
string (uuid)
studentIdrequired
string (uuid)
groupIdrequired
string (uuid)
statusrequired
enum: "pending" | "active" | "completed" | "dropped"
enrolledAtrequired
string (date-time)
endedAtrequired
string (date-time) | null
priceMinorrequired
integer-9007199254740991–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
discountMinorrequired
integer-9007199254740991–9007199254740991
discountReasonrequired
string | null≥1 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "status": "pending",
  "enrolledAt": "2026-03-02T09:00:00.000Z",
  "endedAt": "2026-03-02T09:00:00.000Z",
  "priceMinor": 12000,
  "currency": "ILS",
  "discountMinor": -9007199254740991,
  "discountReason": "string",
  "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.

POST /api/v1/enrollments/{id}/transfer

Transfer an enrollment to another group: drops the source and creates a new one, in one transaction.

Requires authenticationScopeenrollments.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
toGroupIdrequired
string (uuid)

Example

json
{
  "toGroupId": "6d0ea93a-6d0e-7d0e-80ea-6d0ea93a6d0e"
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/enrollments/37386ae0-3738-7738-8386-37386ae03738/transfer" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "toGroupId": "6d0ea93a-6d0e-7d0e-80ea-6d0ea93a6d0e"
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
studentIdrequired
string (uuid)
groupIdrequired
string (uuid)
statusrequired
enum: "pending" | "active" | "completed" | "dropped"
enrolledAtrequired
string (date-time)
endedAtrequired
string (date-time) | null
priceMinorrequired
integer-9007199254740991–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
discountMinorrequired
integer-9007199254740991–9007199254740991
discountReasonrequired
string | null≥1 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "status": "pending",
  "enrolledAt": "2026-03-02T09:00:00.000Z",
  "endedAt": "2026-03-02T09:00:00.000Z",
  "priceMinor": 12000,
  "currency": "ILS",
  "discountMinor": -9007199254740991,
  "discountReason": "string",
  "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/groups

List groups (cursor-paginated). A `groups.write`-less caller (e.g. a teacher) only sees groups they teach.

Requires authenticationScopegroups.read

Path & query parameters

NameInTypeConstraints
cursor
querystring
limit
queryinteger1–100 · default: 25
branchId
querystring (uuid)
courseId
querystring (uuid)
status
queryenum: "planned" | "active" | "completed" | "cancelled"
teacherStaffId
querystring (uuid)

curl example

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

Responses

200
NameTypeConstraints
datarequired
array<object>
nextCursorrequired
string | null
json
{
  "data": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "branchId": "390b8975-390b-790b-80b8-390b8975390b",
      "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
      "name": "Algebra I",
      "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
      "capacity": -9007199254740991,
      "startDate": "2026-03-02",
      "endDate": "2026-03-02",
      "status": "planned",
      "feeMinor": -9007199254740991,
      "room": "string",
      "createdAt": "2026-03-02T09:00:00.000Z",
      "updatedAt": "2026-03-02T09:00:00.000Z"
    }
  ],
  "nextCursor": null
}
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/groups

Create a group, optionally with its initial weekly schedules.

Requires authenticationScopegroups.write

Request body

NameTypeConstraints
branchIdrequired
string (uuid)
courseIdrequired
string (uuid)
namerequired
string1–150 chars
teacherStaffId
string (uuid)
capacity
integer1–9007199254740991
startDaterequired
string (date)
endDate
string | string (date)
status
enum: "planned" | "active" | "completed" | "cancelled"default: "planned"
feeMinor
integer0–9007199254740991
room
string | string
schedules
array<object>

Example

json
{
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "name": "Algebra I",
  "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
  "capacity": 1,
  "startDate": "2026-03-02",
  "endDate": "string",
  "status": "planned",
  "feeMinor": 0,
  "room": "string",
  "schedules": [
    {
      "weekday": 0,
      "startTime": "string",
      "endTime": "string",
      "validFrom": "2026-03-02",
      "validTo": "string"
    }
  ]
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/groups" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "branchId": "390b8975-390b-790b-80b8-390b8975390b",
    "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
    "name": "Algebra I",
    "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
    "capacity": 1,
    "startDate": "2026-03-02",
    "endDate": "string",
    "status": "planned",
    "feeMinor": 0,
    "room": "string",
    "schedules": [
      {
        "weekday": 0,
        "startTime": "string",
        "endTime": "string",
        "validFrom": "2026-03-02",
        "validTo": "string"
      }
    ]
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
courseIdrequired
string (uuid)
namerequired
string
teacherStaffIdrequired
string (uuid) | null
capacityrequired
integer | null-9007199254740991–9007199254740991
startDaterequired
string (date)
endDaterequired
string (date) | null
statusrequired
enum: "planned" | "active" | "completed" | "cancelled"
feeMinorrequired
integer | null-9007199254740991–9007199254740991
roomrequired
string | null≥1 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "name": "Algebra I",
  "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
  "capacity": -9007199254740991,
  "startDate": "2026-03-02",
  "endDate": "2026-03-02",
  "status": "planned",
  "feeMinor": -9007199254740991,
  "room": "string",
  "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/groups/{id}

Delete a group. Fails with 409 if it has enrollments or sessions.

Requires authenticationScopegroups.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X DELETE "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200The group 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.

GET /api/v1/groups/{id}

Get one group.

Requires authenticationScopegroups.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
courseIdrequired
string (uuid)
namerequired
string
teacherStaffIdrequired
string (uuid) | null
capacityrequired
integer | null-9007199254740991–9007199254740991
startDaterequired
string (date)
endDaterequired
string (date) | null
statusrequired
enum: "planned" | "active" | "completed" | "cancelled"
feeMinorrequired
integer | null-9007199254740991–9007199254740991
roomrequired
string | null≥1 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "name": "Algebra I",
  "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
  "capacity": -9007199254740991,
  "startDate": "2026-03-02",
  "endDate": "2026-03-02",
  "status": "planned",
  "feeMinor": -9007199254740991,
  "room": "string",
  "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.

PATCH /api/v1/groups/{id}

Update a group (including status transitions).

Requires authenticationScopegroups.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
branchId
string (uuid)
courseId
string (uuid)
name
string1–150 chars
teacherStaffId
string (uuid) | null
capacity
integer1–9007199254740991
startDate
string (date)
endDate
string (date) | null
status
enum: "planned" | "active" | "completed" | "cancelled"default: "planned"
feeMinor
integer | null0–9007199254740991
room
enum: "" | string | null

Example

json
{
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "name": "Algebra I",
  "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
  "capacity": 1,
  "startDate": "2026-03-02",
  "endDate": "2026-03-02",
  "status": "planned",
  "feeMinor": 0,
  "room": ""
}

curl example

curl
curl -X PATCH "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "branchId": "390b8975-390b-790b-80b8-390b8975390b",
    "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
    "name": "Algebra I",
    "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
    "capacity": 1,
    "startDate": "2026-03-02",
    "endDate": "2026-03-02",
    "status": "planned",
    "feeMinor": 0,
    "room": ""
  }'

Responses

200
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
courseIdrequired
string (uuid)
namerequired
string
teacherStaffIdrequired
string (uuid) | null
capacityrequired
integer | null-9007199254740991–9007199254740991
startDaterequired
string (date)
endDaterequired
string (date) | null
statusrequired
enum: "planned" | "active" | "completed" | "cancelled"
feeMinorrequired
integer | null-9007199254740991–9007199254740991
roomrequired
string | null≥1 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "name": "Algebra I",
  "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
  "capacity": -9007199254740991,
  "startDate": "2026-03-02",
  "endDate": "2026-03-02",
  "status": "planned",
  "feeMinor": -9007199254740991,
  "room": "string",
  "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/groups/{id}/enrollments

List a group’s enrollments (cursor-paginated).

Requires authenticationScopeenrollments.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring
cursor
querystring
limit
queryinteger1–100 · default: 25

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738/enrollments" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
datarequired
array<object>
nextCursorrequired
string | null
json
{
  "data": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
      "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
      "status": "pending",
      "enrolledAt": "2026-03-02T09:00:00.000Z",
      "endedAt": "2026-03-02T09:00:00.000Z",
      "priceMinor": 12000,
      "currency": "ILS",
      "discountMinor": -9007199254740991,
      "discountReason": "string",
      "createdAt": "2026-03-02T09:00:00.000Z",
      "updatedAt": "2026-03-02T09:00:00.000Z"
    }
  ],
  "nextCursor": null
}
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/groups/{id}/schedules

List a group’s weekly schedule rules.

Requires authenticationScopegroups.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738/schedules" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
json
[
  {
    "id": "37386ae0-3738-7738-8386-37386ae03738",
    "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
    "weekday": 0,
    "startTime": "string",
    "endTime": "string",
    "validFrom": "2026-03-02",
    "validTo": "2026-03-02"
  }
]
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.

PUT /api/v1/groups/{id}/schedules

Replace a group’s weekly schedule rules and regenerate its upcoming sessions from them.

Requires authenticationScopegroups.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
schedulesrequired
array<object>

Example

json
{
  "schedules": [
    {
      "weekday": 0,
      "startTime": "string",
      "endTime": "string",
      "validFrom": "2026-03-02",
      "validTo": "string"
    }
  ]
}

curl example

curl
curl -X PUT "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738/schedules" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "schedules": [
      {
        "weekday": 0,
        "startTime": "string",
        "endTime": "string",
        "validFrom": "2026-03-02",
        "validTo": "string"
      }
    ]
  }'

Responses

200
json
[
  {
    "id": "37386ae0-3738-7738-8386-37386ae03738",
    "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
    "weekday": 0,
    "startTime": "string",
    "endTime": "string",
    "validFrom": "2026-03-02",
    "validTo": "2026-03-02"
  }
]
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/groups/{id}/sessions

List a group’s sessions (cursor-paginated, optional date range and status filter — `?status=scheduled` or repeated `status=` for several).

Requires authenticationScopegroups.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring
cursor
querystring
limit
queryinteger1–100 · default: 25
from
querystring (date-time)
to
querystring (date-time)
status
queryenum: "scheduled" | "held" | "cancelled" | array<enum: "scheduled" | "held" | "cancelled">

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738/sessions" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
datarequired
array<object>
nextCursorrequired
string | null
json
{
  "data": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
      "scheduledStart": "2026-03-02T09:00:00.000Z",
      "scheduledEnd": "2026-03-02T09:00:00.000Z",
      "status": "scheduled",
      "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
      "topic": "string",
      "notes": "Prefers afternoon sessions.",
      "lessonId": "3d477cf4-3d47-7d47-8477-3d477cf43d47",
      "createdAt": "2026-03-02T09:00:00.000Z",
      "updatedAt": "2026-03-02T09:00:00.000Z"
    }
  ],
  "nextCursor": null
}
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/groups/{id}/sessions/generate

Materialize this group’s sessions from its schedule rules for the rolling window.

Requires authenticationScopegroups.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
until
string (date)

Example

json
{
  "until": "2026-03-02"
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/groups/37386ae0-3738-7738-8386-37386ae03738/sessions/generate" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "until": "2026-03-02"
  }'

Responses

201
NameTypeConstraints
createdrequired
integer0–9007199254740991
totalrequired
integer0–9007199254740991
json
{
  "created": 0,
  "total": 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.

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/me/schedule

The caller’s own weekly schedule: sessions of groups they teach, are enrolled in, or their children are enrolled in.

Requires authenticationScopeNo additional permission

Path & query parameters

NameInTypeConstraints
fromrequired
querystring (date)
torequired
querystring (date)

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/me/schedule?from=2026-03-02&to=2026-03-02" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
json
[
  {
    "sessionId": "736a51cd-736a-736a-86a5-736a51cd736a",
    "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
    "groupName": "string",
    "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
    "courseName": "string",
    "scheduledStart": "2026-03-02T09:00:00.000Z",
    "scheduledEnd": "2026-03-02T09:00:00.000Z",
    "status": "scheduled",
    "relation": "teacher",
    "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7"
  }
]
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/me/teaching/today

Today’s sessions for the calling teacher, each with roster size, marked count and attendance state, plus a backlog of past held sessions with no attendance recorded.

Requires authenticationScopeNo additional permission

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/me/teaching/today" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
daterequired
string (date)
timezonerequired
string
staffIdrequired
string (uuid) | null
sessionsrequired
array<object>
unmarkedBacklogrequired
array<object>
json
{
  "date": "2026-03-02",
  "timezone": "string",
  "staffId": "489fc644-489f-789f-89fc-489fc644489f",
  "sessions": [
    {
      "sessionId": "736a51cd-736a-736a-86a5-736a51cd736a",
      "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
      "groupName": "string",
      "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
      "courseName": "string",
      "scheduledStart": "2026-03-02T09:00:00.000Z",
      "scheduledEnd": "2026-03-02T09:00:00.000Z",
      "status": "scheduled",
      "rosterCount": 0,
      "markedCount": 0,
      "attendanceState": "unmarked"
    }
  ],
  "unmarkedBacklog": [
    {
      "sessionId": "736a51cd-736a-736a-86a5-736a51cd736a",
      "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
      "groupName": "string",
      "scheduledStart": "2026-03-02T09:00:00.000Z",
      "scheduledEnd": "2026-03-02T09:00:00.000Z",
      "rosterCount": 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.

PATCH /api/v1/sessions/{id}

Update a session: cancel it (with a reason, emits `session.cancelled`), or set its topic/notes/substitute teacher.

Requires authenticationScopegroups.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
status
enum: "cancelled"
reason
string0–500 chars
topic
enum: "" | string | null
notes
enum: "" | string | null
teacherStaffId
string (uuid) | null
lessonId
string (uuid) | null

Example

json
{
  "status": "cancelled",
  "reason": "Requested by guardian.",
  "topic": "",
  "notes": "",
  "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
  "lessonId": "3d477cf4-3d47-7d47-8477-3d477cf43d47"
}

curl example

curl
curl -X PATCH "https://api.yourdomain.com/api/v1/sessions/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "status": "cancelled",
    "reason": "Requested by guardian.",
    "topic": "",
    "notes": "",
    "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
    "lessonId": "3d477cf4-3d47-7d47-8477-3d477cf43d47"
  }'

Responses

200
NameTypeConstraints
idrequired
string (uuid)
groupIdrequired
string (uuid)
scheduledStartrequired
string (date-time)
scheduledEndrequired
string (date-time)
statusrequired
enum: "scheduled" | "held" | "cancelled"
teacherStaffIdrequired
string (uuid) | null
topicrequired
string | null≥1 chars
notesrequired
string | null≥1 chars
lessonIdrequired
string (uuid) | null
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "scheduledStart": "2026-03-02T09:00:00.000Z",
  "scheduledEnd": "2026-03-02T09:00:00.000Z",
  "status": "scheduled",
  "teacherStaffId": "22f9eb14-22f9-72f9-8f9e-22f9eb1422f9",
  "topic": "string",
  "notes": "Prefers afternoon sessions.",
  "lessonId": "3d477cf4-3d47-7d47-8477-3d477cf43d47",
  "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/students/{id}/enrollments

List a student’s enrollments (cursor-paginated).

Requires authenticationScopeenrollments.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring
cursor
querystring
limit
queryinteger1–100 · default: 25

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/students/37386ae0-3738-7738-8386-37386ae03738/enrollments" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
datarequired
array<object>
nextCursorrequired
string | null
json
{
  "data": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
      "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
      "status": "pending",
      "enrolledAt": "2026-03-02T09:00:00.000Z",
      "endedAt": "2026-03-02T09:00:00.000Z",
      "priceMinor": 12000,
      "currency": "ILS",
      "discountMinor": -9007199254740991,
      "discountReason": "string",
      "createdAt": "2026-03-02T09:00:00.000Z",
      "updatedAt": "2026-03-02T09:00:00.000Z"
    }
  ],
  "nextCursor": null
}
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.