billing

Billing

Fee schedules, invoices, invoice lines, payments, and statements.

22 endpoints

GET /api/v1/billing/summary

Billing dashboard summary: outstanding, collected this month, overdue, by status.

Requires authenticationScopeinvoices.read

curl example

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

Responses

200
NameTypeConstraints
currencyrequired
string3–3 chars
outstandingrequired
Money
collectedThisMonthrequired
Money
overdueCountrequired
integer0–9007199254740991
overdueTotalrequired
Money
byStatusrequired
object
json
{
  "currency": "USD",
  "outstanding": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "collectedThisMonth": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "overdueCount": 0,
  "overdueTotal": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "byStatus": {
    "draft": 0,
    "issued": 0,
    "partially_paid": 0,
    "paid": 0,
    "overdue": 0,
    "void": 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.

GET /api/v1/fee-schedules

List fee schedules (cursor-paginated).

Requires authenticationScopeinvoices.read

Path & query parameters

NameInTypeConstraints
cursor
querystring
limit
queryinteger1–100 · default: 25
kind
queryenum: "per_group" | "per_course" | "one_off" | "registration"
isActive
queryboolean

curl example

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

Responses

200
NameTypeConstraints
datarequired
array<object>
nextCursorrequired
string | null
json
{
  "data": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "name": "Algebra I",
      "kind": "per_group",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "recurrence": "once",
      "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
      "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
      "dueDay": 1,
      "isActive": true,
      "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/fee-schedules

Create a fee schedule.

Requires authenticationScopeinvoices.write

Request body

NameTypeConstraints
namerequired
string1–150 chars
kindrequired
enum: "per_group" | "per_course" | "one_off" | "registration"
amountMinorrequired
integer0–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
recurrencerequired
enum: "once" | "monthly" | "per_term"
courseId
string (uuid)
groupId
string (uuid)
dueDay
integer1–31
isActive
booleandefault: true

Example

json
{
  "name": "Algebra I",
  "kind": "per_group",
  "amountMinor": 12000,
  "currency": "ILS",
  "recurrence": "once",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "dueDay": 1,
  "isActive": true
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/fee-schedules" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Algebra I",
    "kind": "per_group",
    "amountMinor": 12000,
    "currency": "ILS",
    "recurrence": "once",
    "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
    "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
    "dueDay": 1,
    "isActive": true
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
namerequired
string
kindrequired
enum: "per_group" | "per_course" | "one_off" | "registration"
amountrequired
Money
recurrencerequired
enum: "once" | "monthly" | "per_term"
courseIdrequired
string (uuid) | null
groupIdrequired
string (uuid) | null
dueDayrequired
integer | null1–31
isActiverequired
boolean
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "name": "Algebra I",
  "kind": "per_group",
  "amount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "recurrence": "once",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "dueDay": 1,
  "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/fee-schedules/{id}

Delete a fee schedule. Refused (409) if any invoice line still references it.

Requires authenticationScopeinvoices.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200The fee schedule 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/fee-schedules/{id}

Get a fee schedule by id.

Requires authenticationScopeinvoices.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200
NameTypeConstraints
idrequired
string (uuid)
namerequired
string
kindrequired
enum: "per_group" | "per_course" | "one_off" | "registration"
amountrequired
Money
recurrencerequired
enum: "once" | "monthly" | "per_term"
courseIdrequired
string (uuid) | null
groupIdrequired
string (uuid) | null
dueDayrequired
integer | null1–31
isActiverequired
boolean
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "name": "Algebra I",
  "kind": "per_group",
  "amount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "recurrence": "once",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "dueDay": 1,
  "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/fee-schedules/{id}

Update a fee schedule.

Requires authenticationScopeinvoices.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
name
string1–150 chars
kind
enum: "per_group" | "per_course" | "one_off" | "registration"
amountMinor
integer0–9007199254740991
currency
enum: "ILS" | "USD" | "EUR"
recurrence
enum: "once" | "monthly" | "per_term"
courseId
string (uuid)
groupId
string (uuid)
dueDay
integer1–31
isActive
booleandefault: true

Example

json
{
  "name": "Algebra I",
  "kind": "per_group",
  "amountMinor": 12000,
  "currency": "ILS",
  "recurrence": "once",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "dueDay": 1,
  "isActive": true
}

curl example

curl
curl -X PATCH "https://api.yourdomain.com/api/v1/fee-schedules/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "name": "Algebra I",
    "kind": "per_group",
    "amountMinor": 12000,
    "currency": "ILS",
    "recurrence": "once",
    "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
    "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
    "dueDay": 1,
    "isActive": true
  }'

Responses

200
NameTypeConstraints
idrequired
string (uuid)
namerequired
string
kindrequired
enum: "per_group" | "per_course" | "one_off" | "registration"
amountrequired
Money
recurrencerequired
enum: "once" | "monthly" | "per_term"
courseIdrequired
string (uuid) | null
groupIdrequired
string (uuid) | null
dueDayrequired
integer | null1–31
isActiverequired
boolean
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "name": "Algebra I",
  "kind": "per_group",
  "amount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "recurrence": "once",
  "courseId": "d0e4743a-d0e4-70e4-8e47-d0e4743ad0e4",
  "groupId": "6dc7fce6-6dc7-7dc7-8c7f-6dc7fce66dc7",
  "dueDay": 1,
  "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.

POST /api/v1/fee-schedules/{id}/generate

Batch-generate this period's invoices for a "monthly" fee schedule — one per actively-enrolled student, skipping anyone already invoiced for the period. `dryRun: true` previews counts only.

Requires authenticationScopeinvoices.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
periodrequired
string
dryRunrequired
boolean

Example

json
{
  "period": "string",
  "dryRun": true
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/fee-schedules/37386ae0-3738-7738-8386-37386ae03738/generate" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "period": "string",
    "dryRun": true
  }'

Responses

200
NameTypeConstraints
periodrequired
string
periodStartrequired
string (date)
periodEndrequired
string (date)
dueDaterequired
string (date)
dryRunrequired
boolean
eligibleStudentCountrequired
integer0–9007199254740991
alreadyInvoicedCountrequired
integer0–9007199254740991
createdInvoiceIdsrequired
array<string (uuid)>
json
{
  "period": "string",
  "periodStart": "2026-03-02",
  "periodEnd": "2026-03-02",
  "dueDate": "2026-03-02",
  "dryRun": true,
  "eligibleStudentCount": 0,
  "alreadyInvoicedCount": 0,
  "createdInvoiceIds": [
    "9bebdb24-9beb-7beb-8ebd-9bebdb249beb"
  ]
}
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/invoices

List invoices (filters: status, studentId, guardianId, overdue, due date range; cursor-paginated).

Requires authenticationScopeinvoices.read

Path & query parameters

NameInTypeConstraints
cursor
querystring
limit
queryinteger1–100 · default: 25
status
queryenum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"
studentId
querystring (uuid)
guardianId
querystring (uuid)
overdue
queryboolean
dueDateFrom
querystring (date)
dueDateTo
querystring (date)
sortBy
queryenum: "dueDate" | "total"default: "dueDate"
sortDir
queryenum: "asc" | "desc"default: "asc"

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/invoices" \
  -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",
      "number": "string",
      "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
      "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
      "status": "draft",
      "issueDate": "2026-03-02",
      "dueDate": "2026-03-02",
      "subtotal": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "discount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "tax": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "paid": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "currency": "USD",
      "notes": "Prefers afternoon sessions.",
      "version": -9007199254740991,
      "voidedAt": "2026-03-02T09:00:00.000Z",
      "voidReason": "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/invoices

Create a draft invoice. Totals are always recomputed server-side from `lines`.

Requires authenticationScopeinvoices.write

Request body

NameTypeConstraints
branchIdrequired
string (uuid)
studentIdrequired
string (uuid)
payerGuardianId
string (uuid)
issueDaterequired
string (date)
dueDaterequired
string (date)
currencyrequired
enum: "ILS" | "USD" | "EUR"
discountMinor
integer0–9007199254740991 · default: 0
taxMinor
integer0–9007199254740991 · default: 0
notes
string | string
linesrequired
array<object>

Example

json
{
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "currency": "ILS",
  "discountMinor": 0,
  "taxMinor": 0,
  "notes": "Prefers afternoon sessions.",
  "lines": [
    {
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unitMinor": 0,
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "string",
      "periodEnd": "string"
    }
  ]
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/invoices" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "branchId": "390b8975-390b-790b-80b8-390b8975390b",
    "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
    "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
    "issueDate": "2026-03-02",
    "dueDate": "2026-03-02",
    "currency": "ILS",
    "discountMinor": 0,
    "taxMinor": 0,
    "notes": "Prefers afternoon sessions.",
    "lines": [
      {
        "description": "A short, human-readable description.",
        "quantity": 1,
        "unitMinor": 0,
        "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
        "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
        "periodStart": "string",
        "periodEnd": "string"
      }
    ]
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
numberrequired
string≥1 chars
studentIdrequired
string (uuid)
payerGuardianIdrequired
string (uuid) | null
statusrequired
enum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"
issueDaterequired
string (date)
dueDaterequired
string (date)
subtotalrequired
Money
discountrequired
Money
taxrequired
Money
totalrequired
Money
paidrequired
Money
currencyrequired
string3–3 chars
notesrequired
string | null1–2000 chars
versionrequired
integer-9007199254740991–9007199254740991
voidedAtrequired
string (date-time) | null
voidReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
linesrequired
array<object>
paymentsrequired
array<object>
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "number": "string",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "status": "draft",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "subtotal": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "discount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "tax": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "total": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "paid": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "currency": "USD",
  "notes": "Prefers afternoon sessions.",
  "version": -9007199254740991,
  "voidedAt": "2026-03-02T09:00:00.000Z",
  "voidReason": "string",
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z",
  "lines": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "2026-03-02",
      "periodEnd": "2026-03-02"
    }
  ],
  "payments": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "method": "cash",
      "provider": "manual",
      "providerRef": "string",
      "receivedAt": "2026-03-02T09:00:00.000Z",
      "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
      "note": "string",
      "reversedAt": "2026-03-02T09:00:00.000Z",
      "reversalReason": "string",
      "createdAt": "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/invoices/{id}

Get an invoice, with its lines and payments.

Requires authenticationScopeinvoices.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
numberrequired
string≥1 chars
studentIdrequired
string (uuid)
payerGuardianIdrequired
string (uuid) | null
statusrequired
enum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"
issueDaterequired
string (date)
dueDaterequired
string (date)
subtotalrequired
Money
discountrequired
Money
taxrequired
Money
totalrequired
Money
paidrequired
Money
currencyrequired
string3–3 chars
notesrequired
string | null1–2000 chars
versionrequired
integer-9007199254740991–9007199254740991
voidedAtrequired
string (date-time) | null
voidReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
linesrequired
array<object>
paymentsrequired
array<object>
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "number": "string",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "status": "draft",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "subtotal": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "discount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "tax": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "total": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "paid": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "currency": "USD",
  "notes": "Prefers afternoon sessions.",
  "version": -9007199254740991,
  "voidedAt": "2026-03-02T09:00:00.000Z",
  "voidReason": "string",
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z",
  "lines": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "2026-03-02",
      "periodEnd": "2026-03-02"
    }
  ],
  "payments": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "method": "cash",
      "provider": "manual",
      "providerRef": "string",
      "receivedAt": "2026-03-02T09:00:00.000Z",
      "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
      "note": "string",
      "reversedAt": "2026-03-02T09:00:00.000Z",
      "reversalReason": "string",
      "createdAt": "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/invoices/{id}

