Resources
Content Integration API Reference

Content Integration API Reference

Endpoint reference for Content API keys, source JSON expansion, resource control, result retrieval, and webhooks.

All paths are relative to https://api.tutorflow.io.

Content Integration uses /v1/content/** for classroom-owned TutorFlow content. The Agent Platform uses /v1/platform/** for AI agent workflows. Do not use Platform credentials or Agent Platform ownership fields for Content Integration requests.

Authentication types

Auth typeUsed byHeader
Admin sessionKey management and webhook managementCookie: jwt=... or curl -b tutorflow-admin.cookies
Content API keyExpansion create, status, result, direct content resourcesAuthorization: Bearer tf_content_...

API key endpoints

List manageable organizations

GET /v1/content/organizations

Auth: admin session.

Use this endpoint first when the customer does not know their organization ID. It returns organizations where the signed-in admin can manage Content Integration.

Response 200:

[
  {
    "id": "00000000-0000-4000-8000-000000000001",
    "name": "Customer Academy",
    "slug": "customer-academy",
    "role": "ADMIN"
  }
]

Create key

POST /v1/content/organizations/{organizationId}/api-keys

Auth: admin session. Use an id returned by GET /v1/content/organizations as {organizationId}.

Request:

{
  "name": "external-content-test",
  "rateLimitPerMinute": 60
}

Response 201:

{
  "apiKey": "tf_content_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "keyId": "0b063e58-7e19-4787-90f0-d081c85f50d3",
  "keyPrefix": "tf_content_abc123def456",
  "name": "external-content-test",
  "rateLimitPerMinute": 60
}

List keys

GET /v1/content/organizations/{organizationId}/api-keys

Auth: admin session.

Response 200 includes key metadata only. The full secret is not returned.

Rotate key

POST /v1/content/organizations/{organizationId}/api-keys/{keyId}/rotate

Auth: admin session.

Response 200 returns a new one-time apiKey.

Revoke key

POST /v1/content/organizations/{organizationId}/api-keys/{keyId}/revoke

Auth: admin session.

Response 200 has no body.

Expansion endpoints

Create expansion

POST /v1/content/integrations/expansions

Headers:

Authorization: Bearer tf_content_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json
Idempotency-Key: source-content-level-a1-2026-07-04

Request fields:

FieldTypeRequiredNotes
classroomIduuidYesTarget classroom. Use GET /v1/content/classrooms after key creation to discover it.
requestedOutputsstring[]NoSupported values are interactive_module, summary_video, expanded_quiz.
payloadobjectYesExisting source JSON.
sourceTypestringNoDefaults to source_json.
idempotencyKeystringNoHeader is preferred.

Response 202 returns the created job and queued output rows.

Get status

GET /v1/content/integrations/expansions/{jobId}

Response 200 returns the job and outputs. Poll until completed or failed.

Get result

GET /v1/content/integrations/expansions/{jobId}/result

Response 200 returns job, outputs, and a combined manifest.

Classroom discovery

GET /v1/content/classrooms

Auth: Content API key.

Response:

[
  {
    "id": "00000000-0000-4000-8000-000000000010",
    "name": "Customer Academy",
    "slug": "customer-academy",
    "locale": "en"
  }
]

Use one returned id as {classroomId} for expansion and resource CRUD endpoints.

Content resource endpoints

The same tf_content_ bearer key can create and control TutorFlow content resources directly. These endpoints do not require the external system to know an organization ID after the key has been created.

Modules

POST   /v1/content/classrooms/{classroomId}/modules
GET    /v1/content/classrooms/{classroomId}/modules
GET    /v1/content/classrooms/{classroomId}/modules/{moduleId}
PATCH  /v1/content/classrooms/{classroomId}/modules/{moduleId}
DELETE /v1/content/classrooms/{classroomId}/modules/{moduleId}
POST   /v1/content/classrooms/{classroomId}/modules/{moduleId}/copy-to-course

Module delete returns 200 with { "success": true }.

Courses

POST  /v1/content/classrooms/{classroomId}/courses
GET   /v1/content/classrooms/{classroomId}/courses
GET   /v1/content/classrooms/{classroomId}/courses/{courseId}
PATCH /v1/content/classrooms/{classroomId}/courses/{courseId}
DELETE /v1/content/classrooms/{classroomId}/courses/{courseId}

Course delete returns 200 with deleted id and optional chatSessionId.

Videos

POST   /v1/content/classrooms/{classroomId}/videos
GET    /v1/content/classrooms/{classroomId}/videos
GET    /v1/content/classrooms/{classroomId}/videos/{videoId}
PATCH  /v1/content/classrooms/{classroomId}/videos/{videoId}
DELETE /v1/content/classrooms/{classroomId}/videos/{videoId}
POST   /v1/content/classrooms/{classroomId}/videos/{videoId}/scenes
PATCH  /v1/content/classrooms/{classroomId}/videos/{videoId}/scenes/{sceneId}
DELETE /v1/content/classrooms/{classroomId}/videos/{videoId}/scenes/{sceneId}
PATCH  /v1/content/classrooms/{classroomId}/videos/{videoId}/scenes/reorder

Video delete returns 204 with no body. Scene delete returns 200 with the updated video object.

Slides

POST  /v1/content/classrooms/{classroomId}/slides
GET   /v1/content/classrooms/{classroomId}/slides
GET   /v1/content/classrooms/{classroomId}/slides/{slideId}
PATCH /v1/content/classrooms/{classroomId}/slides/{slideId}
DELETE /v1/content/classrooms/{classroomId}/slides/{slideId}

Slide delete returns 200 with the deleted slide object.

Tests

POST   /v1/content/classrooms/{classroomId}/tests
GET    /v1/content/classrooms/{classroomId}/tests
GET    /v1/content/classrooms/{classroomId}/tests/{testId}
PATCH  /v1/content/classrooms/{classroomId}/tests/{testId}
DELETE /v1/content/classrooms/{classroomId}/tests/{testId}

Test delete returns 200 with { "success": true }.

For request and response examples, see Content Resource API.

Optional legacy standalone lesson export

POST /v1/content/classrooms/{classroomId}/integrations/exports

Request:

{
  "lessonId": "standalone-lesson-id",
  "idempotencyKey": "standalone-lesson:standalone-lesson-id"
}

Skip this endpoint for new integrations. Use it only when TutorFlow support confirms that an existing standalone lesson is not represented by the course, video, slide, test, or module resource APIs. For courses, videos, slides, tests, and modules, use the Content resource endpoints above with the tf_content_ bearer key.

Webhook endpoints

Create webhook

POST /v1/content/organizations/{organizationId}/webhooks

Auth: admin session. Use an id returned by GET /v1/content/organizations as {organizationId}.

Request:

{
  "url": "https://example.com/tutorflow/content-webhooks",
  "events": ["content.completed", "content.failed"]
}

Response 201 returns endpoint metadata and a one-time secret.

List webhooks

GET /v1/content/organizations/{organizationId}/webhooks

Response 200 returns endpoint metadata without the signing secret.

Delete webhook

DELETE /v1/content/organizations/{organizationId}/webhooks/{webhookId}

Response 200 has no body.

Status codes

CodeMeaning
200Read, update, delete, slide create, key rotate, key revoke, and webhook delete requests succeeded.
201Key, webhook, module, course, video, video scene, or test created.
202Expansion job accepted.
400Request body is invalid.
401Missing or invalid Content API key.
403Signed-in admin cannot manage the organization.
404Job, key, or webhook was not found.
409Idempotency or state conflict.
429Rate limit exceeded.
500Unexpected server error.