Skip to main content
Tessera’s API is generated from a single contract: every operation’s input and output is defined once, validated at runtime, and rendered into the API reference (in the navigation) from the same schemas. This page covers the conventions that apply across every endpoint; the reference covers each one, for example creating a course from an import.

Authentication

Two ways to authenticate:
  • API tokens (tsk_…): created in the app by an administrator, or by an instructor for their own courses. A token is shown once, at creation — copy it then, because it isn’t shown again. Send it as a bearer token:
  • Browser sessions: the app itself authenticates through Cloudflare Access; this only matters if you’re calling the API from a script or another system, in which case use a token.

Scopes

Every token is created with one or more scopes, and can only call routes that need a scope it has:

Versioning

Every route is under /api/v1/. This is the version to build against.

Errors

Every error response is a JSON object:

Pagination

List endpoints use cursor pagination:
Pass limit to control page size, and pass the previous response’s nextCursor as cursor to get the next page. A nextCursor of null means there’s nothing more.

Idempotency

Send an Idempotency-Key header on a POST that creates something, to make retries safe:
The same key from the same caller replays the first response instead of creating a duplicate.

Rate limits

Each token (or session) is limited to a fixed number of requests per minute. Going over returns 429 rate-limited with a Retry-After header giving the number of seconds to wait.

Request IDs

Every response carries an X-Request-Id header, useful when reporting an issue with a specific call.

File upload and download

Files are handled outside the JSON contract, since they carry raw bytes: Upload:
Send the file as a multipart field named file. The limit is 25 MB per file. Download:
Without format, this returns the original file. With it, it returns that accessible format once it’s been generated. Range requests are supported, so this works for streaming audio and large files.

Example: create a course and import content

This creates a course and adds a module with one lesson, in a single call, using a fictional example:
A successful call returns the new course’s outline, with its modules, lessons, and blocks.