Update a draft invoice (draft only). Replaces `lines` entirely. Requires the current `version`.

Requires authenticationScopeinvoices.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
versionrequired
integer1–9007199254740991
branchId
string (uuid)
payerGuardianId
string (uuid)
issueDate
string (date)
dueDate
string (date)
currency
enum: "ILS" | "USD" | "EUR"
discountMinor
integer0–9007199254740991
notes
enum: "" | string | null
linesrequired
array<object>

Example

json
{
  "version": 1,
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "currency": "ILS",
  "discountMinor": 0,
  "notes": "",
  "lines": [
    {
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unitMinor": 0,
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "2026-03-02",
      "periodEnd": "2026-03-02"
    }
  ]
}

curl example

curl
curl -X PATCH "https://api.yourdomain.com/api/v1/invoices/37386ae0-3738-7738-8386-37386ae03738" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "version": 1,
    "branchId": "390b8975-390b-790b-80b8-390b8975390b",
    "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
    "issueDate": "2026-03-02",
    "dueDate": "2026-03-02",
    "currency": "ILS",
    "discountMinor": 0,
    "notes": "",
    "lines": [
      {
        "description": "A short, human-readable description.",
        "quantity": 1,
        "unitMinor": 0,
        "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
        "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
        "periodStart": "2026-03-02",
        "periodEnd": "2026-03-02"
      }
    ]
  }'

