After this guide an agent can find TutorFlow, register, work on its trial credits, and ask a person for a top-up, all without anyone setting it up first. Terms such as workspace, classroom, and Content key are defined in Terms.
Overview
An AI agent can start with TutorFlow on its own:
- Discover the service from a public manifest.
- Register an account in one
POSTand receive a livetf_content_key (contentApiKey) and a classroom (defaultClassroomId). - Spend the 50 trial credits ($1.00) at once, on the Content API, with no email verification, no payment method, and no person in the loop.
- When credits run out, get a checkout link and forward it to a person, or pay in USDC.
Using Claude or another MCP client? See MCP Integration. The MCP server covers registration, billing, pricing, courses, and evaluations as tools.
Quick reference
| Step | Route | Auth | Needed for the trial? |
|---|---|---|---|
| 1. Discover | GET /v1/platform/.well-known/agent.json | None | No |
| 2. Register | POST /v1/platform/agent/register | None | Yes |
| 3. Find the classroom | GET /v1/platform/agent/account | Live key | Optional: register already returns defaultClassroomId |
| 4. Work | /v1/content/classrooms/{classroomId}/... | Key | Yes |
| 5. Verify the email | POST /v1/platform/agent/verify-email/resend | Live key | No, only before buying credits |
| 6. Buy credits | POST /v1/platform/agent/billing/session or the x402 routes | Live key | No |
The shortest path is step 2, then step 4.
1. Discovery
curl https://api.tutorflow.io/v1/platform/.well-known/agent.jsonAn abridged answer:
{
"schema": "https://tutorflow.io/agent-manifest/v3",
"name": "TutorFlow Agent Platform",
"baseUrl": "https://api.tutorflow.io/v1/content",
"accountBaseUrl": "https://api.tutorflow.io/v1/platform/agent",
"auth": {
"type": "bearer",
"header": "Authorization",
"prefix": "tf_content_",
"testPrefix": "tf_content_test_"
},
"registration": {
"endpoint": "/v1/platform/agent/register",
"method": "POST",
"requiredFields": ["name", "slug"],
"optionalFields": ["email", "agentIdentity"],
"returns": ["contentApiKey", "defaultClassroomId", "contentApiBaseUrl"]
},
"services": ["course", "module", "test", "slide", "video", "game", "evaluation"],
"capabilities": {
"course": {
"endpoint": "POST /v1/content/classrooms/{classroomId}/courses/generate",
"unit": "lesson",
"unitPriceUsd": 0.06,
"basePriceUsd": 0.06
},
"evaluation": {
"endpoint": "POST /v1/content/classrooms/{classroomId}/evaluations",
"unit": "request",
"unitPriceUsd": 0.02
},
"video": {
"endpoint": "POST /v1/content/classrooms/{classroomId}/videos",
"unit": "video",
"unitPriceUsd": 0
}
},
"addOns": {
"video_narration": { "endpoint": "POST /v1/content/classrooms/{classroomId}/videos/{id}/narration", "unit": "scene", "unitPriceUsd": 0.02 },
"video_render": { "endpoint": "POST /v1/content/classrooms/{classroomId}/videos/{id}/render", "unit": "render", "unitPriceUsd": 0.1 }
},
"trial": {
"creditsUsd": 1,
"credits": 50,
"centsPerCredit": 2,
"emailVerificationRequiredForTrial": false,
"emailVerificationRequiredForBilling": true
},
"pricing": { "endpoint": "/v1/platform/pricing-catalog", "currency": "USD", "model": "per_unit" },
"docs": "https://tutorflow.io/agent-platform/docs",
"health": "/v1/platform/health"
}Replace {classroomId} in the endpoints with your defaultClassroomId. Where x402 is enabled, the manifest also carries x402 and a paymentMethods.usdc entry.
2. Registration
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Account display name. |
slug | string | Yes | Unique identifier. Lowercase letters, numbers, and hyphens; cannot start or end with a hyphen. |
email | string | No | The email of the person responsible for the account. Not needed for the trial, but buying credits needs it verified, and there is no public route to add it later. |
agentIdentity | string | No | Free-form identity, such as "claude-opus via LangChain". |
curl -X POST https://api.tutorflow.io/v1/platform/agent/register \
-H "Content-Type: application/json" \
-d '{
"name": "My AI Tutor",
"slug": "my-ai-tutor",
"email": "operator@example.com",
"agentIdentity": "claude-opus via LangChain"
}'201 Created. The fields that matter:
{
"contentApiKey": "tf_content_...",
"defaultClassroomId": "00000000-0000-4000-8000-000000000010",
"contentApiBaseUrl": "https://api.tutorflow.io/v1/content",
"trialContentCredits": 50,
"requiresEmailVerification": true,
"verifyEmailResendEndpoint": "POST /v1/platform/agent/verify-email/resend"
}The full answer is in Quick Start. Its apiKey and keyPrefix are null: register no longer issues legacy tf_platform_ keys.
Register is limited to 5 attempts per IP per rolling hour, failed attempts included. Register once and keep the key; over the limit the answer is 429 platform_rate_limit_exceeded with Retry-After.
Store
contentApiKeyat once. Only its hash is kept; the raw key is never returned again.
Registration creates a TutorFlow organization for the account, a default classroom, and the key. requiresEmailVerification: true does not block anything until you buy credits. An account that is never verified and never used is closed after 7 days.
3. Find the classroom
defaultClassroomId from registration is the classroom for every Content API call. You can read it again, with the balance, at any time:
curl https://api.tutorflow.io/v1/platform/agent/account \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"The answer is described in Quick Start.
4. Work on the Content API
With the key and the classroom, call the Content API:
# Generate a course: 202 with a run
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 course", "lessonCount": 5 }'
# Follow the run
curl "https://api.tutorflow.io/v1/content/classrooms/$CLASSROOM_ID/runs/$RUN_ID" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"
# Grade an answer
curl -X POST "https://api.tutorflow.io/v1/content/classrooms/$CLASSROOM_ID/evaluations" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"evaluationType": "open_ended",
"questionText": "What causes seasons on Earth?",
"learnerAnswer": "The tilt of the Earth axis causes seasons.",
"maxScore": 10,
"language": "en"
}'Tests, modules, and slide decks are generated the same way as courses. Videos, games, and simulations are built in steps. See Generate Your First Content, Follow a Generation, and the Content API Reference.
Generated resources carry editorUrl and publicUrl. To let a person look at the work, send publicUrl, which opens without an account. To let a person change it, send editorUrl, which needs a TutorFlow sign-in as an admin of the account's organization: at first only the person who verified the account email. See Show the work to a person.
5. Email verification
Verification is not needed for the trial. It is needed before any purchase. Send or resend the link:
curl -X POST https://api.tutorflow.io/v1/platform/agent/verify-email/resend \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"The person who owns the email opens the link, which calls GET /v1/platform/agent/verify-email?token=.... The agent cannot do this step; it can only ask. Without an email on file, the resend call answers 400 platform_invalid_request, and the account cannot buy credits. Verifying also makes that person an admin of the account's organization, so they can sign in to TutorFlow and open editorUrl links. If they have no TutorFlow account yet, one is created and they get an email to set a password.
6. Buy credits
When a Content API call answers 402 content_payment_required, nothing was charged. Do not block on a person. Instead:
- Call
POST /v1/platform/agent/billing/sessionand send the returnedurlto a person over Slack, email, or chat. They choose $5 to $5,000 and pay through Stripe. - Carry on with work that does not need credits.
- Retry once
GET /v1/platform/agent/billing/statusorGET /v1/platform/agent/accountshows enoughcredits. Use the sameIdempotency-Key.
curl -X POST https://api.tutorflow.io/v1/platform/agent/billing/session \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"{
"url": "https://tutorflow.io/agent-platform/checkout?token=...",
"sessionId": "..."
}sessionId is the TutorFlow checkout token, not a Stripe session id. The link is valid for one hour.
With an unverified email, this call answers 403 email_verification_required. Verify first (step 5).
Pay with USDC instead
Where x402 is enabled, an agent with USDC on Base can buy credits without a card: ask POST /v1/platform/agent/billing/x402/deposit for an address, pay it, then send the payment to POST /v1/platform/agent/billing/x402 in the x-payment header. See Pricing and Billing.
Metered overdraft
Once a person pays through checkout, the card is on file and the account becomes metered: it may overdraw up to its overdraftLimit, and the overdraft is billed to the card at 2 cents per credit. See Pricing and Billing.
Route summary
| Method | Route | Auth | Description |
|---|---|---|---|
GET | /v1/platform/.well-known/agent.json | None | Discovery manifest |
GET | /v1/platform/pricing-catalog | None | Prices |
POST | /v1/platform/agent/register | None (IP throttled) | Register an account |
GET | /v1/platform/agent/verify-email?token= | None | Verify the email (from the email link) |
POST | /v1/platform/agent/verify-email/resend | Live key | Resend the verification email |
GET | /v1/platform/agent/account | Live key | Account, balance, classroom ids |
GET | /v1/platform/agent/billing/status | Live key | Payment method and balance |
POST | /v1/platform/agent/billing/session | Live key | Checkout link for a person |
POST | /v1/platform/agent/billing/x402/deposit | Live key | USDC deposit address |
POST | /v1/platform/agent/billing/x402 | Live key | Credit a paid USDC deposit |
GET | /v1/platform/agent/checkout?token= | None | Validate a checkout token (used by the checkout page) |
POST | /v1/platform/agent/checkout | None | Create the Stripe session (used by the checkout page) |
"Live key" means a live tf_content_ key with full access, like the one registration returns. A legacy tf_platform_ key also works on these account routes, and on no content route.