Simulations are reachable from the Content API with the same operations the admin UI has, and at the same credit cost. The API routes through the very services the UI calls, so nothing about access, validation, or pricing differs between the two.
All routes live under /v1/content/classrooms/{classroomId}/simulations and take a tf_content_ key.
What a simulation is
A model a learner perturbs. There is no winning, no losing, and no score; the learner moves controls and reads what changes. If you want something with a score, you want Games instead.
Resource operations
| Method | Path | Success response |
|---|---|---|
POST | /simulations | 201 with the created simulation |
GET | /simulations | 200 with a page of simulations |
GET | /simulations/{id} | 200 with the simulation, including its built HTML |
PATCH | /simulations/{id} | 200 with the updated simulation |
DELETE | /simulations/{id} | 200 with the deleted simulation |
POST | /simulations/{id}/versions/{version}/restore | 200 with the restored simulation |
POST /simulations honours the Idempotency-Key header, like the other content resources. A retried create with the same key returns the simulation made the first time rather than a second one.
Restoring a version runs no model and charges nothing. It copies the chosen version forward as the newest one rather than rewinding, so nothing an educator made is lost and a restore is itself reversible.
Reading a simulation returns its HTML
GET /simulations/{id} includes a content field holding the built simulation as a complete HTML document. It can be large.
GET /simulations does not include it. List responses carry metadata only, so paging through a classroom stays cheap. Fetch the content for the one simulation you actually need.
The contentKey field is TutorFlow's internal storage reference. Treat it as opaque and read the simulation through the API rather than trying to address that key yourself.
Fields worth knowing
brief holds the plan the build was generated from: the quantities the model tracks, the controls with their ranges and starting values, and the questions a learner is meant to answer by moving them. It is the most useful thing to read if you want to know what a simulation actually does without parsing its HTML.
subject is chosen by the planner, not by you, and is one of computer-science, ai-ml, finance, business, math, science, other. representation is always 2d-canvas today.
Generation
Building a simulation is three steps, and each is its own call. They are separate because the plan is cheap and the build is not: reading a plan and rejecting it should not cost what building it costs.
| Method | Path | Credits |
|---|---|---|
POST | /simulations/{id}/brief | 1 |
POST | /simulations/{id}/build | 12 |
POST | /simulations/{id}/revise | 10 |
These are the same prices the admin UI pays, drawn from the organization's AI Credit balance. Check the balance with GET /v1/content/credits before a batch.
POST /simulations/{id}/brief accepts an optional referenceMarkdown body field to ground the plan in your own material. POST /simulations/{id}/revise takes a feedback field describing the change in plain language, the same way the chat panel in the editor does.
These three stream
The generation routes respond with text/event-stream, not a JSON body. Read them as Server-Sent Events. The build completes when the stream ends.
Disconnecting aborts the work. If your client hangs up mid-build, the model call stops rather than running to completion unread. That also means a client timeout shorter than a build will cancel the build, so set timeouts with the build duration in mind rather than the default.
A typical run
POST /simulationswith a title, and keep the returned id.POST /simulations/{id}/briefwith the principle you want learners to work out. Read the plan from the stream.- Inspect
brief. If the model is wrong, ask for another brief. This is the cheap point to change your mind, and a simulation that computes the wrong thing is the failure this content type is most prone to. POST /simulations/{id}/build. Wait for the stream to end.GET /simulations/{id}to read the built document and its version history.POST /simulations/{id}/revisewith feedback if something needs changing.PATCH /simulations/{id}withvisibility: "PUBLIC"when it is ready to share, and hand out its link.
What the build guarantees
Every generated version is checked before it is stored. Beyond validating the page, TutorFlow runs the simulation and drives each declared control from one end of its range to the other, watching whether the drawing actually changes. A version whose sliders move and whose picture does not is rebuilt rather than returned, because that failure passes every static rule and is useless in a classroom.
That check confirms the simulation responds. It does not check that the arithmetic is right, and it does not judge whether the subject or the difficulty suits a particular class. An integration that publishes automatically is publishing something no person has opened. Read the brief at minimum, and open the built document before it reaches learners.