API reference

API Reference

Welcome to the Okta Partners platform API reference. Once your app is approved and a tenant installs it, this API lets your app read and write Okta data — strictly within the scopes that tenant explicitly granted.

The runtime API is hosted by **okta-web** (the core platform app); every request hits the `/apps` path under the base URL. The partner platform (okta-partners) is where you register your app, pick scopes, and manage versions and webhooks.

The API is REST over HTTPS, exchanges JSON (UTF-8), and uses standard HTTP status codes. Every read and write is isolated per tenant and protected by a named scope.

Your first call

curl https://getokta.io/api/apps/whoami \
  -H "Authorization: Bearer $OKTA_PARTNER_TOKEN" \
  -H "Accept: application/json"

Base URL

The runtime API is hosted by okta-web under the following path:

https://getokta.io/api/apps

Sandbox environment:

https://dev.getokta.io/api/apps

Authentication

Every request authenticates with a per-installation **Bearer token**. The token is issued automatically when a tenant installs your app; it is bound to a (tenant, app) pair and carries the granted scopes.

Authorization: Bearer <installation_token>
  • Never embed the token in front-end code or a public repo — store it as a server-side secret (e.g. `OKTA_PARTNER_TOKEN`).
  • The token is rotatable from the partner dashboard; external apps receive the new token over the bridge without a redeploy.
  • A missing or invalid token returns `401 Unauthorized`. A valid token lacking the required scope returns `403 Forbidden`.

Verify your token

curl https://getokta.io/api/apps/whoami \
  -H "Authorization: Bearer $OKTA_PARTNER_TOKEN"
# → { "tenant_id": 42, "module": "your-app", "scopes": [ ... ] }

Scopes

Every piece of data is protected by a scope shaped `..`. Partners get exactly two actions: `read` and `write`. Delete is never granted to partners. You pick scopes when creating the app; the tenant approves them on install.

Scope Description
education.students.read Read students
education.students.write Create / update students
education.guardians.read Read guardians
education.subjects.read Read subjects
education.grades.read Read grades
education.sections.read Read sections
education.academic_years.read Read academic years
education.terms.read Read terms
employees.directory.read Read employee directory
entity.hierarchy.read See the entity’s tree: who is beneath, their profiles, who is above — and a condition for reading the children’s data with `?entities=`
reports.builder.read Report catalog / run, list the school’s letterheads and print on them
reports.builder.write Propose an app-authored letterhead (arrives as a draft)
notifications.providers.send Send via a notification provider
notifications.dispatch.send Dispatch a notification from your app’s catalog over HTTP (an Embedded app calls the service in-process, no scope needed)
notifications.logs.read Read the delivery log of your app’s notifications (your installation only)
realtime.messages.write Publish an instant message to your app's surfaces (listening needs no scope)

Endpoints

All paths are relative to the base URL above. Write endpoints (POST/PATCH) require the matching scope.

Identity

GET /whoami no scope Current installation info (tenant, app, scopes).
GET https://getokta.io/api/apps/whoami

Current installation info (tenant, app, scopes).

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: none
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_a43d
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Entity & tree

GET /entity no scope Where am I: the entity’s type, whether it is a container, its parent.
GET https://getokta.io/api/apps/entity

Where am I: the entity’s type, whether it is a container, its parent.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: none
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_8823
    A stable identifier for this endpoint — quote it to support to speed up tracing.

GET /entity/children entity.hierarchy.read The entities beneath, each with `installed` and `access` (what can be read there), plus `can_read_children` for the current person.
GET https://getokta.io/api/apps/entity/children

The entities beneath, each with `installed` and `access` (what can be read there), plus `can_read_children` for the current person.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: entity.hierarchy.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_5fbb
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

descendants boolean

Every level instead of the next one only.

GET /entity/children/{id} entity.hierarchy.read One child’s profile: logo (as a path), contact, country, stage, sizes, and `access`.
GET https://getokta.io/api/apps/entity/children/{id}

One child’s profile: logo (as a path), contact, country, stage, sizes, and `access`.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: entity.hierarchy.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_cfc0
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id string required

ULID of an entity beneath yours.

GET /entity/departments entity.hierarchy.read The complex’s departments and each one’s schools, with `viewer` — where the person stands (`reach` what they reach, or null for the whole tree). Every tree read is already fenced to the person’s department.
GET https://getokta.io/api/apps/entity/departments