Responses

200
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
numberrequired
string≥1 chars
studentIdrequired
string (uuid)
payerGuardianIdrequired
string (uuid) | null
statusrequired
enum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"
issueDaterequired
string (date)
dueDaterequired
string (date)
subtotalrequired
Money
discountrequired
Money
taxrequired
Money
totalrequired
Money
paidrequired
Money
currencyrequired
string3–3 chars
notesrequired
string | null1–2000 chars
versionrequired
integer-9007199254740991–9007199254740991
voidedAtrequired
string (date-time) | null
voidReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
linesrequired
array<object>
paymentsrequired
array<object>
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "number": "string",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "status": "draft",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "subtotal": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "discount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "tax": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "total": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "paid": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "currency": "USD",
  "notes": "Prefers afternoon sessions.",
  "version": -9007199254740991,
  "voidedAt": "2026-03-02T09:00:00.000Z",
  "voidReason": "string",
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z",
  "lines": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "2026-03-02",
      "periodEnd": "2026-03-02"
    }
  ],
  "payments": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "method": "cash",
      "provider": "manual",
      "providerRef": "string",
      "receivedAt": "2026-03-02T09:00:00.000Z",
      "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
      "note": "string",
      "reversedAt": "2026-03-02T09:00:00.000Z",
      "reversalReason": "string",
      "createdAt": "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/invoices/{id}/issue

