Introduction

For AI agents and the developers who build them. One unauthenticated call creates a TutorFlow agent account with a Content key, a default classroom, and 50 trial credits; the next calls generate content on the Content API.

These docs describe the HTTP calls an agent makes on its own: create an account, generate courses, tests, modules, slides, videos, games, and simulations, grade answers, and pay for the work. Every request goes to https://api.tutorflow.io.

What an agent gets

One call to POST /v1/platform/agent/register gives the agent:

Field in the answerWhat it isUse it for
contentApiKeyA live Content key (tf_content_...), shown onceEvery call in these docs: content work on /v1/content/** and the account routes on /v1/platform/agent/*
apiKeynull. Register no longer issues legacy keysNothing
defaultClassroomIdThe classroom that live-key content goes intoThe {classroomId} in every Content API path
organizationIdThe id of the agent's workspaceSupport requests. No route needs it.
trialContentCredits50, the trial credits on the one credit balanceSpending right away, with no email verification and no payment method

GET /v1/platform/agent/account adds sandboxClassroomId: the only classroom a test key reaches. It is null until the account has a test key.

The account has one credit balance. Every priced call made with a live key spends it; test keys spend nothing. A credit costs 2 US cents.

The first three calls

1. Create the account. No key. Store contentApiKey and defaultClassroomId at once: the key is never shown again.

bash
curl -X POST https://api.tutorflow.io/v1/platform/agent/register \
  -H "Content-Type: application/json" \
  -d '{ "name": "My EdTech Agent", "slug": "my-edtech-agent", "email": "operator@example.com" }'

201 Created with contentApiKey, apiKey, defaultClassroomId, trialContentCredits: 50, and requiresEmailVerification: true. The full answer is in Quick Start.

2. Check the key and the balance.

bash
curl https://api.tutorflow.io/v1/platform/agent/account \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"

200 OK with credits (the balance in credits), defaultClassroomId, sandboxClassroomId, isEmailVerified, and ready-made Content API URLs in contentApiUrls.

3. Generate content.

bash
curl -X POST "https://api.tutorflow.io/v1/content/classrooms/$CLASSROOM_ID/courses/generate" \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: course:intro-python:v1" \
  -d '{ "topic": "Beginner Python: variables, loops, and functions", "lessonCount": 1, "language": "en" }'

202 Accepted with runId, status: "queued", estimatedCredits: 6, and statusUrl. Read GET /v1/content/classrooms/{classroomId}/runs/{runId} until status is completed or failed. The whole walk-through is in Generate Your First Content.

What happens on errors

Every error is a JSON error object. Branch on error.code, never on message. The full table is in Error Handling.

Status and codeWhenWhat the agent does
402 content_payment_requiredA priced Content API call costs more than the balance (plus any metered overdraft)Nothing was charged. The error carries billingSessionUrl, an x402 block where USDC payment is enabled (it is on production), and emailVerification. Top up, then retry with the same Idempotency-Key. See When credits run out.
410 platform_route_removedA call to a content route under /v1/platform (/courses, /tests, /modules, /slides, /videos, /games, /evaluations, /learners, /webhooks), removed on 2026-10-16Do not retry. Move the call to the Content API; error.migrationGuide links the migration guide.
429 content_rate_limit_exceeded or platform_rate_limit_exceededThe key (Content API, 60 per minute by default) or the account (account routes, 1,000 per minute) is over its limitWait the Retry-After seconds, then retry. Every counted Content API answer carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. See Rate Limiting.
401, 403Wrong key for the routeSee Where each key works.

The 410 body, as production answers it:

JSON
{
  "error": {
    "code": "platform_route_removed",
    "message": "This Agent Platform content route was removed. Use the Content API with a tf_content_ key: https://tutorflow.io/agent-platform/docs/guides/content-api-migration",
    "migrationGuide": "https://tutorflow.io/agent-platform/docs/guides/content-api-migration",
    "status": 410
  }
}

Terms

These docs use each term below in one sense only. Other pages link here at the first use.

Agent account

What POST /v1/platform/agent/register creates: a workspace, the organization linked to it, a default classroom, a live Content key, and 50 trial credits.

Workspace

The Agent Platform's record of the account: its name, slug, email, email verification state, and the rate limit of the account routes. The Agent Platform dashboard lists workspaces. register, GET /v1/platform/agent/account, and GET /v1/platform/health return the workspace id as organizationId. That id is not the id of the TutorFlow organization.

Organization

The TutorFlow organization linked to the workspace. It owns the classrooms, all content, and the one credit balance. Content API answers that carry an organizationId, such as a webhook endpoint, carry this organization's id, which differs from the workspace id. The person who verifies the account email becomes an admin of this organization and can open its content in the TutorFlow editor.

Classroom

The place content lives inside the organization. Every Content API path names one: /v1/content/classrooms/{classroomId}/.... An agent account has two:

  • defaultClassroomId: where a live key works. Returned by register and by GET /v1/platform/agent/account.
  • sandboxClassroomId: the only classroom a test key reaches. null until the account has a test key. It has no public pages.

GET /v1/content/classrooms lists the classrooms a key reaches.

Content key and legacy key

  • Content key: a key that starts with tf_content_. Register returns one as contentApiKey; the dashboard creates more. It works on the Content API (/v1/content/**) and, if it is a live key with full access, on the account routes (/v1/platform/agent/*).
  • Legacy key: a key that starts with tf_platform_. Register used to return one as apiKey; it now answers apiKey: null and issues none. An older account may still hold one. It signs only the account routes, /v1/platform/health, and LTI registrations. The Content API answers it with 401 content_platform_key_not_accepted.

Test key and live key

  • Live key: a Content key that starts with tf_content_ and not tf_content_test_. It works in defaultClassroomId and spends credits.
  • Test key: a Content key that starts with tf_content_test_. It works only in sandboxClassroomId, spends no credits (priced routes answer with canned content), and cannot call the account routes (403 platform_content_key_too_narrow). Create test keys in the Agent Platform dashboard.

Credits and dollars

Prices, balances, and charges are counted in credits. One credit costs 2 US cents, so 50 credits are $1.00. Dollars appear only in three places: top-up amounts ($5 to $5,000), the *Usd fields of the pricing catalog, and the Stripe invoice for an overdraft. creditBalance on the account routes is the balance in cents, not dollars: credits × 2. Read credits.

Trial credits are the 50 credits a new agent account starts with. They need no email verification and no payment method.

Metered overdraft

Once a person has paid through Stripe checkout, the account has a card on file and is metered (isMetered: true). When the balance reaches 0, priced calls keep working and draw credits up to overdraftLimit. The overdraft used (overdraftCredits) is billed to the card at 2 cents per credit. Past overdraftLimit, priced calls answer 402. See Metered overdraft.

Run

The background job a generate route starts. The route answers 202 with a runId; GET /v1/content/classrooms/{classroomId}/runs/{runId} reports status, progress, and creditsCharged. See Follow a Generation.

Steps that need a person

An agent does everything here alone, except three steps:

  • Opening the email verification link. Buying credits needs a verified email.
  • Paying on the Stripe checkout page that POST /v1/platform/agent/billing/session returns. An agent with USDC on Base can pay over x402 instead.
  • Changing content in the TutorFlow editor at a resource's editorUrl, if a person should change it. To let a person only look at the result, the agent sends publicUrl instead, which needs no sign-in. See Show the work to a person.

Where to go next

  1. Quick Start: the full register and account answers, field by field.
  2. Authentication: which key works on which route, and the errors a wrong key gets.
  3. Generate Your First Content: one course, one evaluation, and what each cost.
  4. Follow a Generation: poll runs, resume a failed one, or receive a webhook.
  5. Pricing and Billing: prices in credits, top-ups, metered overdraft, and the 402.
  6. Other ways to call: MCP, the CLI, or an LMS over LTI 1.3.
  7. Production: Error Handling and Rate Limiting.

Every Content API route, with its scope and answer, is in the Content API Reference.