The complex’s departments and each one’s schools, with `viewer` — where the person stands (`reach` what they reach, or null for the whole tree). Every tree read is already fenced to the person’s department.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: entity.hierarchy.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_aaa5
    A stable identifier for this endpoint — quote it to support to speed up tracing.

GET /entity/ancestors entity.hierarchy.read The entities above me, nearest first.
GET https://getokta.io/api/apps/entity/ancestors

The entities above me, nearest first.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: entity.hierarchy.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_937a
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Students

GET /education/students education.students.read List students (paginated).
GET https://getokta.io/api/apps/education/students

List students (paginated).

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.students.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_b079
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

GET /education/students/{id} education.students.read A single student.
GET https://getokta.io/api/apps/education/students/{id}

A single student.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.students.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_5905
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id integer required

The resource id in Okta.

Query Params

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

POST /education/students education.students.write Create a student.
POST https://getokta.io/api/apps/education/students

Create a student.

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.students.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_0ec3
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

full_name string required

Student's full name.

national_id string

National / residency id.

birth_date date

Birth date (YYYY-MM-DD).

gender enum

male or female.

grade_id integer

Grade id.

section_id integer

Section id.

guardian_id integer

Guardian id.

PATCH /education/students/{id} education.students.write Update a student.
PATCH https://getokta.io/api/apps/education/students/{id}

Update a student.

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.students.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_e45a
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id integer required

The resource id in Okta.

Body Params

full_name string

Student's full name.

national_id string

National / residency id.

birth_date date

Birth date (YYYY-MM-DD).

gender enum

male or female.

grade_id integer

Grade id.

section_id integer

Section id.

guardian_id integer

Guardian id.

Guardians

GET /education/guardians education.guardians.read List guardians.
GET https://getokta.io/api/apps/education/guardians

List guardians.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.guardians.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_aac5
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

GET /education/guardians/{id} education.guardians.read A single guardian.
GET https://getokta.io/api/apps/education/guardians/{id}

A single guardian.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.guardians.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_4be0
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id integer required

The resource id in Okta.

Query Params

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

POST /education/guardians education.guardians.write Create a guardian.
POST https://getokta.io/api/apps/education/guardians

Create a guardian.

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.guardians.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_8da4
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

full_name string required

Guardian's full name.

phone string required

Phone in E.164 format.

email string

Email address.

relation enum

father | mother | other.

PATCH /education/guardians/{id} education.guardians.write Update a guardian.
PATCH https://getokta.io/api/apps/education/guardians/{id}

Update a guardian.

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.guardians.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_4ca6
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id integer required

The resource id in Okta.

Body Params

full_name string

Guardian's full name.

phone string

Phone in E.164 format.

email string

Email address.

relation enum

father | mother | other.

Curriculum

GET /education/subjects education.subjects.read Subjects.
GET https://getokta.io/api/apps/education/subjects

Subjects.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.subjects.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_bd8c
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

POST /education/subjects education.subjects.write Create a subject (idempotent).
POST https://getokta.io/api/apps/education/subjects

Create a subject (idempotent).

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.subjects.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_96e0
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

name string required

Subject name.

code string

Subject code.

GET /education/grades education.grades.read Grades.
GET https://getokta.io/api/apps/education/grades

Grades.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.grades.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_7d9a
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

GET /education/sections education.sections.read Sections.
GET https://getokta.io/api/apps/education/sections

Sections.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.sections.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_1d44
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

GET /education/academic-years education.academic_years.read Academic years.
GET https://getokta.io/api/apps/education/academic-years

Academic years.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.academic_years.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_faa5
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

GET /education/terms education.terms.read Terms.
GET https://getokta.io/api/apps/education/terms

Terms.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: education.terms.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_df6c
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

Employees

GET /employees/directory employees.directory.read Employee directory.
GET https://getokta.io/api/apps/employees/directory

Employee directory.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: employees.directory.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_c6a4
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (1-based).

per_page integer

Items per page (max 100).

search string

Optional free-text search.

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

GET /employees/directory/{id} employees.directory.read A single employee.
GET https://getokta.io/api/apps/employees/directory/{id}

A single employee.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: employees.directory.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_5c8f
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id integer required

The resource id in Okta.

Query Params

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