Issue a draft invoice: allocates its number, sets issue/due dates, and emits `invoice.issued`.

Requires authenticationScopeinvoices.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
numberrequired
string≥1 chars
studentIdrequired
string (uuid)
payerGuardianIdrequired
string (uuid) | null
statusrequired
enum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"
issueDaterequired
string (date)
dueDaterequired
string (date)
subtotalrequired
Money
discountrequired
Money
taxrequired
Money
totalrequired
Money
paidrequired
Money
currencyrequired
string3–3 chars
notesrequired
string | null1–2000 chars
versionrequired
integer-9007199254740991–9007199254740991
voidedAtrequired
string (date-time) | null
voidReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
linesrequired
array<object>
paymentsrequired
array<object>
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "number": "string",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "status": "draft",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "subtotal": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "discount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "tax": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "total": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "paid": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "currency": "USD",
  "notes": "Prefers afternoon sessions.",
  "version": -9007199254740991,
  "voidedAt": "2026-03-02T09:00:00.000Z",
  "voidReason": "string",
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z",
  "lines": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "2026-03-02",
      "periodEnd": "2026-03-02"
    }
  ],
  "payments": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "method": "cash",
      "provider": "manual",
      "providerRef": "string",
      "receivedAt": "2026-03-02T09:00:00.000Z",
      "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
      "note": "string",
      "reversedAt": "2026-03-02T09:00:00.000Z",
      "reversalReason": "string",
      "createdAt": "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/invoices/{id}/payments

List every payment recorded against an invoice.

