Agent Self-Service Onboarding

How an autonomous agent discovers TutorFlow, registers an account, works on the Content API with trial credits, and asks a person to top up when the credits run out.

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:

  1. Discover the service from a public manifest.
  2. Register an account in one POST and receive a live tf_content_ key (contentApiKey) and a classroom (defaultClassroomId).
  3. 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.
  4. 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

StepRouteAuthNeeded for the trial?
1. DiscoverGET /v1/platform/.well-known/agent.jsonNoneNo
2. RegisterPOST /v1/platform/agent/registerNoneYes
3. Find the classroomGET /v1/platform/agent/accountLive keyOptional: register already returns defaultClassroomId
4. Work/v1/content/classrooms/{classroomId}/...KeyYes
5. Verify the emailPOST /v1/platform/agent/verify-email/resendLive keyNo, only before buying credits
6. Buy creditsPOST /v1/platform/agent/billing/session or the x402 routesLive keyNo

The shortest path is step 2, then step 4.

1. Discovery

bash
curl https://api.tutorflow.io/v1/platform/.well-known/agent.json

An abridged answer:

JSON
{
  "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

FieldTypeRequiredDescription
namestringYesAccount display name.
slugstringYesUnique identifier. Lowercase letters, numbers, and hyphens; cannot start or end with a hyphen.
emailstringNoThe 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.
agentIdentitystringNoFree-form identity, such as "claude-opus via LangChain".
bash
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:

JSON
{
  "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 contentApiKey at 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:

bash
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:

bash
# 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:

bash
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:

  1. Call POST /v1/platform/agent/billing/session and send the returned url to a person over Slack, email, or chat. They choose $5 to $5,000 and pay through Stripe.
  2. Carry on with work that does not need credits.
  3. Retry once GET /v1/platform/agent/billing/status or GET /v1/platform/agent/account shows enough credits. Use the same Idempotency-Key.
bash
curl -X POST https://api.tutorflow.io/v1/platform/agent/billing/session \
  -H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY"
JSON
{
  "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

MethodRouteAuthDescription
GET/v1/platform/.well-known/agent.jsonNoneDiscovery manifest
GET/v1/platform/pricing-catalogNonePrices
POST/v1/platform/agent/registerNone (IP throttled)Register an account
GET/v1/platform/agent/verify-email?token=NoneVerify the email (from the email link)
POST/v1/platform/agent/verify-email/resendLive keyResend the verification email
GET/v1/platform/agent/accountLive keyAccount, balance, classroom ids
GET/v1/platform/agent/billing/statusLive keyPayment method and balance
POST/v1/platform/agent/billing/sessionLive keyCheckout link for a person
POST/v1/platform/agent/billing/x402/depositLive keyUSDC deposit address
POST/v1/platform/agent/billing/x402Live keyCredit a paid USDC deposit
GET/v1/platform/agent/checkout?token=NoneValidate a checkout token (used by the checkout page)
POST/v1/platform/agent/checkoutNoneCreate 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.