Iframe Embeds

The iframe embed system lets you render REC-CAP assessments, goals, progress, and life domains directly inside your own application. Your users see an RCMS-powered experience that fits visually inside your product.

Why iframes (and when to use the API instead)

Iframes and the JSON API serve different purposes. Use the right one for each task:

TaskUse
Provision an organization, staff member, or clientJSON API
Take a REC-CAP assessment, review results, update goalsIframe embed
Sync enrollment status, receive event notificationsJSON API / Webhooks
Display a client's assessment history or progress chartIframe embed

Partners get continuous UI improvements for free — when RCMS adds a new chart or refines a workflow, your embed picks it up on the next page load with no work on your side.

The ten embed routes

All embeds are served from embed.measurerecovery.com — a dedicated subdomain with its own cookie, CSP, and security policies isolated from the main RCMS application.

Context 1: Staff organization-level

Add these to your staff navigation sidebar. Scoped to an organization.

EmbedURL pathRequired permission
Assessments library/org/:orgId/assessmentsassessments:read
Resources/org/:orgId/resourcesresources:read
Goal Templates/org/:orgId/goal-templatesgoal_templates:read

Context 2: Staff client-level tabs

Add these as tabs inside your client record view. Scoped to one client.

EmbedURL pathRequired permission
Assessments tab/clients/:clientId/assessmentsassessments:read, assessments:write
Goals tab/clients/:clientId/goalsgoals:read, goals:write
Progress tab/clients/:clientId/progressprogress:read
Life Domains tab/clients/:clientId/life-domainslife_domains:read, life_domains:write

Context 3: Client portal

Embed these in your client-facing application. The token is scoped to the signed-in client — they see only their own data.

EmbedURL pathWhat the client sees
My Goals/client-portal/goalsActive goals, tasks, progress bars
Assessment/client-portal/assessmentTake or resume their REC-CAP assessment
Progress/client-portal/progressScore trend, domain breakdowns, history

The embed token flow

Iframes can't use your API key directly — that would expose it in the browser. Instead, your backend mints a short-lived embed token (a signed JWT) that authorizes a specific user to see a specific embed. The iframe URL carries the token; RCMS validates it server-side and enforces permissions via Row Level Security.

Partner backend                         RCMS API                  Embed iframe
     |                                     |                            |
     | POST /v1/embed-tokens               |                            |
     | (API key + embed_type + identity)   |                            |
     | --------------------------------->  |                            |
     |                                     | Validate key, mint JWT      |
     |                                     | (30-60 min TTL)             |
     | <---------------------------------  |                            |
     | { token, iframe_url, expires_at }   |                            |
     |                                     |                            |
     | Render <iframe src={iframe_url}>    |                            |
     | ----------------------------------------------------------->      |
     |                                     |                            |
     |                                     | Validate JWT + enforce RLS  |
     |                                     | <------------------------  |
     |                                     | Render REC-CAP UI           |
     |                                     | -------------------------> |

Mint an embed token

curl -X POST https://api-sandbox.measurerecovery.com/v1/embed-tokens \
  -H "Authorization: Bearer rcms_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "embed_type": "clients/260/assessments",
    "staff_user_id": "partner-staff-abc123",
    "permissions": ["assessments:read", "assessments:write"],
    "ttl_seconds": 1800
  }'

Response:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "iframe_url": "https://embed.measurerecovery.com/clients/260/assessments?token=eyJ...",
  "expires_at": "2026-04-18T17:30:00Z",
  "refresh_at": "2026-04-18T17:24:00Z"
}

Request body reference

FieldTypeDescription
embed_typestring, requiredWhich embed to authorize (e.g. clients/260/assessments)
staff_user_idstring, conditionalRequired for staff-context embeds (Contexts 1 & 2). Your identifier for the staff member.
client_user_idstring, conditionalRequired for client-portal embeds (Context 3). Your identifier for the signed-in client.
permissionsstring[], optionalRequested permission scopes. Defaults to the read-only set for the embed.
ttl_secondsnumber, optionalToken lifetime. Default 1800 (30 min). Min 300, max 3600.

Worked examples

Staff view: assessments tab inside a client record

Your staff user opens their client record for Agatha Harkness. You want to embed the RCMS Assessments tab inside your own page.

// Partner backend
const response = await fetch(
  "https://api.measurerecovery.com/v1/embed-tokens",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.RCMS_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      embed_type: `clients/${rcmsClientId}/assessments`,
      staff_user_id: currentUser.id,
      permissions: ["assessments:read", "assessments:write"],
      ttl_seconds: 1800,
    }),
  },
);
const { iframe_url } = await response.json();
return { iframe_url };
<!-- Partner frontend -->
<iframe
  src={iframe_url}
  title="REC-CAP Assessments"
  style={{ width: "100%", height: "800px", border: 0 }}
  allow="clipboard-read; clipboard-write"
/>

Client portal: embed “My Goals” in your app

A client logs in to your platform. You want to show their RCMS recovery goals.

// Partner backend
const response = await fetch(
  "https://api.measurerecovery.com/v1/embed-tokens",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.RCMS_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      embed_type: "client-portal/goals",
      client_user_id: session.rcmsClientId,
      permissions: ["goals:read", "goals:write"],
      ttl_seconds: 1800,
    }),
  },
);
const { iframe_url } = await response.json();

Responsive sizing

RCMS UI is responsive and adapts to its container. Partners should:

What's guaranteed — and what isn't

Contract itemStable?
The 10 embed URL patterns aboveYes — versioned, changes trigger a new major version
Embed token request/response shapeYes
Permission names (assessments:read, etc.)Yes
The set of features visible in each embedYes — we only add, never silently remove
Exact pixel layout, chart positions, widget orderNo — we iterate the UI
Colors, fonts, exact copyNo
New widgets or tabs added inside an embedAdded without notice — partners benefit automatically

Security model

Error handling inside the iframe

If the token is missing, invalid, or expired, the iframe renders a friendly error page that tells the user to refresh. You'll also receive a rcms:token_error postMessage event that your parent app can listen for:

window.addEventListener("message", (event) => {
  if (event.origin !== "https://embed.measurerecovery.com") return;
  if (event.data?.type === "rcms:token_error") {
    // Mint a fresh token and swap iframe src
    refreshEmbedToken();
  }
});

Next steps

Getting Started

Request an API key and make your first call.

API Reference

Full request/response documentation for every endpoint.