Requires authenticationScopepayments.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200
NameTypeConstraints
datarequired
array<object>
nextCursorrequired
string | null
json
{
  "data": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "method": "cash",
      "provider": "manual",
      "providerRef": "string",
      "receivedAt": "2026-03-02T09:00:00.000Z",
      "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
      "note": "string",
      "reversedAt": "2026-03-02T09:00:00.000Z",
      "reversalReason": "string",
      "createdAt": "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/invoices/{id}/payments

Record a payment against an invoice. Emits `payment.recorded`.

Requires authenticationScopepayments.record

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
amountMinorrequired
integer1–9007199254740991
currencyrequired
enum: "ILS" | "USD" | "EUR"
methodrequired
enum: "cash" | "bank_transfer" | "card" | "other"
provider
enum: "manual" | "stripe" | "tranzila" | "other"default: "manual"
providerRef
string | string
receivedAt
string | string (date-time)
note
string | string

Example

json
{
  "amountMinor": 12000,
  "currency": "ILS",
  "method": "cash",
  "provider": "manual",
  "providerRef": "string",
  "receivedAt": "string",
  "note": "string"
}

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/invoices/37386ae0-3738-7738-8386-37386ae03738/payments" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "amountMinor": 12000,
    "currency": "ILS",
    "method": "cash",
    "provider": "manual",
    "providerRef": "string",
    "receivedAt": "string",
    "note": "string"
  }'

Responses

201
NameTypeConstraints
idrequired
string (uuid)
invoiceIdrequired
string (uuid)
amountrequired
Money
methodrequired
enum: "cash" | "bank_transfer" | "card" | "other"
providerrequired
enum: "manual" | "stripe" | "tranzila" | "other"
providerRefrequired
string | null≥1 chars
receivedAtrequired
string (date-time)
receivedByUserIdrequired
string (uuid)
noterequired
string | null1–1000 chars
reversedAtrequired
string (date-time) | null
reversalReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
  "amount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "method": "cash",
  "provider": "manual",
  "providerRef": "string",
  "receivedAt": "2026-03-02T09:00:00.000Z",
  "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
  "note": "string",
  "reversedAt": "2026-03-02T09:00:00.000Z",
  "reversalReason": "string",
  "createdAt": "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/invoices/{id}/remind

Send a payment reminder (the `invoice.overdue` template) to the invoice's payer/guardians. Idempotent per invoice per UTC day — a second call the same day reports `alreadyRemindedToday` instead of re-sending.

Requires authenticationScopeinvoices.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200
NameTypeConstraints
invoiceIdrequired
string (uuid)
alreadyRemindedTodayrequired
boolean
sentAtrequired
string (date-time)
json
{
  "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
  "alreadyRemindedToday": true,
  "sentAt": "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/invoices/{id}/void

Void an invoice. Refused (409) if it has any active (non-reversed) payments.

Requires authenticationScopeinvoices.write

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
reasonrequired
string1–500 chars

Example

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

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/invoices/37386ae0-3738-7738-8386-37386ae03738/void" \
  -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)
branchIdrequired
string (uuid)
numberrequired
string≥1 chars
studentIdrequired
string (uuid)
payerGuardianIdrequired
string (uuid) | null
statusrequired
enum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"
issueDaterequired
string (date)
dueDaterequired
string (date)
subtotalrequired
Money
discountrequired
Money
taxrequired
Money
totalrequired
Money
paidrequired
Money
currencyrequired
string3–3 chars
notesrequired
string | null1–2000 chars
versionrequired
integer-9007199254740991–9007199254740991
voidedAtrequired
string (date-time) | null
voidReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
linesrequired
array<object>
paymentsrequired
array<object>
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "number": "string",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "status": "draft",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "subtotal": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "discount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "tax": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "total": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "paid": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "currency": "USD",
  "notes": "Prefers afternoon sessions.",
  "version": -9007199254740991,
  "voidedAt": "2026-03-02T09:00:00.000Z",
  "voidReason": "string",
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z",
  "lines": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "2026-03-02",
      "periodEnd": "2026-03-02"
    }
  ],
  "payments": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "method": "cash",
      "provider": "manual",
      "providerRef": "string",
      "receivedAt": "2026-03-02T09:00:00.000Z",
      "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
      "note": "string",
      "reversedAt": "2026-03-02T09:00:00.000Z",
      "reversalReason": "string",
      "createdAt": "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/invoices/remind-overdue

