Content and generation
PlaySpace makes things. An illustrated storybook written for one child about the thing they are actually working on. A worksheet a clinician drew on with a client. A form built for a caseload and filled in during a session. A sandtray or dollhouse scene, saved and reopened next week. A playroom that decides which of those a session offers at all.
This page says which of it a partner application can reach today, how, and what is deliberately still out of reach. It is written to be checked against the endpoint summary and the @playspace-health/embed reference, not to describe a plan.
Who owns content
Everything on this page belongs to one practitioner. There is no organisation-wide content library on the partner surface and no admin view over another clinician's work.
That is why almost every call here needs a delegated token — one issued acting as a specific practitioner. An organisation-wide token has no practitioner to scope to, and the API answers 403 rather than guessing. The same rule governs embed tokens: an embed is minted for someone, and what a clinician creates inside the frame is owned by them.
What a partner can reach today
| Content | Read | Write |
|---|---|---|
| Storybooks | list, pages, page images, cover, PDF download | generate, make shelf-ready, delete — and create, publish and shelve inside an embedded surface |
| Worksheets | list, pages, page images, cover, PDF download | create and delete from your server; upload, edit, shelve and delete inside an embedded surface |
| Forms | list the clinician's published forms, list and get their submissions | create, make shelf-ready, delete — and author and fill inside the embedded surface |
| Clinical notes | list and get the acting clinician's notes | nothing — authoring is internal |
| Playrooms | list, get, list contents | create, update, attach and detach a storybook or worksheet |
| Toolkits | list, get, list contents | create, update, attach and detach a storybook or worksheet |
| Sandtray and dollhouse | list saves, get a save, save thumbnail | start a two-seat live session; delete a save |
Three access paths lead to that table and they are not interchangeable.
The API, reached with your partner credential from your own server. Everything in the Read column, plus storybook and worksheet creation, playroom and toolkit management, and starting a game session. This is what you call when your backend needs to know what exists or to act without a person present. It is Level 4.
A single embedded surface, rendered in an iframe with @playspace-health/embed and authorised by a short-lived capability token you mint on your server. This is where a clinician makes one thing: writes a storybook, imports a worksheet and draws on it, builds a form or fills one in, plays a sandtray session with a client. Your page never sees the content — it renders in PlaySpace's document and reports back ids and counts. It is Level 3, and each of those surfaces has its own reference page: storybooks, forms, worksheets, games.
The framed workspace, which carries the Creative Suite and the Forms area with their own capability set, so a clinician moves between all of it without your page mounting anything new. It is Level 1.
Answers to a form are the clearest case of the split, and the exception that proves it. You author and fill a form inside the embedded surface; you read the answers back from your own server, through the submissions listing on the form. That listing is the one place on this API where patient-authored clinical content crosses to your side — check status before treating an answer set as final, and handle the payload as the clinical record it is.
What is not on the partner surface
Named explicitly, because a gap nobody names gets assumed away.
- Generated games (PlayStudio) and three-dimensional model generation. Both exist in the product. Neither is externally reachable, in either direction — you cannot start one and you cannot list what a clinician has made.
- The game catalogue, and every session item other than the sandtray and dollhouse.
- Authoring a clinical note. The notes a clinician writes — including the ones PlaySpace drafts from session audio — are readable from your server, as is the verbatim session transcript behind a drafted one when you ask for it a note at a time; both are covered by Read a session note. Creating and deleting a note is internal, and so is every write from your server. The one exception is the clinician's own hand: in the framed workspace, a seat minted
note:writelets them edit, sign and unlock the notes they own without leaving your product. - A client's annotated copy of a worksheet. Worksheet listing covers the clinician's own library; a copy a client has drawn on is clinical content and is never returned.
- A unified index across content types. There is no artifact resource and no cross-type query. If you want to know everything one clinician has, you call each list endpoint.
Generation
One generation capability is on the partner surface: the storybook. Every other generator in the product — worksheets, forms, extracting a form from a document a clinic already uses, games, three-dimensional models — is internal, and none of them is reachable from a partner application by any route.
Storybook generation is reachable two ways.
Inside the embedded surface
The clinician does the writing. You mint a capability token carrying storybook:create, frame mode="create", and listen for events. This is the path most integrations want, because the prompt is a clinical judgement and the person making it is sitting in front of the frame.
The working version of this is Generate a storybook.
From your own backend
POST /v1/partner/storybooks starts a book without a frame — an overnight batch, a template a clinic applies after every intake.
POST /v1/partner/storybooks
Authorization: Bearer <delegated partner token>
Idempotency-Key: storybook-for-appointment-8f42c1
Content-Type: application/json
{
"prompt": "A brave fox who learns to ask a grown-up for help when they feel worried",
"settings": {
"target_age": "6-12",
"number_of_pages": "short",
"lines_per_page": "standard",
"style": "emotional",
"image_style": "watercolor",
"include_character_names": ["Fen"]
}
}
The 201 carries the book in its generating state, with an empty page list and a Location header pointing at it. Illustration takes a minute or two. Poll GET /v1/partner/storybooks/{id} until status is ready or failed; there is no change feed and no callback, so polling is the mechanism rather than a fallback.
When it is ready, GET /v1/partner/storybooks/{id}/download returns the book as a PDF and GET /v1/partner/storybooks/{id}/pages returns the text with signed image links. Those links are short-lived — read them when you need them rather than caching them.
Four things are enforced and none is decoration.
- A delegated token, and the
practitioners:writescope. The owning practitioner comes from the token's claim, never from the body. Idempotency-Keyis mandatory. A retried automation replays the original book instead of paying to generate a second one. Key it on something stable in your own system, such as the appointment the book is for.- The practice must have storybook generation enabled. It is a per-clinic entitlement checked in the service, not a switch in a user interface, so a script hits the same
403a person would. - Generation cannot be cancelled once accepted. The money is spent at the point the
201is returned.
There is no quota, and that is the constraint
There is no metering on any spending surface: no quota endpoint, no per-organisation ceiling, no per-clinician spend reading, and no usage response to warn a practice administrator with. The mandatory idempotency key and the per-clinic entitlement are the only two controls that exist, and neither is a ceiling — they stop you paying twice for the same book and stop a practice generating at all, with nothing in between.
That is why storybooks are the only generation capability exposed. A metered, enforceable ceiling is a prerequisite before any further generator reaches a partner, and it has to exist before the first endpoint rather than after the first invoice. Until then, budget on your side: count what you start, and treat the absence of a 429 for quota as an absence of a safety net rather than an absence of a limit.
Attribution, as it actually works
There is no attribution triple and no artifact index. The grain is simpler and narrower than that: content is owned by the practitioner the delegated token acts as, and that is the whole of it.
- There is no subject on a storybook or a worksheet. A book written for one child is not linked to that child's record in PlaySpace, so the link between the two is yours to hold.
- There is no session link on generated content either. An appointment is not part of a storybook's identity.
- The one place a subject is bound is a form submission, and it is bound at mint time on the token rather than chosen in the frame — see
patientIdin the@playspace-health/embedreference. - Game saves belong to a session, which belongs to a clinician and a patient.
So mintEmbedToken returning practitioner_id, and the ids on every embed event, are the material you record against your own records. Store your own reference from the moment storybook.created fires — it arrives before the first page is written, so you keep the id even if the clinician closes the frame while it is still illustrating.
Handling what comes back
Storybook and worksheet titles are patient-adjacent. A storybook title is model-generated from the clinician's prompt and can echo details of the child the story was written for; a worksheet title is the clinician's own filename or the source document's metadata. Both are fine to render in a clinical interface and are not fine in logs, analytics or a support ticket. Counts and ids are safe everywhere.
Signed asset links are credentials. Page images, covers and PDF downloads come back as short-lived signed URLs. Never log one, never put one in an error message, and never render one anywhere it could be screenshotted alongside a name.
The rest of the handling rules, and what PlaySpace does and does not hold, are on Security and compliance.