POST /employees/directory employees.directory.write Add an employee (idempotent).
POST https://getokta.io/api/apps/employees/directory

Add an employee (idempotent).

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: employees.directory.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_0fe2
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

full_name string required

Employee's full name.

job_title string

Job title.

email string

Email address.

Reports

GET /reports/builder reports.builder.read Catalog of available reports.
GET https://getokta.io/api/apps/reports/builder

Catalog of available reports.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: reports.builder.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_5f23
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

POST /reports/builder/{key}/run reports.builder.read Run a report (idempotent).
POST https://getokta.io/api/apps/reports/builder/{key}/run

Run a report (idempotent).

  • Rate Limit: HEAVY
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: reports.builder.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_8dd1
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

key string required

Report key from the catalog.

Body Params

parameters object

Report parameters (report-specific).

GET /reports/templates reports.builder.read The school’s approved letterheads.
GET https://getokta.io/api/apps/reports/templates

The school’s approved letterheads.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: reports.builder.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_865a
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

entities string

Up to 20 comma-separated ULIDs of entities beneath yours: the answer is {"entities": {"<ulid>": this endpoint’s answer for that entity}}, a refused one carrying error and status under its key. A school is read with its own grant to your app or your entity’s read grant carried down; entity.hierarchy.read is required.

entity string

ULID of ONE entity beneath yours: the answer is that entity’s, as is. For a person holding tenants.children.view_members, never an installation token.

POST /reports/templates/{id}/render reports.builder.read Print your content on a letterhead — returns a PDF.
POST https://getokta.io/api/apps/reports/templates/{id}/render

Print your content on a letterhead — returns a PDF.

  • Rate Limit: HEAVY
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: reports.builder.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_2c93
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id string required

The opaque template id exactly as the listing returned it — not a number.

Body Params

blocks array required

The document body — blocks: heading, text, table, info-row, divider, spacer, image. An unknown type is refused, not skipped.

variables object

Values for the template’s declared variables. An undeclared key is dropped; platform variables cannot be overwritten.

POST /reports/templates reports.builder.write Propose a template (arrives as a draft, idempotent).
POST https://getokta.io/api/apps/reports/templates

Propose a template (arrives as a draft, idempotent).

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: reports.builder.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_2d4e
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

name_ar string required

Template name in Arabic.

name_en string

Template name in English.

description string

A description shown to whoever picks the template.

type enum

administrative | general.

orientation enum

portrait | landscape.

paper_size enum

a4 | a3 | letter.

header_enabled boolean

Show the header band.

footer_enabled boolean

Show the footer band.

header_right_content string

Right header slot — text accepting {{variables}}.

header_center_content string

Center header slot.

header_left_content string

Left header slot.

footer_right_content string

Right footer slot.

footer_center_content string

Center footer slot.

footer_left_content string

Left footer slot.

watermark_text string

Watermark text.

watermark_opacity integer

Watermark opacity (0–100).

margin_top_mm integer

Top margin in mm (0–40).

margin_right_mm integer

Right margin in mm (0–40).

margin_bottom_mm integer

Bottom margin in mm (0–40).

margin_left_mm integer

Left margin in mm (0–40).

signatures_enabled boolean

Print the signature block at the foot.

signatures_columns integer

Signature block columns (1–4).

signatures_title string

Signature block title.

signatures array

Signatories: title_ar (required), title_en, name, show_line. An empty array removes them all; omitting the key leaves them alone.

variables array

Template fields: key (required), label_ar (required), label_en, type (text|date|number|currency), required, default_value. A key shadowing a platform variable is dropped silently.

PATCH /reports/templates/{id} reports.builder.write Edit a template your app authored (revokes approval).
PATCH https://getokta.io/api/apps/reports/templates/{id}

Edit a template your app authored (revokes approval).

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: reports.builder.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_1937
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id string required

The opaque template id exactly as the listing returned it — not a number.

Body Params

name_ar string

Template name in Arabic.

name_en string

Template name in English.

description string

A description shown to whoever picks the template.

type enum

administrative | general.

orientation enum

portrait | landscape.

paper_size enum

a4 | a3 | letter.

header_enabled boolean

Show the header band.

footer_enabled boolean

Show the footer band.

header_right_content string

Right header slot — text accepting {{variables}}.

header_center_content string

Center header slot.

header_left_content string

Left header slot.

footer_right_content string

Right footer slot.