Bulk-send a payment reminder to every `overdue` invoice not already reminded today (idempotent per invoice per UTC day).

Requires authenticationScopeinvoices.write

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/invoices/remind-overdue" \
  -H "Authorization: Bearer $INSTITFLOW_API_KEY"

Responses

200
NameTypeConstraints
totalOverduerequired
integer0–9007199254740991
remindedrequired
integer0–9007199254740991
alreadyRemindedTodayrequired
integer0–9007199254740991
json
{
  "totalOverdue": 0,
  "reminded": 0,
  "alreadyRemindedToday": 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/invoices

My own invoices (student: own; guardian: invoices they pay, or their children’s). Cursor-paginated; filterable by `studentId` and `status`.

Requires authenticationScopeNo additional permission

Path & query parameters

NameInTypeConstraints
cursor
querystring
limit
queryinteger1–100 · default: 25
studentId
querystring (uuid)
status
queryenum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"

curl example

curl
curl -X GET "https://api.yourdomain.com/api/v1/me/invoices" \
  -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",
      "number": "string",
      "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
      "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
      "status": "draft",
      "issueDate": "2026-03-02",
      "dueDate": "2026-03-02",
      "subtotal": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "discount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "tax": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "paid": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "currency": "USD",
      "notes": "Prefers afternoon sessions.",
      "version": -9007199254740991,
      "voidedAt": "2026-03-02T09:00:00.000Z",
      "voidReason": "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/me/invoices/{id}

One of my own invoices, with its lines and payments.

Requires authenticationScopeNo additional permission

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200
NameTypeConstraints
idrequired
string (uuid)
branchIdrequired
string (uuid)
numberrequired
string≥1 chars
studentIdrequired
string (uuid)
payerGuardianIdrequired
string (uuid) | null
statusrequired
enum: "draft" | "issued" | "partially_paid" | "paid" | "overdue" | "void"
issueDaterequired
string (date)
dueDaterequired
string (date)
subtotalrequired
Money
discountrequired
Money
taxrequired
Money
totalrequired
Money
paidrequired
Money
currencyrequired
string3–3 chars
notesrequired
string | null1–2000 chars
versionrequired
integer-9007199254740991–9007199254740991
voidedAtrequired
string (date-time) | null
voidReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
updatedAtrequired
string (date-time)
linesrequired
array<object>
paymentsrequired
array<object>
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "branchId": "390b8975-390b-790b-80b8-390b8975390b",
  "number": "string",
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "payerGuardianId": "4e92fac4-4e92-7e92-892f-4e92fac44e92",
  "status": "draft",
  "issueDate": "2026-03-02",
  "dueDate": "2026-03-02",
  "subtotal": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "discount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "tax": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "total": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "paid": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "currency": "USD",
  "notes": "Prefers afternoon sessions.",
  "version": -9007199254740991,
  "voidedAt": "2026-03-02T09:00:00.000Z",
  "voidReason": "string",
  "createdAt": "2026-03-02T09:00:00.000Z",
  "updatedAt": "2026-03-02T09:00:00.000Z",
  "lines": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "description": "A short, human-readable description.",
      "quantity": 1,
      "unit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "total": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "enrollmentId": "c8bc7863-c8bc-78bc-8bc7-c8bc7863c8bc",
      "feeScheduleId": "3cfbbfe7-3cfb-7cfb-8fbb-3cfbbfe73cfb",
      "periodStart": "2026-03-02",
      "periodEnd": "2026-03-02"
    }
  ],
  "payments": [
    {
      "id": "37386ae0-3738-7738-8386-37386ae03738",
      "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
      "amount": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "method": "cash",
      "provider": "manual",
      "providerRef": "string",
      "receivedAt": "2026-03-02T09:00:00.000Z",
      "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
      "note": "string",
      "reversedAt": "2026-03-02T09:00:00.000Z",
      "reversalReason": "string",
      "createdAt": "2026-03-02T09:00:00.000Z"
    }
  ]
}
400The request could not be read at all — unparseable body, unusable content type, oversized payload (`MALFORMED_REQUEST`). Never a schema failure: those are 422.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

