A game is a playable web page built from a practice objective. Games use the same operations and credit prices as the TutorFlow editor. Every route is under /v1/content/classrooms/{classroomId}/games and takes a tf_content_ key.
Planning, building, revising, restoring, and sharing work the same way for games and simulations, and are described once in Generation: Brief, Build, Revise. This page covers what is specific to games. The full route list is in the API Reference.
The game object
Create, read, update, and restore return the same shape. content appears only on GET /games/{gameId}.
| Field | Notes |
|---|---|
id | Use as {gameId} on later calls. |
classroomId | The classroom the game belongs to. |
title, description | Display text. description may be null. |
visibility | PRIVATE or PUBLIC. A public game opens at its play link without an account. |
slug | A short label TutorFlow assigns. It is not part of any link. |
metadata | An object you own. The keys in Metadata that shapes the plan feed the brief; other keys are stored untouched. |
brief | The plan the build reads. null until a brief is generated or written. See The brief. |
contentKey | Storage reference of the version being served. An opaque identifier, not a URL. null until the first build. |
contentVersion | The version being served. 0 until the first build, then incremented by every build, revision, and restore. |
buildHistory | One entry per version: version, contentKey (opaque), createdAt, source (build, revision, or restore), note with the revision feedback when there was one, and restoredFromVersion on a restore. |
thumbnail | Storage reference of a capture of the opening screen, or null. An opaque identifier, not a URL. |
content | The built game as one complete HTML document, or null before the first build. Only on GET /games/{gameId}. |
createdAt, updatedAt | Timestamps. Sort the list by updatedAt to find recent changes. |
content is the whole page and can be large, so lists never include it. To show a game to people, share its play link (see Share and delete) or serve the HTML from content yourself.
The brief
A generated brief has these fields. Write your own with PATCH /games/{gameId} and a brief object to skip the priced brief call.
| Field | Notes |
|---|---|
title | Short, concrete title for the game. |
pitch | One sentence on what playing it is like. |
coreLoop | The action the player repeats. |
mechanics | Two to five rules or devices the game is built from. |
levels | Two to six entries of name, goal, and twist. |
winCondition, failCondition | What ends a run either way. |
controls | How it is played, by keyboard and by touch. |
Metadata that shapes the plan
The TutorFlow create wizard stores its answers on metadata, and the brief reads the same keys. All are optional. PATCH merges metadata: keys you send replace their old values, and keys you leave out stay.
| Key | Values | Notes |
|---|---|---|
topic | Free text | What the game teaches. Falls back to title. |
audience | Free text | Who plays it. |
objectiveFocus | Free text | The skill a round should exercise. |
mechanic | Free text | A mechanic to build around, if you have one in mind. |
dimension | 2d or 3d | Defaults to 2d. It does not change the price. |
persistence | session or local | Whether progress survives a reload. Defaults to session. |
playLength | short, standard, or deep | Defaults to standard. |
visualStyle | Free text | Art direction for the page. |
language | Language name or code | Language of on-screen text. Set it; it is not inferred. |
referenceMarkdown | Markdown | Your own material to ground the plan. POST /brief can override it per call. |
Create a game
title and visibility are required. Keep new games PRIVATE until a person has played the build.
curl -X POST "$TUTORFLOW_API_BASE_URL/v1/content/classrooms/$CLASSROOM_ID/games" \
-H "Authorization: Bearer $TUTORFLOW_CONTENT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: game:fractions-run:v1" \
-d '{
"title": "Fractions run",
"description": "Practice comparing fractions under time pressure.",
"visibility": "PRIVATE",
"metadata": {
"topic": "Comparing fractions with unlike denominators",
"audience": "Grade 5",
"objectiveFocus": "Decide which of two fractions is larger",
"playLength": "short",
"language": "en",
"externalId": "game:fractions-run"
}
}'The response is 201 with the game object, contentVersion: 0, brief: null.
List games
GET /v1/content/classrooms/{classroomId}/games?page=1&limit=20&field=updatedAt&order=DESC&search=fraction
Authorization: Bearer tf_content_...| Parameter | Default | Notes |
|---|---|---|
page | 1 | 1-based. |
limit | 20 | Values above 100 are clamped to 100. take is a deprecated alias. |
field | createdAt | title, createdAt, or updatedAt. Anything else returns 422 with error.allowedValues. |
order | DESC | ASC or DESC. Ties break on id. |
search | Case-insensitive substring of title. | |
updatedSince | ISO 8601 date-time. Only games updated at or after it. |
The response is the list envelope with game objects without content. The same parameters work on every resource list; see List pages.
Update a game
PATCH /games/{gameId} is partial. It accepts title, description, visibility, brief, thumbnail, and metadata, and returns 200 with the updated game. contentKey and contentVersion belong to the build pipeline and cannot be set.