Resources
Content Integration Examples

Content Integration Examples

Copy-ready curl, Node.js, and Python examples for Content Integration.

These examples show the full path from key creation to result retrieval. Resource calls require a classroom id, discovered with the Content API key after key creation.

Before running the examples

The curl examples use jq and an admin session cookie. If your admin account uses email and password sign-in, create the cookie jar first:

set -euo pipefail
 
export TUTORFLOW_API_BASE_URL="https://api.tutorflow.io"
 
curl -c tutorflow-admin.cookies -X POST "$TUTORFLOW_API_BASE_URL/auth/login" \
  -H "Content-Type: application/json" \
  -H "Referer: https://tutorflow.io/sign-in" \
  -d '{
    "email": "admin@example.com",
    "password": "your-password",
    "timezone": "Asia/Seoul"
  }'

If your organization uses SSO or OAuth sign-in, create the key from an authenticated TutorFlow admin environment instead of using the password-login example.

curl: find organization ID

curl "$TUTORFLOW_API_BASE_URL/v1/content/organizations" \
  -b tutorflow-admin.cookies
 
export TUTORFLOW_CONTENT_ORG_ID="$(curl -s "$TUTORFLOW_API_BASE_URL/v1/content/organizations" \
  -b tutorflow-admin.cookies | jq -r '.[0].id')"

curl: create key

KEY_RESPONSE="$(curl -s -X POST "$TUTORFLOW_API_BASE_URL/v1/content/organizations/$TUTORFLOW_CONTENT_ORG_ID/api-keys" \
  -H "Content-Type: application/json" \
  -b tutorflow-admin.cookies \
  -d '{"name":"external-content-test","rateLimitPerMinute":60}')"
 
export TUTORFLOW_CONTENT_API_KEY="$(printf '%s' "$KEY_RESPONSE" | jq -r '.apiKey')"
export TUTORFLOW_CONTENT_KEY_PREFIX="$(printf '%s' "$KEY_RESPONSE" | jq -r '.keyPrefix')"

curl: find classroom ID

curl "$TUTORFLOW_API_BASE_URL/v1/content/classrooms" \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"
 
export TUTORFLOW_CLASSROOM_ID="$(curl -s "$TUTORFLOW_API_BASE_URL/v1/content/classrooms" \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY" | jq -r '.[0].id')"

curl: create expansion

cat > source-content.json <<JSON
{
  "classroomId": "$TUTORFLOW_CLASSROOM_ID",
  "requestedOutputs": ["interactive_module", "summary_video", "expanded_quiz"],
  "payload": {
    "category": {
      "id": "language-basics",
      "title": "Language Basics"
    },
    "language": "en",
    "level": {
      "id": "level-a1",
      "title": "A1 Foundations",
      "lessons": [
        {
          "id": "lesson-vocabulary-1",
          "type": "vocabulary",
          "title": "Basic greetings",
          "items": [
            {
              "term": "hello",
              "meaning": "a greeting"
            }
          ]
        }
      ]
    }
  }
}
JSON
 
JOB_RESPONSE="$(curl -s -X POST "$TUTORFLOW_API_BASE_URL/v1/content/integrations/expansions" \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: language-basics-level-a1-2026-07-04" \
  --data-binary @source-content.json)"
 
export JOB_ID="$(printf '%s' "$JOB_RESPONSE" | jq -r '.id')"

curl: poll and retrieve

curl "$TUTORFLOW_API_BASE_URL/v1/content/integrations/expansions/$JOB_ID" \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"
 
curl "$TUTORFLOW_API_BASE_URL/v1/content/integrations/expansions/$JOB_ID/result" \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"

Node.js: create expansion

const tutorFlowApiBaseUrl =
  process.env.TUTORFLOW_API_BASE_URL ?? 'https://api.tutorflow.io'
 
const response = await fetch(
  `${tutorFlowApiBaseUrl}/v1/content/integrations/expansions`,
  {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.TUTORFLOW_CONTENT_API_KEY}`,
      'Content-Type': 'application/json',
      'Idempotency-Key': 'language-basics-level-a1-2026-07-04',
    },
    body: JSON.stringify({
      classroomId: process.env.TUTORFLOW_CLASSROOM_ID,
      requestedOutputs: ['interactive_module', 'summary_video', 'expanded_quiz'],
      payload: {
        category: { id: 'language-basics', title: 'Language Basics' },
        language: 'en',
        level: {
          id: 'level-a1',
          title: 'A1 Foundations',
          lessons: [
            {
              id: 'lesson-vocabulary-1',
              type: 'vocabulary',
              title: 'Basic greetings',
              items: [{ term: 'hello', meaning: 'a greeting' }],
            },
          ],
        },
      },
    }),
  },
)
 
if (!response.ok) {
  throw new Error(await response.text())
}
 
const job = await response.json()

Node.js: polling helper

async function waitForContentJob(jobId) {
  const tutorFlowApiBaseUrl =
    process.env.TUTORFLOW_API_BASE_URL ?? 'https://api.tutorflow.io'
 
  for (let attempt = 0; attempt < 60; attempt++) {
    const response = await fetch(
      `${tutorFlowApiBaseUrl}/v1/content/integrations/expansions/${jobId}`,
      {
        headers: {
          Authorization: `Bearer ${process.env.TUTORFLOW_CONTENT_API_KEY}`,
        },
      },
    )
 
    if (!response.ok) {
      throw new Error(await response.text())
    }
 
    const job = await response.json()
 
    if (job.status === 'completed' || job.status === 'failed') {
      return job
    }
 
    await new Promise((resolve) => setTimeout(resolve, 3000))
  }
 
  throw new Error('Content job did not finish within the polling window')
}

Python: create expansion

import os
import requests
 
api_base_url = os.environ.get("TUTORFLOW_API_BASE_URL", "https://api.tutorflow.io")
 
response = requests.post(
    f"{api_base_url}/v1/content/integrations/expansions",
    headers={
        "Authorization": f"Bearer {os.environ['TUTORFLOW_CONTENT_API_KEY']}",
        "Content-Type": "application/json",
        "Idempotency-Key": "language-basics-level-a1-2026-07-04",
    },
    json={
        "classroomId": os.environ["TUTORFLOW_CLASSROOM_ID"],
        "requestedOutputs": ["interactive_module", "summary_video", "expanded_quiz"],
        "payload": {
            "category": {"id": "language-basics", "title": "Language Basics"},
            "language": "en",
            "level": {
                "id": "level-a1",
                "title": "A1 Foundations",
                "lessons": [
                    {
                        "id": "lesson-vocabulary-1",
                        "type": "vocabulary",
                        "title": "Basic greetings",
                        "items": [{"term": "hello", "meaning": "a greeting"}],
                    }
                ],
            },
        },
    },
    timeout=30,
)
response.raise_for_status()
job = response.json()

Manifest storage shape

{
  "sourceContentId": "language-basics:level-a1",
  "tutorFlowJobId": "3f9440c4-7b15-48d7-a02f-4c1c50a8c3e1",
  "outputType": "interactive_module",
  "status": "completed",
  "resourceType": "module",
  "resourceId": "module-request-id",
  "manifest": {}
}