GET /api/v1/me/statement

My own (or one linked child’s) statement: invoices and payments, chronological, with a running balance.

Requires authenticationScopeNo additional permission

Path & query parameters

NameInTypeConstraints
studentId
querystring (uuid)

curl example

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

Responses

200
NameTypeConstraints
studentIdrequired
string (uuid)
currencyrequired
string3–3 chars
entriesrequired
array<object>
balancerequired
Money
json
{
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "currency": "USD",
  "entries": [
    {
      "type": "invoice",
      "date": "2026-03-02T09:00:00.000Z",
      "referenceId": "6b25c837-6b25-7b25-825c-6b25c8376b25",
      "description": "A short, human-readable description.",
      "debit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "credit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "balance": {
        "amountMinor": 12000,
        "currency": "ILS"
      }
    }
  ],
  "balance": {
    "amountMinor": 12000,
    "currency": "ILS"
  }
}
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/payments/{id}/reverse

Reverse a recorded payment, recomputing its invoice’s paid amount/status.

Requires authenticationScopepayments.record

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

Request body

NameTypeConstraints
reasonrequired
string1–500 chars

Example

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

curl example

curl
curl -X POST "https://api.yourdomain.com/api/v1/payments/37386ae0-3738-7738-8386-37386ae03738/reverse" \
  -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)
invoiceIdrequired
string (uuid)
amountrequired
Money
methodrequired
enum: "cash" | "bank_transfer" | "card" | "other"
providerrequired
enum: "manual" | "stripe" | "tranzila" | "other"
providerRefrequired
string | null≥1 chars
receivedAtrequired
string (date-time)
receivedByUserIdrequired
string (uuid)
noterequired
string | null1–1000 chars
reversedAtrequired
string (date-time) | null
reversalReasonrequired
string | null1–500 chars
createdAtrequired
string (date-time)
json
{
  "id": "37386ae0-3738-7738-8386-37386ae03738",
  "invoiceId": "f3093e02-f309-7309-8093-f3093e02f309",
  "amount": {
    "amountMinor": 12000,
    "currency": "ILS"
  },
  "method": "cash",
  "provider": "manual",
  "providerRef": "string",
  "receivedAt": "2026-03-02T09:00:00.000Z",
  "receivedByUserId": "56d35175-56d3-76d3-8d35-56d3517556d3",
  "note": "string",
  "reversedAt": "2026-03-02T09:00:00.000Z",
  "reversalReason": "string",
  "createdAt": "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}/statement

A student’s invoices + payments, chronological, with a running balance.

Requires authenticationScopeinvoices.read

Path & query parameters

NameInTypeConstraints
idrequired
pathstring

curl example

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

Responses

200
NameTypeConstraints
studentIdrequired
string (uuid)
currencyrequired
string3–3 chars
entriesrequired
array<object>
balancerequired
Money
json
{
  "studentId": "a4a70332-a4a7-74a7-8a70-a4a70332a4a7",
  "currency": "USD",
  "entries": [
    {
      "type": "invoice",
      "date": "2026-03-02T09:00:00.000Z",
      "referenceId": "6b25c837-6b25-7b25-825c-6b25c8376b25",
      "description": "A short, human-readable description.",
      "debit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "credit": {
        "amountMinor": 12000,
        "currency": "ILS"
      },
      "balance": {
        "amountMinor": 12000,
        "currency": "ILS"
      }
    }
  ],
  "balance": {
    "amountMinor": 12000,
    "currency": "ILS"
  }
}
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.