Skip to main content
The Exode SaaS API is a REST API over HTTPS. All endpoints are under the saas/v2/ prefix.

Base URL

The full method address is https://api.exode.biz/saas/v2/<module>/<method> — for example, https://api.exode.biz/saas/v2/user/create.

Authentication

Requests are made on behalf of a service user (API client) — a school employee with a configured set of permissions and their own API token.
  • Authenticate with the Authorization: Bearer <TOKEN> header.
  • The token does not expire, and you can revoke it at any time.
  • The token must belong to a user with the API client flag (a service user created on the API keys page gets it) — otherwise SaaS endpoints return 403 Forbidden, even if all other permissions are in place.

How to get the token and IDs

1

Create an API key

The school owner opens Manage → School → For developers → API keys (/manage/school/api-keys) and creates a key — this also creates a service user and issues a token. A school can have at most 5 keys. The same page lists the keys with a token preview and issue date, and lets you rotate (reissue) the token.
2

Save the token

Copy the token right away — it is shown in full only once (see below). This is the value of the Authorization: Bearer <TOKEN> header.
3

Copy the Seller-Id and School-Id

On the same page, the “Integration data → Identifiers” card shows both IDs as Seller-Id: 123; School-Id: 456 — click the line to copy it. These are numbers; they do not change when the token is rotated.
If you prefer, contact support and we will help you set things up.
The token is shown in full only at creation or rotation — save it right away. The key list shows only a preview (the first and last 4 characters) and the issue date. Rotation issues a new token and immediately revokes the old one.
A new key immediately receives all the permissions SaaS API methods need, so your first request works without setup. The set depends on the school segment (school.segment: Commerce — a commercial online school, Corporate — corporate employee training): commercial schools additionally get “School Sales” and “School Refunds”, corporate schools get “Staff Management” and “Staff browsing” (employee sync from HR/1C works out of the box). You can change the set on the key’s page; for details, see API key permissions.
Never store the token in code or a repository. Use environment variables. The token grants access to school data — do not share it with third parties.

Required headers

Request headers

string
required
The service user’s API token in the Bearer YOUR_TOKEN format. The school owner issues the token in the admin panel: Manage → School → For developers → API keys — see the “Authentication” section for details.
integer
required
The numeric ID of the seller — the account the school belongs to. Copy it on the API keys page, in the Integration data → Identifiers card. The token’s permissions are checked against this ID.
integer
required
The numeric ID of the school, found in the same place as Seller-Id. The value must match the seller’s school — otherwise a 400 error with cause: "ForbiddenSchoolMismatch" is returned.
A missing or invalid Authorization header results in 401 Unauthorized. Without Seller-Id (or with the ID of a seller the token does not belong to), methods return 401 Forbidden. The API determines the school from the seller and checks School-Id against it: if you pass the ID of a different school, you get 400 ForbiddenSchoolMismatch.
In the examples on method pages, header values are written as {{ sellerId }} and {{ schoolId }} — these are variables of the Postman collection. When running cURL from a terminal, replace them with the numeric IDs, and replace YOUR_TOKEN with your token.

Response format

Every successful response is wrapped in a single structure:
boolean
required
true for successful responses (HTTP codes 200–206).
integer
required
HTTP response code (200, 201, etc.).
any
required
The method’s payload. Its structure is described on the page of the specific method and strictly matches the response schema (extra fields are not returned).
Successful response

Error format

Errors are returned in the same envelope plus the cause, message, error fields and an optional data field:
boolean
required
Always false for errors.
integer
required
HTTP error code: 400, 401, 403, 404, 429, 500.
string
required
Machine-readable cause code. Use it to build your error handling. Examples: validation, Unauthorized, Forbidden, EmailIsBusy, Rate.
string | string[]
required
Human-readable error message. With cause: "validation", it is an array of strings, one for each violated rule (for example, ["extId must be shorter than or equal to 50 characters"]).
string
required
Technical description (matches message by default).
object
Additional data (for example, retryAfter for 429). Optional.
Error example

Common cause codes (cause)

The specific cause codes for each method are listed on its page (in the “Error” responses). For example, creating a user can return UserAlreadyExist, EmailIsBusy, PhoneIsBusy, TgIdIsBusy.

Access permissions (RBAC)

Each method checks the API key’s permissions — the checkboxes on the key’s page in the account. If a method lists several permissions, any one of them is enough. Without the required permission, the method returns 401 with the message Forbidden seller resource - permissions <Code>.

API key permissions

Which checkboxes to enable for your integration task, which methods each permission unlocks and which permissions a new key receives.

Rate limits

Some methods are rate-limited. When the limit is exceeded, the API returns HTTP 429 with cause: "Rate":
Rate limit exceeded
  • The limit is counted per service user (token).
  • The data.retryAfter field tells you when you can retry the request.
  • Limits are listed on method pages. For example, generating exports is limited to 100 requests per hour.
Implement retries that respect retryAfter, with exponential backoff for transient errors (429, 5xx).

Pagination

List methods (.../list/raw, course progress, etc.) accept pagination parameters in the query:
integer
Page size. From 1 to 1000. Defaults to 100.
integer
Page number (starting from 1). An alternative to skip: used only if skip is not passed.
integer
Offset (number of records to skip). If both skip and page are passed, skip takes effect.
A list method’s response is a single envelope with a page:
Page structure
Pass array parameters by repeating the key: userIds=1&userIds=2&userIds=3. Pass ranges as nested fields, for example createdAtDateRange[from] and createdAtDateRange[to].

Request example

Always check success/code and handle the error cause — this speeds up integration troubleshooting.

Updated: 2026-09-28 05:04 UTC