Use this runbook when a developer or AI coding agent is writing integration code, test scripts, SDK wrappers, or support diagnostics for Content Integration.
Non-negotiable boundary
Content Integration is the API surface for content that people create, review, or manage in TutorFlow UI.
| Use case | Correct API |
|---|---|
| Create, read, update, or delete UI-owned courses, videos, slides, tests, or modules | /v1/content/** |
| Expand customer-owned source JSON into editable TutorFlow content | /v1/content/integrations/expansions |
| Create or rotate a key for an external content system | /v1/content/organizations/{organizationId}/api-keys |
| Autonomous AI agent workflows that were built for Agent Platform | /v1/platform/** |
Do not mix these surfaces. A Content API client should never require an Agent Platform ownership id, platform key, edit token, or Platform public URL.
Discovery sequence
Never ask a customer to guess ids from a screenshot or copy ids from an internal database.
- Sign in as a TutorFlow admin and create
tutorflow-admin.cookies. - Call
GET /v1/content/organizationswith the admin session cookie. - Create a
tf_content_key for the selected organization. - Call
GET /v1/content/classroomswith thetf_content_bearer key. - Use the returned classroom
idfor expansion and resource CRUD.
Minimal environment variables
export TUTORFLOW_API_BASE_URL="https://api.tutorflow.io"
export TUTORFLOW_CONTENT_API_KEY="tf_content_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export TUTORFLOW_CLASSROOM_ID="00000000-0000-4000-8000-000000000010"Do not introduce an organization-id environment variable as a prerequisite for bearer-key resource calls. Organization id is only needed while an admin creates or manages keys and webhooks.
Safe request defaults
Use these defaults in generated clients and examples:
| Concern | Default |
|---|---|
| Auth header | Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY |
| Content type | Content-Type: application/json |
| Idempotency | Send Idempotency-Key on every create request. |
| Timeout | Use a client timeout of at least 30 seconds for create requests. |
| Polling | Poll expansion jobs every 2 to 5 seconds until completed or failed. |
| Retries | Retry network failures with the same idempotency key. Do not retry validation errors blindly. |
Good idempotency key patterns:
module:{externalModuleId}:{version}
course:{externalCourseId}:{version}
video:{externalVideoId}:{version}
slides:{externalDeckId}:{version}
test:{externalAssessmentId}:{version}
expansion:{externalContentGroupId}:{version}Response handling contract
Store these values after every successful create or expansion result:
| Field | Store it because |
|---|---|
TutorFlow resource id | It is required for later GET, PATCH, and DELETE calls. |
classroomId | It proves the resource is attached to the intended classroom. |
keyPrefix | It is safe to share in support tickets. |
Idempotency-Key | It explains replay behavior and prevents accidental duplicates. |
job.id | It is the support and reconciliation id for expansion jobs. |
outputs[].resourceId | It links generated outputs to direct resource APIs. |
outputs[].manifest | It is the handoff payload for review or downstream sync. |
Do not store full tf_content_ keys in logs, analytics events, crash reports, or generated code comments.
Smoke test script outline
set -euo pipefail
curl -sS "$TUTORFLOW_API_BASE_URL/v1/content/classrooms" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"
MODULE_ID="$(curl -sS -X POST "$TUTORFLOW_API_BASE_URL/v1/content/classrooms/$TUTORFLOW_CLASSROOM_ID/modules" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: module:smoke-test:v1" \
-d '{
"title": "Content API smoke test",
"type": "markdown",
"content": "<h2>Smoke test</h2><p>This module was created by the Content API.</p>",
"metadata": {
"externalId": "module:smoke-test"
}
}' | jq -r '.id')"
curl -sS "$TUTORFLOW_API_BASE_URL/v1/content/classrooms/$TUTORFLOW_CLASSROOM_ID/modules/$MODULE_ID" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"
curl -sS -X PATCH "$TUTORFLOW_API_BASE_URL/v1/content/classrooms/$TUTORFLOW_CLASSROOM_ID/modules/$MODULE_ID" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Content API smoke test updated"
}'
curl -sS -X DELETE "$TUTORFLOW_API_BASE_URL/v1/content/classrooms/$TUTORFLOW_CLASSROOM_ID/modules/$MODULE_ID" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"For production scripts, create and clean up a resource in each required type: module, course, video, slide, and test.
Common AI agent mistakes
| Mistake | Correct behavior |
|---|---|
Using /v1/platform/** because the task mentions external automation | Use /v1/content/** for human-owned TutorFlow UI content. |
| Asking the customer for a hard-coded organization id | Call GET /v1/content/organizations after admin login. |
| Asking the customer for a hard-coded classroom id | Call GET /v1/content/classrooms with the Content API key. |
| Reusing one idempotency key for changed request bodies | Generate a new key when the source version changes. |
| Logging the full bearer key in test output | Log only keyPrefix. |
| Treating summary video output as a finished MP4 | Treat it as editable video structure until rendering is triggered after review. |
| Expecting every delete to return the same body | Follow the resource-specific delete table in Content Resource API. |
Pre-handoff checklist
Before handing integration code to a customer, verify:
- The script discovers organization and classroom ids through the API.
- The script uses only
tf_content_keys for/v1/content/**. - No Agent Platform ownership id, platform API key, edit token, or Platform URL appears in generated customer code or support notes.
- Create requests send stable idempotency keys.
- The script stores returned TutorFlow ids next to external ids.
- The script handles
400,401,403,404,409, and429responses. - Logs redact the full bearer token.
- A small pilot payload completes before larger production payloads are sent.