Use your own appointment video
Your video provider can run the call alongside PlaySpace's shared activities. Supply a clinician URL and a patient URL when you book each virtual appointment. PlaySpace delivers each participant only their own URL, and your provider owns the call's camera, microphone, participant, and call controls. PlaySpace's optional audio recording operates independently, as described below.
PlaySpace supports an inline video page and an explicit separate-window option. Your provider does not need to emit PlaySpace or Whereby events. PlaySpace's configurable waiting room controls access to activities independently of the provider's admission flow.
Enable the integration
Ask for partner video on the registration form, or afterwards through your PlaySpace contact. Either way PlaySpace approves the exact HTTPS origins your video links use, and either way enablement is a decision a person takes — the registration form records the request, it does not turn anything on. At least one origin must be approved before enablement. An origin is the scheme, hostname, and optional port, such as https://video.example.com; paths, query strings, fragments, and wildcard hostnames are not origins. Approval covers the whole origin: once https://video.example.com is approved, any page on it can be supplied, so keep pages you do not fully control, such as user-uploaded content, on a different origin.
Read the resulting settings with GET /v1/partner/session-config, using practitioners:read:
{
"data": {
"supplied_video": {
"enabled": true,
"approved_origins": ["https://video.example.com"],
"revision": 2
}
}
}
This is an excerpt of the response. supplied_video is always read-only to partners. Neither partner_editable_fields nor enabled_features grants permission to change it. Enabling it leaves the organization's existing video_provider setting and existing appointments unchanged.
Book an appointment
Once enabled, every new virtual appointment requires both URLs. Submit them in a strict video object on POST /v1/partner/appointments, with appointments:write and a fresh Idempotency-Key:
{
"partner_clinic_id": "00000000-0000-4000-8000-000000000001",
"partner_practitioner_id": "00000000-0000-4000-8000-000000000002",
"partner_patient_id": "00000000-0000-4000-8000-000000000003",
"start_at": "2026-10-15T14:00:00Z",
"end_at": "2026-10-15T14:50:00Z",
"session_type": "virtual",
"video": {
"clinician_url": "https://video.example.com/room/host?credential=example-host",
"patient_url": "https://video.example.com/room/guest?credential=example-guest",
"label": "Our video room",
"expires_at": "2026-10-15T15:30:00Z",
"presentation": "inline"
}
}
Use your own identifiers, schedule, and provider credentials. The example URLs are placeholders.
| Field | Contract |
|---|---|
clinician_url |
Required HTTPS URL for the clinician's privileges; approved origin |
patient_url |
Required HTTPS URL for the patient's privileges; approved origin |
label |
Optional display label, up to 80 characters; keep it free of patient details |
expires_at |
Optional offset-aware datetime covering the scheduled appointment; checked again before URL delivery |
presentation |
inline or external; defaults to inline |
PlaySpace validates the URL and origin without requesting the provider page. Signed paths, query strings, and fragments are preserved. Provider URLs are encrypted in storage and are never returned in general appointment responses. Do not send them in notes, labels, notification content, or analytics.
The video object is rejected for in-person appointments and organizations where partner video is disabled. Existing appointments keep the video ownership they had at creation: a platform-video appointment cannot be converted, and partner video cannot be removed from an appointment.
Update or reschedule
Use PATCH /v1/partner/appointments/{id} with appointments:write and a fresh Idempotency-Key. A supplied video object replaces the complete pair atomically, including optional metadata. Omitting video preserves it on ordinary edits.
Changing the appointment times requires submitting both URLs again. You may resubmit the same pair if it remains valid for the new schedule. For example:
{
"start_at": "2026-10-15T15:00:00Z",
"end_at": "2026-10-15T15:50:00Z",
"video": {
"clinician_url": "https://video.example.com/room/host?credential=example-host-v2",
"patient_url": "https://video.example.com/room/guest?credential=example-guest-v2",
"expires_at": "2026-10-15T16:30:00Z",
"presentation": "inline"
}
}
To replace links without rescheduling, send video alone. The new pair takes effect on the next join or when a participant explicitly selects Reload video. Ongoing calls never switch automatically. A failed reload preserves the current call.
If platform configuration changes while a write is being validated, the request can return a retriable 409 conflict. Read the current configuration, check your URLs against it, and submit a new request with a fresh idempotency key. The appointment and its required video details are accepted together or neither is accepted.
Open the PlaySpace session
POST /v1/partner/appointments/{id}/session-links stays bodyless and requires only appointments:read, with an Idempotency-Key as for other Partner API POSTs. Do not submit provider URLs there.
clinician_video_url and patient_video_url remain PlaySpace entry links, each a short https://<host>/join/<code> address that redirects to that participant's PlaySpace session credential — so the short link is the credential. Deliver each to the right person over your existing secure channel. Both links remain available for a partner-video virtual appointment even if the organization's video_provider is None.
General appointment responses expose only non-secret video metadata:
{
"video": {
"ownership": "partner",
"label": "Our video room",
"presentation": "inline",
"expires_at": "2026-10-15T16:30:00Z"
}
}
An appointment with platform-owned video reports {"ownership":"platform"}. Keep the provider URL pair in your own secure system if you need it for later rescheduling; the Partner API does not reveal it back to you.
Inline and separate-window video
For inline presentation, your provider must allow its page to be framed by the PlaySpace session origin and support camera and microphone in that frame. PlaySpace sends no provider-specific commands and does not infer attendance or connection from an iframe loading.
PlaySpace takes a URL and nothing else. It never accepts HTML, an <iframe> snippet or a script to place in the pane; what it places there is its own <iframe> with your URL as its src. That frame delegates camera, microphone, display-capture, fullscreen, autoplay and speaker-selection to your page, and it is sandboxed: your page can run script, keep its own origin and storage, submit forms, open pop-up windows and show dialogs, but it cannot navigate the PlaySpace tab away, start a download or lock the pointer. A page that needs one of those will not work inline; use presentation: "external" for it.
Participants can select Open video separately at any time. PlaySpace first removes the inline frame, then opens that participant's same URL using noopener,noreferrer. A retry action remains available if the browser blocks the window. Activity navigation never starts another inline call after this handoff.
Returning inline is explicit: the participant is asked to leave the separate video call first, then confirms reopening it inside PlaySpace. For presentation: "external", the session presents the separate-window action without mounting an inline frame.
Providers that cannot be framed
Some providers forbid every third-party site from placing their call page in an iframe. Google Meet, Zoom's web client and Microsoft Teams all do. This is a decision the provider enforces in the browser, not a PlaySpace limitation, and there is no PlaySpace setting, approved origin or partner programme that lifts it. For these providers use presentation: "external" from the first booking.
Why the frame stays blank
A browser decides whether a page may render inside another site's iframe from two response headers the framed site sends: X-Frame-Options (DENY or SAMEORIGIN) and the newer Content-Security-Policy: frame-ancestors directive, which lists the origins allowed to frame the page. Either one is enough to refuse. The check is enforced by the browser on the participant's machine before any of the page's own code runs, so neither PlaySpace nor your integration can observe the refusal, negotiate around it or inject a header the provider did not send. The frame simply shows the browser's own "refused to connect" placeholder.
For example, every Google Meet page answers with x-frame-options: SAMEORIGIN, which permits framing only by pages on the same Google origin:
$ curl -sI https://meet.google.com/new | grep -i x-frame-options
x-frame-options: SAMEORIGIN
Whereby and Daily omit these headers because embedding is part of their product. Run the same check against your provider's actual meeting URL, not its marketing site, before choosing a presentation. A provider that sends frame-ancestors with an explicit origin list will only frame on origins the provider itself has approved, which PlaySpace's session origin will not be on unless you have arranged that with the provider.
What to send
- Set
presentation: "external"when you book. PlaySpace then never mounts a frame for that appointment and shows each participant an Open video window action instead. - Approve the provider's origin as usual, for Google Meet
https://meet.google.com. The origin check applies regardless of presentation. - Providers of this kind usually issue one link per meeting rather than one per role; the host is whichever account is signed in. Send the same URL as both
clinician_urlandpatient_url. The contract accepts an identical pair. - Set
expires_atto the meeting's own expiry if the provider has one, otherwise to the end of the appointment window.
If you send presentation: "inline" for such a provider, the booking is accepted, the participant sees a blank frame with the browser's refusal message, and they must select Open video separately themselves to recover. Avoid offering Return video here in your own guidance for these providers; returning inline would mount the same blank frame.
What participants experience
The call and PlaySpace run in two browser tabs or windows for each participant. PlaySpace opens the provider URL with noopener,noreferrer, so it cannot see whether the call connected and has no signal to close or refocus the other tab. Participants move between the two themselves.
Two independent admission flows apply. The provider's own lobby governs who is in the call; PlaySpace's waiting room governs who sees the shared activities. A clinician admits the patient in both places. Check your provider's guest policy: Google Meet, for instance, may refuse a participant who is not signed in to a Google account before they can even knock, depending on the meeting's access type (Open, Trusted or Restricted) and the host organisation's Workspace settings. If your patients will not have provider accounts, confirm anonymous guests can request to join before you go live.
PlaySpace's independent audio recording works unchanged with an external call: the microphone is shared between the provider tab and the PlaySpace tab, and both must stay open for the recording to capture the participant. The recording controls and disclosure remain in the PlaySpace tab only.
Independent PlaySpace audio recording
Partner video supports PlaySpace's audio recording and AI note-taker. Availability follows the organization's recording_enabled setting, its active PlaySpace session configuration, and the clinician's clinical-notes access. A failed configuration read leaves recording unavailable. Only the clinician can start or stop recording; the patient contributes audio without receiving recording controls.
When enabled, PlaySpace uses a separate microphone connection for each participant, with the recording disclosure shown in the PlaySpace session. A patient waiting for PlaySpace admission does not join that audio connection. Both participants must keep PlaySpace open and allow its microphone access so both sides can be recorded.
Muting or leaving the provider call does not mute or stop PlaySpace capture. Opening video separately, returning inline, reloading video, or losing access to a provider link does not control the independent audio connection. Use PlaySpace's recording control to stop the recording. Your provider's native recording controls, if any, remain separate.
Unavailable video
Disabling the integration, removing an approved origin, reaching a supplied expiry, or cancelling an appointment prevents new provider-URL delivery. Invalid encrypted details also fail closed. Participants see an unavailable video state; independently authorized PlaySpace activities and audio recording can remain usable. Video availability does not change the organization's recording setting or the clinician's recording access. PlaySpace never falls back to creating a default video room.
Disablement preserves the appointment's partner-video ownership and prevents supplied-video writes. Cancellation remains available. Re-enabling requires the current origin and expiry checks to pass before URLs can be delivered again.
These controls do not revoke provider credentials already delivered or terminate an external call. They also do not introduce general revocation of previously issued PlaySpace session tokens. Use your provider's own controls when you need to end a call or revoke its links.
Providers verified with this contract
PlaySpace sends no provider-specific commands, so any provider that issues a distinct HTTPS link per role and allows its page to be framed can be used. Two have been driven through the generic renderer end to end:
| Provider | clinician_url |
patient_url |
|---|---|---|
| Whereby | hostRoomUrl from the Whereby meetings API (the room URL carrying the host key) |
roomUrl |
| Daily prebuilt | Room URL plus ?t= an owner meeting token |
Room URL plus ?t= a non-owner meeting token |
In both cases approve the account's provider subdomain as the origin, keep the pair in your own secure system, and set expires_at to the provider room's expiry. Providers that refuse framing, such as Zoom, Google Meet and Microsoft Teams, work only with presentation: "external"; see Providers that cannot be framed. Providers that need an SDK and a token rather than a URL are supplied by hosting your own video page.
Host your own video page
The URL you supply does not have to belong to a video company. It can be a page on your own origin that runs whatever video technology you use: a vendor's JavaScript SDK with a meeting token, a vendor's embed inside a further frame, or a WebRTC client you wrote. PlaySpace treats that page exactly as it treats a Whereby room. It frames it, delegates the camera and microphone to it, and asks nothing of it.
This is the route for providers that need an SDK and a token rather than a link, such as Zoom's Video SDK, Twilio or Agora. Approve your own origin, build one page per role or one page that reads the role from its own signed query string, and submit those two URLs when you book.
Your page has to do three things:
- Allow PlaySpace to frame it. Send no
X-Frame-Options, or aContent-Security-Policy: frame-ancestorsthat lists the PlaySpace origin your appointments open on. - Let the camera and microphone through. If your page, or a CDN in front of it, sends a
Permissions-Policyheader, it must permitcameraandmicrophoneforself; the header wins over the frame'sallowattribute. If your page nests a vendor frame of its own, that inner<iframe>needs its ownallow="camera; microphone", because permission is delegated one frame level at a time. - Carry its own credential. Anything your page needs to join the call rides in the URL you supplied, which PlaySpace stores encrypted and delivers only to that role. Keep patient details out of it.
Work within the sandbox described under Inline and separate-window video: script, same-origin storage, forms, pop-ups and dialogs are available; top-level navigation and downloads are not. Test the page as you would any provider. A blank pane usually means a framing header; a page that loads but never gets a camera usually means a Permissions-Policy header.
Verify before going live
Test clinician and patient privileges with your real provider, including two-way audio/video, native call controls, iframe permissions, and its own lobby. A generic compatibility page alone cannot prove media works. Also verify PlaySpace admission, synchronized activities, resizing and reconnects without restarting video, explicit link reload, framing refusal, blocked popups, and explicit return from a separate window.
If you enable PlaySpace recording, verify the disclosure, absence of patient audio capture before PlaySpace admission, clinician start/stop controls, and a recording containing both participants. Check that provider mute/leave and separate-window video keep their independent behavior, and that disabling recording or denying clinician access prevents recording.
See Testing and going live for the wider launch checks, and the API reference for the full request schemas.