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 answer | What it is | Use it for |
|---|---|---|
contentApiKey | A live Content key (tf_content_...), shown once | Every call in these docs: content work on /v1/content/** and the account routes on /v1/platform/agent/* |
apiKey | null. Register no longer issues legacy keys | Nothing |
defaultClassroomId | The classroom that live-key content goes into | The {classroomId} in every Content API path |
organizationId | The id of the agent's workspace | Support requests. No route needs it. |
trialContentCredits | 50, the trial credits on the one credit balance | Spending 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.
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.
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.
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 code | When | What the agent does |
|---|---|---|
402 content_payment_required | A 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_removed | A call to a content route under /v1/platform (/courses, /tests, /modules, /slides, /videos, /games, /evaluations, /learners, /webhooks), removed on 2026-10-16 | Do not retry. Move the call to the Content API; error.migrationGuide links the migration guide. |
429 content_rate_limit_exceeded or platform_rate_limit_exceeded | The key (Content API, 60 per minute by default) or the account (account routes, 1,000 per minute) is over its limit | Wait 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, 403 | Wrong key for the route | See Where each key works. |
The 410 body, as production answers it:
{
"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 byGET /v1/platform/agent/account.sandboxClassroomId: the only classroom a test key reaches.nulluntil 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 ascontentApiKey; 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 asapiKey; it now answersapiKey: nulland 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 with401content_platform_key_not_accepted.
Test key and live key
- Live key: a Content key that starts with
tf_content_and nottf_content_test_. It works indefaultClassroomIdand spends credits. - Test key: a Content key that starts with
tf_content_test_. It works only insandboxClassroomId, spends no credits (priced routes answer with canned content), and cannot call the account routes (403platform_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/sessionreturns. 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 sendspublicUrlinstead, which needs no sign-in. See Show the work to a person.
Where to go next
- Quick Start: the full register and account answers, field by field.
- Authentication: which key works on which route, and the errors a wrong key gets.
- Generate Your First Content: one course, one evaluation, and what each cost.
- Follow a Generation: poll runs, resume a failed one, or receive a webhook.
- Pricing and Billing: prices in credits, top-ups, metered overdraft, and the
402. - Other ways to call: MCP, the CLI, or an LMS over LTI 1.3.
- Production: Error Handling and Rate Limiting.
Every Content API route, with its scope and answer, is in the Content API Reference.