Koala Enterprise API
Manage teachers, schedule lessons, distribute classroom join links, and pull attendance, usage, and recordings — programmatically, from your own systems.
All request and response bodies are JSON. Timestamps are ISO 8601 strings, UTC unless an offset is included (e.g. 2026-07-10T15:00:00Z).
Authentication
Every request must include your enterprise API token as a Bearer token:
Authorization: Bearer YOUR_API_TOKEN
Your API token is issued by the Koala team when your enterprise account is set up. It grants full access to your organization's data — keep it secret, and contact Koala support if you need it rotated.
Requests with a missing or invalid token return 401 Unauthorized.
Core concepts
- Teacher — a member of your organization with a Koala account and a personal classroom ("room"). Your enterprise has a fixed number of seats; only enabled teachers count against it.
- Lesson — a scheduled time slot for a teacher. Creating a lesson returns two links: a teacher link for the tutor and a student link for students to join that teacher's room. Students don't need accounts — they join through the student link and enter their name.
- Session — an actual classroom meeting that took place. A lesson can have zero or more sessions (for example, if the teacher reconnects). Recordings are produced per lesson (stitched from its sessions) and, if enabled for your account, per session.
Lessons
List lessons
/v1/lessonsFetch a single lesson by ID, or list lessons in a time range.
Query parameters
| Parameter | Type | Description |
|---|---|---|
id | UUID | Fetch one specific lesson. Cannot be combined with start/end. |
start | timestamp | Start of the time range (filters on lesson start time). Required together with end. |
end | timestamp | End of the time range. The range may not exceed 90 days. |
count | boolean | If true, returns only { "count": n } instead of the lesson list. |
startRange | integer | Pagination offset (default 0). |
rangeCount | integer | Maximum number of lessons to return (default: no limit). |
Example
curl "https://business.teachwithkoala.com/v1/lessons?start=2026-07-01T00:00:00Z&end=2026-07-31T23:59:59Z" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Response
An array of lessons, ordered by end time:
[
{
"id": "7d9e1c9a-...",
"recordingStatus": "ready",
"teacherLink": "https://yourdomain.teachwithkoala.com/?lesson=7d9e1c9a-...",
"studentLink": "https://yourdomain.teachwithkoala.com/?lesson=7d9e1c9a-...&room=ab12cd34",
"startTime": "2026-07-10T15:00:00+00:00",
"endTime": "2026-07-10T16:00:00+00:00",
"teacherEmail": "tutor@yourcompany.com",
"studentsAttendance": [],
"teacherAttendance": []
}
]
recordingStatus is one of:
| Status | Meaning |
|---|---|
scheduled | The lesson hasn't happened yet. |
processing | The lesson happened; the recording is still being processed. |
ready | The recording is ready to download (see Get a lesson recording). |
no_meeting | The lesson time passed but no classroom meeting took place. |
error | Recording processing failed. Contact Koala support or trigger a reprocess. |
studentsAttendance and teacherAttendance arrays are always empty in this endpoint's response. Use the attendance endpoint to retrieve attendance data.Create lessons
/v1/lessonsSchedule one or more lessons. Identify the teacher by teacherId or teacherEmail (not both). No availability checks are applied — your scheduling system is the source of truth.
Request body
[
{
"start": "2026-07-15T15:00:00Z",
"end": "2026-07-15T16:00:00Z",
"teacherEmail": "tutor@yourcompany.com"
}
]
Response
One entry per created lesson, including the join links to distribute:
[
{
"teacherId": "b4f8a2e1-...",
"teacherEmail": "tutor@yourcompany.com",
"lessonId": "7d9e1c9a-...",
"teacherLink": "https://yourdomain.teachwithkoala.com/?lesson=7d9e1c9a-...",
"studentLink": "https://yourdomain.teachwithkoala.com/?lesson=7d9e1c9a-...&room=ab12cd34"
}
]
Errors
400— missing start/end, or both/neither ofteacherIdandteacherEmailsupplied.404— a referenced teacher does not exist in your organization. The response message lists which ones; no lessons are created.
Delete lessons
/v1/lessonsDelete lessons that have not started yet. There is no update/reschedule endpoint — to move a lesson, delete it and create a new one.
Request body
[
{ "lessonId": "7d9e1c9a-..." },
{ "lessonId": "3c2b1a0f-..." }
]
Response
{ "deleted_lessons": [ { "id": "7d9e1c9a-..." }, { "id": "3c2b1a0f-..." } ] }
Errors
404— one or more lesson IDs weren't found (the message lists them; nothing is deleted).400— one or more lessons already started (the message lists them; nothing is deleted).
Get lesson attendance
/v1/lessons/attendance?lessonIds=<id1>,<id2>,...Join/leave intervals for the teacher and each student, for up to 50 lessons per request. A participant who reconnects appears as multiple intervals.
Response
An object keyed by lesson ID (lessons with no attendance are omitted):
{
"7d9e1c9a-...": {
"teacherAttendance": [
{
"teacherId": "b4f8a2e1-...",
"startTime": "2026-07-10T15:01:12+00:00",
"endTime": "2026-07-10T16:02:40+00:00",
"userAgent": { "platform": "macOS", "mobile": false }
}
],
"studentsAttendance": [
{
"name": "Maya",
"startTime": "2026-07-10T15:03:05+00:00",
"endTime": "2026-07-10T15:58:31+00:00",
"userAgent": { "platform": "Windows", "mobile": false }
}
]
}
}
Student names are the names students entered when joining. userAgent describes the participant's device/browser and may be null.
Get a lesson recording
/v1/lessons/recording?lesson=<lessonId>Returns a temporary download URL for the lesson's video recording. Only available once the lesson's recordingStatus is ready.
Response
{ "signedUrl": "https://..." }
The URL is valid for 7 days. Fetch a fresh one at any time.
Errors
404— lesson not found, or its recording isn't ready yet.
List a lesson's sessions
/v1/lessons/sessions?lessonId=<lessonId>Returns the raw classroom sessions that took place under a lesson — useful for diagnosing what happened during a lesson (e.g. reconnects). Key fields per session: id, started_at, ended_at, recording_status.
Teachers
List teachers
/v1/teachersResponse
[
{
"id": "b4f8a2e1-...",
"email": "tutor@yourcompany.com",
"isEnabled": true,
"isAdmin": false,
"totalTeachingSeconds": 184230,
"roomName": "ab12cd34"
}
]
roomName may be null if the teacher's classroom hasn't been provisioned yet.
Add teachers
/v1/teachersCreates Koala accounts for the given email addresses and adds them to your organization. Fails with 400 if your organization has reached its seat limit.
Request body
{ "teachers": [ { "email": "new.tutor@yourcompany.com" } ] }
Response
A per-teacher result; some may succeed while others fail:
[
{
"id": "e19c3f7b-...",
"email": "new.tutor@yourcompany.com",
"success": true,
"message": "Teacher Added"
},
{
"id": null,
"email": "taken@elsewhere.com",
"success": false,
"message": "User already part of a different tutoring org."
}
]
New teachers sign in with their email address via the login page's password-reset / magic-link flow (no password is communicated by the API).
Enable / disable a teacher
/v1/teachers?teacher_id=<id>&is_enabled=<true|false>Disabled teachers keep their account and history but can't hold classes and don't count against your seat limit. Re-enabling checks the seat limit and returns 400 if you're at capacity.
Response
{ "success": true }
Teaching time report
/v1/teachers/teaching-time?start_date=<ts>&end_date=<ts>Total seconds of classroom time per teacher over a date range (max 365 days). Omit teacher_ids to get all teachers; otherwise pass a JSON array, e.g. teacher_ids=["b4f8a2e1-..."] (URL-encoded). Teachers with no sessions in the range are included with 0.
Response
{
"b4f8a2e1-...": 184230,
"e19c3f7b-...": 0
}
A teacher's session history
/v1/teachers/<teacher_id>/sessionsEvery classroom session for one teacher, newest first, optionally filtered with start_date and end_date (max 365 days).
Response
{
"sessions": [
{
"started_at": "2026-07-10T15:01:12+00:00",
"ended_at": "2026-07-10T16:02:40+00:00",
"duration_seconds": 3688
}
]
}
Session recordings
Reprocess a session recording
/v1/sessions/reprocessRe-runs recording processing for a session — for example after a processing error, or to have the recording.ready webhook fire again.
Request body
{ "sessionId": "9f8e7d6c-..." }
Response
202 Accepted:
{ "success": true }
Processing is asynchronous; if your account has the recording.ready webhook configured, it fires again when the new recording is ready.
Errors
404— session not found in your organization.400— the session's recording is not in a reprocessable state, or the session is older than the 30-day recording retention window (raw recording segments are deleted after that, so reprocessing is no longer possible).
Webhooks
Instead of polling for recording status, Koala can push events to an HTTPS endpoint you provide. Webhooks are configured by the Koala team — send us your endpoint URL and a secret token, and we'll set them up. Every webhook request includes your token:
Authorization: Bearer YOUR_WEBHOOK_TOKEN
Content-Type: application/json
Verify the token on every delivery before trusting the payload.
Lesson recording processed
Fires when a lesson's recording finishes processing. The payload is the lesson object (same shape as List lessons) plus a recordingSignedUrl field — a 7-day download URL, or null if the lesson produced no recording (e.g. no meeting took place).
{
"id": "7d9e1c9a-...",
"recordingStatus": "ready",
"teacherEmail": "tutor@yourcompany.com",
"startTime": "2026-07-10T15:00:00+00:00",
"endTime": "2026-07-10T16:00:00+00:00",
"teacherLink": "https://yourdomain.teachwithkoala.com/?lesson=7d9e1c9a-...",
"studentLink": "https://yourdomain.teachwithkoala.com/?lesson=7d9e1c9a-...&room=ab12cd34",
"recordingSignedUrl": "https://..."
}
Respond with HTTP 200 and the JSON body { "ok": true }, served with Content-Type: application/json. Anything else — including a 200 with a non-JSON body — is treated as a failure and the delivery is retried.
Session recording ready (recording.ready)
Fires when an individual session's recording is ready.
{
"event": "recording.ready",
"sessionId": "9f8e7d6c-...",
"recordingUrl": "https://...",
"tutorEmail": "tutor@yourcompany.com",
"startTime": "2026-07-10T15:01:12+00:00",
"durationSeconds": 3688,
"studentNames": ["Maya", "Leo"]
}
recordingUrl is valid for 7 days. tutorEmail may be null.
Respond with any 2xx status to acknowledge. Failed deliveries are retried up to 3 times with increasing delays (1 hour, 4 hours, 24 hours after the successive failures). After the final failure the event is dropped — you can trigger a fresh delivery with a reprocess request.
Deliveries can occasionally repeat (e.g. after a reprocess), so make your handler idempotent — sessionId is the deduplication key.
Errors
Errors use standard HTTP status codes with a JSON body:
{ "message": "Date range cannot exceed 90 days. Current range: 112 days." }
| Status | Meaning |
|---|---|
400 | Invalid request — the message explains what to fix. |
401 | Missing or invalid API token. |
404 | The requested resource doesn't exist in your organization. |
500 | Something went wrong on our side. Retry later or contact support. |
Limits
| Limit | Value |
|---|---|
| Lesson list time range | 90 days per request |
| Attendance lookup | 50 lessons per request |
| Teaching-time / session-history range | 365 days per request |
| Recording download URLs | Valid 7 days (re-fetchable) |
| Recording retention (reprocessing) | 30 days |
| Teacher seats | Per your contract; add/enable endpoints enforce it |
Support
Questions, token rotation, webhook setup, or anything unexpected: contact the Koala team at noah@teachwithkoala.com.