footer_center_content string

Center footer slot.

footer_left_content string

Left footer slot.

watermark_text string

Watermark text.

watermark_opacity integer

Watermark opacity (0–100).

margin_top_mm integer

Top margin in mm (0–40).

margin_right_mm integer

Right margin in mm (0–40).

margin_bottom_mm integer

Bottom margin in mm (0–40).

margin_left_mm integer

Left margin in mm (0–40).

signatures_enabled boolean

Print the signature block at the foot.

signatures_columns integer

Signature block columns (1–4).

signatures_title string

Signature block title.

signatures array

Signatories: title_ar (required), title_en, name, show_line. An empty array removes them all; omitting the key leaves them alone.

variables array

Template fields: key (required), label_ar (required), label_en, type (text|date|number|currency), required, default_value. A key shadowing a platform variable is dropped silently.

DELETE /reports/templates/{id} reports.builder.write Delete a draft your app authored.
DELETE https://getokta.io/api/apps/reports/templates/{id}

Delete a draft your app authored.

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: reports.builder.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_43ce
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Path Params

id string required

The opaque template id exactly as the listing returned it — not a number.

Notifications

GET /notifications/capabilities notifications.providers.send Notification channel capabilities.
GET https://getokta.io/api/apps/notifications/capabilities

Notification channel capabilities.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: notifications.providers.send
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_f406
    A stable identifier for this endpoint — quote it to support to speed up tracing.

GET /notifications/catalog notifications.providers.send For a provider: the notification catalogue of every app installed on the tenant — keys, their variables, and the tenant’s state per key.
GET https://getokta.io/api/apps/notifications/catalog

For a channel provider: every notification key the apps installed on this tenant declare — names, `variables` (name → type), the developer’s default template and channel ceiling — plus the tenant’s state for the key when it has one (`enabled`, `channels`, `template_id`). These are the keys you will see in `metadata.notification_key`; the variables are what fills your template’s slots. This tenant’s apps only; no recipients, no payloads. `installed_apps` lists every active install with its notification count so an empty answer reads: installs without notifications, or a token on another tenant (`tenant_id`).

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: notifications.providers.send
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_b2fa
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

channel string

Only the keys that would go out on this channel here (the tenant’s choice when it has one, else the developer’s ceiling) — e.g. `whatsapp`.

POST /notifications/send notifications.providers.send Send a message (idempotent).
POST https://getokta.io/api/apps/notifications/send

Send a message (idempotent).

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: notifications.providers.send
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_3458
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

recipient string required

Recipient (phone or user id).

message string required

Message body.

channel string

Specific channel (optional).

POST /notifications/dispatch notifications.dispatch.send Dispatch a catalog notification to its recipient — the platform fans out to the channels (idempotent).
POST https://getokta.io/api/apps/notifications/dispatch

Dispatches a key declared in your app’s catalog to its recipient; the platform picks the channels from the school’s settings. An Embedded app calls `App\Services\PartnerApi\Notifications\DispatchNotification` in-process with the same payload.

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: notifications.dispatch.send
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_6ff9
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

key string required

A key declared in your app’s catalog (`<slug>.<resource>.<event>`). An undeclared key is refused with a 422 that names it.

payload.recipient object

`{type, id}` — who it is about: `parent_of_student` (student ulid), `host_user` (a user id), `school_admin` (the school). Absent = the school’s configured recipients. No `*_id` key is ever read as an address.

payload.variables object

What the templates’ `{{ placeholders }}` resolve to. Flat keys beside the reserved fields are moved here automatically.

payload.subject string

A title your app rendered — used when no template applies.

payload.body string

A body your app rendered — third in precedence after the school’s wording and `default_template`.

payload.url string

A link the in-app card opens.

payload.locale string

Locale of the text you sent (`ar`/`en`).

payload.metadata object

Data for your own use; never printed.

GET /notifications/logs notifications.logs.read What became of what you dispatched: each attempt’s status and error.
GET https://getokta.io/api/apps/notifications/logs

One row per (key, channel) the platform attempted for your installation, with its status and the error the channel job left. `queued` not yet picked up by the worker; `sent` arrived; `failed` did not (the text says why); `skipped_disabled` the school has not enabled the key; `skipped_no_transport` the channel has no transport; `skipped_quiet` inside quiet hours; `skipped_plan_feature` outside the plan.

  • Rate Limit: LIGHT
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: notifications.logs.read
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_4fad
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Query Params

