This page is for an agent, or the developer building one, that has no TutorFlow account yet. After it the agent has an agent account, a live Content key (tf_content_...), the id of the classroom its content goes into, and 50 trial credits. It takes one request and no payment method. Every request goes to https://api.tutorflow.io.
Every response on this page was recorded from a real account. Ids are shortened, for example 0fce....
1. Create an agent account
With the API
One POST, with no key. You do not need to verify the email to start.
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:
{
"organizationId": "9d4c...",
"apiKey": null,
"keyPrefix": null,
"contentApiKey": "tf_content_...",
"contentApiKeyPrefix": "tf_content_zV8z...",
"defaultClassroomId": "0fce...",
"contentApiBaseUrl": "https://api.tutorflow.io/v1/content",
"trialCredits": 100,
"trialContentCredits": 50,
"message": "Store contentApiKey securely; it will not be shown again. It signs every Content API call and the account routes under /v1/platform/agent. apiKey is null: legacy tf_platform_ keys are no longer issued.",
"requiresEmailVerification": true,
"verifyEmailResendEndpoint": "POST /v1/platform/agent/verify-email/resend",
"nextSteps": {
"createCourse": "POST /v1/content/classrooms/0fce.../courses",
"listCourses": "GET /v1/content/classrooms/0fce.../courses",
"createSlide": "POST /v1/content/classrooms/0fce.../slides",
"createVideo": "POST /v1/content/classrooms/0fce.../videos",
"accountInfo": "GET /v1/platform/agent/account"
}
}Keep two values:
contentApiKeyis the live Content key, the key for everything in these docs. It is shown once, so store it now.defaultClassroomIdis the classroom every Content API call names, as/v1/content/classrooms/{defaultClassroomId}/....
The rest:
| Field | Meaning |
|---|---|
organizationId | The workspace id. It is not the id of the TutorFlow organization that owns the classroom and the balance. No route needs it. |
apiKey, keyPrefix | Always null. Register no longer issues legacy keys (tf_platform_); an older account that holds one can keep using it on the account routes. |
contentApiKeyPrefix | The first characters of contentApiKey, to recognize the key later. It does not authenticate. |
contentApiBaseUrl | https://api.tutorflow.io/v1/content. |
trialContentCredits | The trial balance: 50 credits, worth $1.00 at 2 cents per credit. |
trialCredits | The same grant in cents: 100. It is not a second grant. |
message | The text above, telling the agent to store contentApiKey. |
requiresEmailVerification | true while the account email is not verified. It does not block the trial; it blocks only buying credits. |
verifyEmailResendEndpoint | The route that sends the verification email again. |
nextSteps | Content API routes with the classroom filled in. createCourse creates an empty course; to have TutorFlow write one, call POST .../courses/generate. Likewise createSlide creates an empty deck; to generate one, call POST .../slides/generate. |
Include email if the account may ever buy credits: buying needs a verified email, and there is no public route to add one later. An account that is never verified and never used is closed after 7 days.
If register fails, nothing was created:
| Status | error.code | Cause | What to do |
|---|---|---|---|
422 | platform_invalid_request | Bad slug, bad email, or a malformed body | Fix the field named in the error |
409 | platform_conflict | The slug or the email is already registered | Pick another slug, or reuse the account you already have |
429 | platform_rate_limit_exceeded | More than 5 register attempts from this IP in the past hour; failed attempts count | Wait Retry-After seconds. Register once and keep the key. |
With the dashboard
A developer who prefers a browser can create the same account by hand:
- Sign in at tutorflow.io and open the Agent Platform dashboard.
- Create a workspace if you have none. A workspace is the dashboard's name for the agent account. The
slugtakes lowercase letters, numbers, and hyphens. - Create an API key. Choose Live for a key that works in the default classroom and spends credits, or Test for a key that works only in the sandbox classroom and spends nothing. The raw key is shown once.
2. Store the key and the classroom
The rest of these docs read both from the environment:
export TUTORFLOW_CONTENT_API_KEY="tf_content_..."
export CLASSROOM_ID="0fce..."Keep the key in a secret store or an environment variable, never in source code or in a browser.
3. Check the account
curl https://api.tutorflow.io/v1/platform/agent/account \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"200 OK:
{
"organizationId": "9d4c...",
"name": "My EdTech Agent",
"slug": "my-edtech-agent",
"status": "ACTIVE",
"creditBalance": 100,
"credits": 50,
"overdraftCredits": 0,
"overdraftLimit": 100,
"isMetered": false,
"rateLimitPerMinute": 1000,
"isEmailVerified": false,
"restrictedActions": ["add_payment_method", "usdc_payment", "create_billing_session"],
"createdAt": "2026-10-16T18:42:32.470Z",
"defaultClassroomId": "0fce...",
"sandboxClassroomId": null,
"contentApiBaseUrl": "https://api.tutorflow.io/v1/content",
"contentApiUrls": {
"listClassrooms": "GET /v1/content/classrooms",
"generateCourse": "POST /v1/content/classrooms/0fce.../courses/generate",
"listCourses": "GET /v1/content/classrooms/0fce.../courses",
"generateSlides": "POST /v1/content/classrooms/0fce.../slides/generate",
"generateTest": "POST /v1/content/classrooms/0fce.../tests/generate",
"createVideo": "POST /v1/content/classrooms/0fce.../videos"
}
}| Field | Use it for |
|---|---|
organizationId | The workspace id, as in the register answer. |
defaultClassroomId | The classroom for every call with a live key. Read it here again if you lose it. |
credits | The balance, in credits. creditBalance is the same balance in cents (credits × 2), not dollars. |
overdraftCredits, overdraftLimit, isMetered | The metered overdraft. isMetered is false until a person pays through checkout; until then overdraftLimit does not apply. Paying through checkout raises overdraftLimit to 1,000. |
isEmailVerified | Whether the email was verified. Buying credits needs true. |
restrictedActions | Billing actions that wait for a verified email. They clear once the email is verified. |
sandboxClassroomId | The only classroom a test key reaches. null until the account has a test key. |
contentApiUrls | Your first Content API calls, with your classroom filled in. |
rateLimitPerMinute is the account's limit on the account routes. Each Content API key has its own limit, 60 requests per minute by default; see Rate Limiting.
This route takes a live key. A test key gets 403 platform_content_key_too_narrow; a missing or unknown key gets 401 platform_invalid_api_key.
To check the key on the Content API itself, list the classrooms it reaches:
curl https://api.tutorflow.io/v1/content/classrooms \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"[
{ "id": "0fce...", "name": "My EdTech Agent", "slug": "my-edtech-agent", "locale": "en", "isSandbox": false }
]Test keys and live keys
| Live key | Test key | |
|---|---|---|
| Starts with | tf_content_ | tf_content_test_ |
| Works in | Your default classroom | Only the sandbox classroom |
| Credits | Spent | Never spent; priced routes answer with canned content |
Account routes (/v1/platform/agent/*) | Yes | No |
Registration gives you a live key. Create test keys in the Agent Platform dashboard, and use them to build and test without spending credits. See Authentication and Test Mode.
Next
Generate Your First Content: generate a course, wait for it, open it in the editor, and grade an answer.