Recursos
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,
  "expiresAt": "2026-12-31T23:59:59.000Z"
}

expiresAt is optional. Omit it or send null for a non-expiring key.

Response 201:

{
  "apiKey": "tf_content_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "keyId": "0b063e58-7e19-4787-90f0-d081c85f50d3",
  "keyPrefix": "tf_content_abc123def456",
  "name": "external-content-test",
  "rateLimitPerMinute": 60,
  "expiresAt": "2026-12-31T23:59:59.000Z"
}

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.

The rotated key keeps the old key's name, rateLimitPerMinute, and expiresAt. Create a new key instead if you need a different expiration policy.

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. If both are sent, the Idempotency-Key header is used.

Idempotency is request-body aware. Repeating the same key with the same classroom, requested outputs, source type, and payload returns the existing job. Reusing the same key with different request content returns 409.

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 PATCH is partial. Fields omitted from the request keep their existing values. Course delete returns 200 with deleted id and optional chatSessionId.

Course create also prepares the admin editor starter curriculum when no curriculum is supplied: 3 chapters, 4 lessons per chapter, and 12 editable markdown lessons.

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 200 with { "success": true }. Scene delete returns 200 with the updated video object.

POST /videos accepts an optional scenes array. If scenes is omitted, TutorFlow creates the Content API default video setup: landscape 16:9, layout mode auto, target duration 120 seconds, and 13 starter scenes. Scene timing fields must be numbers when present; omit optional timing fields instead of sending null.

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 create returns 201 with the created slide object. If content is omitted, TutorFlow creates the Content API default deck: 10 editable slides with generated image prompt markers on every fourth slide, starting with slide 1. If content is included on create, the create response and later GET /slides/{slideId} response include the stored content. 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 }.

Test create defaults omitted level, totalScore, passingValueType, and passingValue to MEDIUM, 100, SCORE, and 80. A new test receives 20 starter questions worth 5 points each.

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, module copy, key rotate, key revoke, and webhook delete requests succeeded.
201Key, webhook, module, course, video, video scene, slide, 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, webhook, classroom, or content resource was not found. Deleted content resources also return 404.
409Idempotency or state conflict, including reusing an idempotency key with different request content.
429Rate limit exceeded.
500Unexpected server error.