page integer

Page number (default 1).

per_page integer

Page size, max 100 (default 50).

channel string

Filter by channel: `in_app` `push` `whatsapp` `sms` `email` `webhook_out`.

status string

Filter by status.

key string

Filter by notification key.

from string

From date (ISO 8601).

to string

To date (ISO 8601).

Realtime

POST /realtime/publish realtime.messages.write Push an instant message to your app's own surfaces in this tenant (not idempotent).
POST https://getokta.io/api/apps/realtime/publish

Pushes a message to your app's channel in this tenant only. Listening needs no scope — the installation is the permission, and there is no `realtime.messages.read`.

  • Rate Limit: MODERATE
    How heavily this call counts against your quota: LIGHT < MODERATE < HEAVY.
  • Permission needed: realtime.messages.write
    The scope the tenant must grant your app before this call is allowed.
  • Reference Code: srv_c59d
    A stable identifier for this endpoint — quote it to support to speed up tracing.

Body Params

event string required

Your own event name — `^[a-z][a-z0-9_.:-]{0,63}$`. It never becomes the broadcast event name: that is the fixed `app.message`, and yours travels inside the payload.

data object required

The message payload, at most 8192 bytes of JSON. Anything needing data is read by the surface from the API with its usual scope.

The full, always-current list lives in the auto-generated OpenAPI 3.1 spec: /docs/openapi.json · /docs/postman_collection.json

Pagination

List endpoints are paginated. Use `?page=2&per_page=50` (max 100 per page).

{
  "data": [ ... ],
  "total": 1242,
  "per_page": 20,
  "current_page": 1,
  "last_page": 63
}

Idempotency

Write operations (POST/PATCH) accept an optional header. The same key within 24 hours replays the same stored response — so if your side times out, retrying will not create a duplicate record.

Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000

Errors

Errors are returned as a consistent JSON envelope with the appropriate HTTP status code.

{
  "message": "The given scope is not granted for this installation.",
  "error": "scope_not_granted",
  "scope": "education.students.write"
}
Status Name Description
400 Bad Request Malformed or missing request body.
401 Unauthorized Missing or invalid token.
403 Forbidden Valid token, but the required scope is not granted.
404 Not Found Resource not found within the tenant scope.
409 Conflict Idempotency conflict or inconsistent state.
422 Unprocessable Entity Field validation failed.
429 Too Many Requests Rate limit exceeded.
5xx Server Error Transient error — retry with backoff.

Rate limits

Every response carries headers telling you the remaining budget. On exceed, you get `429` with `Retry-After` (seconds). Honor exponential backoff on retry.

Header Description
X-RateLimit-Limit Ceiling for the window.
X-RateLimit-Remaining Remaining in the current window.
Retry-After Seconds until a new request is allowed (with 429).

Webhooks

External apps receive platform events via signed webhooks. Each webhook is an HTTP POST with a JSON body, signed with HMAC-SHA256 over the envelope `.`.

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "event": "education.students.created",
  "tenant_id": 42,
  "created_at": "2026-04-26T10:30:15+03:00",
  "data": { "student": { "id": 123, "full_name": "..." } }
}
Header Description
X-Okta-Event Event name.
X-Okta-Delivery-Id UUID stable across retries (for dedup).
X-Okta-Timestamp Unix timestamp at signing.
X-Okta-Signature HMAC-SHA256 signature (hex).

Verify the signature

$expected = hash_hmac(
    'sha256',
    $request->header('X-Okta-Timestamp').'.'.$request->getContent(),
    $YOUR_WEBHOOK_SECRET,
);

if (! hash_equals($expected, $request->header('X-Okta-Signature'))) {
    return response('invalid signature', 401);
}
  • Check `X-Okta-Timestamp` is within the last 5 minutes, and store `X-Okta-Delivery-Id` for at least 15 minutes to reject replays.
  • Respond 2xx within 10 seconds. For long work, accept with 202 immediately and process asynchronously.
  • Retry backoff: 30s → 2m → 10m → 1h → 6h, after which the delivery is marked failed and surfaces on the Webhook Deliveries page in the partner dashboard.

More resources

This reference is a practical summary. For the full picture (integration types, app lifecycle, the manifest, the policy scanner) see the developer guide.