Language support
Every SDK is generated from the same OpenAPI contract that serves the API, then hand-finished with the ergonomics that make a language feel native — async iterators in TypeScript, enumerables in Ruby, async for in Python, IAsyncEnumerable in .NET. A field that exists in one SDK exists in all of them, because none of them is written by hand.
TypeScript first, and why
TypeScript is first because the user interface is the integration. The differentiating half of this platform is a set of surfaces a person looks at and moves figures around in. Those surfaces render in a browser, and the browser layer of every partner platform we have spoken to is TypeScript, whatever their backend is written in.
A partner on a Rails backend still writes React. So the first SDK is the one that puts a sandtray on a screen, and the server SDK is TypeScript too because the same team will write the token endpoint.
The second consequence is that TypeScript is where the design is proven. Ergonomics that survive contact with the first three integrations get ported outward; ergonomics that do not get fixed before anything is ported.
Available now
@playspace/sdk — server. Node 20 and above, Deno, Bun, and the Vercel and Cloudflare edge runtimes. Identity, sessions, tokens, content, generation, artifacts, exports, the change feed.
@playspace/react — components and hooks. React 18 and 19. Server-component safe.
@playspace/embed — the framework-agnostic browser transport the React SDK is built on. Use it directly on Vue, Svelte, Angular, or no framework at all.
<script type="module">
import { mount } from 'https://cdn.playspace.health/embed/v1/index.js'
mount(document.querySelector('#play'), {
surface: 'sandtray',
fetchToken: () => fetch('/api/playspace/token').then(r => r.text()),
})
</script>
Roadmap
Ordered by partner demand, not by our preference. Each is generated from the same contract and ships with the same test suite translated.
Ruby — playspace gem. Rails is what both of the largest platforms in this category run on, so this is the next server SDK unless a partner asks otherwise first.
Python — playspace package. Sync and async clients from one contract.
C# and .NET — PlaySpace.Sdk on NuGet. IAsyncEnumerable pagination, System.Text.Json, dependency-injection registration.
PHP — playspace/sdk on Packagist, PSR-18 transport.
Java and Kotlin — on the list, not yet scheduled.
If your language is not here, the REST API is complete. No capability is SDK-only. The SDKs remove ceremony — token refresh, idempotency keys, retry, pagination, typed errors — and none of it is difficult to write yourself. The API reference and the OpenAPI document are enough to build a working integration in an afternoon in any language with an HTTP client.
The same call, five ways
Creating a session, in each SDK. Names, casing and idiom follow the language; the contract does not change.
TypeScript
const session = await playspace.sessions.create({
appointment: { externalId: 'appt_11923' },
clinician: { externalId: 'staff_8842' },
participants: [{ patient: { externalId: 'client_55130' } }],
playroom: 'child-default',
})
Ruby
session = playspace.sessions.create(
appointment: { external_id: "appt_11923" },
clinician: { external_id: "staff_8842" },
participants: [{ patient: { external_id: "client_55130" } }],
playroom: "child-default"
)
Python
session = await playspace.sessions.create(
appointment={"external_id": "appt_11923"},
clinician={"external_id": "staff_8842"},
participants=[{"patient": {"external_id": "client_55130"}}],
playroom="child-default",
)
C#
var session = await playspace.Sessions.CreateAsync(new SessionCreate {
Appointment = ExternalRef.Of("appt_11923"),
Clinician = ExternalRef.Of("staff_8842"),
Participants = [ Participant.Patient("client_55130") ],
Playroom = "child-default",
});
HTTP
POST /v1/sessions
Authorization: Bearer eyJhbGci...
Idempotency-Key: 4f81c2a9-...
Content-Type: application/json
{
"appointment": { "external_id": "appt_11923" },
"clinician": { "external_id": "staff_8842" },
"participants": [{ "patient": { "external_id": "client_55130" } }],
"playroom": "child-default"
}
Front-end frameworks
React — @playspace/react, first-class, everything.
Vue, Svelte, Angular, and no framework — @playspace/embed today. It is the transport underneath the React package, so it has the same surfaces, the same events and the same error taxonomy; what it lacks is the component and hook layer.
Framework wrappers — a Vue package and a Svelte package are planned and will be thin. The React package is roughly four hundred lines over the transport, and most of that is the token-renewal contract, which is portable.
Mobile — no native SDK. The surfaces render in a web view today, which works and is how the hosted session link already reaches phones and tablets. A React Native package is on the list behind the server languages.
Versioning
The API is versioned in the path. /v1 is stable. A breaking change means /v2, and /v1 keeps working — we have not deprecated an endpoint yet and will give twelve months' notice before we do.
SDKs follow semantic versioning independently of the API version. An SDK major version is about the shape of the SDK, not the API behind it.
The embed runtime is pinned. https://cdn.playspace.health/embed/v1/ is immutable within a major version. We will not silently swap the runtime under a page you have already shipped, which is a failure mode that other embedded platforms have and that partners have been burned by.
Additive changes ship without a version bump. New fields, new event types, new problem slugs. Every SDK is built to ignore what it does not recognise: an unknown event type is dropped rather than thrown on, and an unknown field is preserved rather than stripped. A host built against today's contract keeps working against next year's.