Skip to main content
Your users get an Upsolve workspace (the AI chat) or application (dashboards) inside your product, signed in as themselves and limited by row-level security to their own data. It takes three things:
  1. An API key, kept on your server.
  2. One backend call per sign-in — POST /v1/api/projects/embed-token — which returns a token for the user.
  3. An iframe that carries the token.

Set it up with an AI coding assistant

The fastest way: open your workspace’s Deploy page in Upsolve, click Create an API key, and copy the Setup prompt. It already contains your organization, project and workspace ids and the exact properties your row-level security reads. Paste it into Claude Code, Cursor or any coding assistant working in your product’s codebase. Or copy this one and replace the values in angle brackets — all of them are on the Deploy page:
Setup prompt
The rest of this page is what that prompt does, step by step.

1. Get an API key and your ids

  • API key. In Upsolve, open Account settings → Developer (ai-hub.upsolve.ai/account/settings?tab=developer) and generate a key. Store it on your server, for example as UPSOLVE_API_KEY. It must never reach the browser.
  • Ids. A workspace’s Deploy page lists the Organization ID (your Upsolve organization), Project ID and Workspace ID, each with a copy button. An application’s id is on its Deploy panel.

2. Sign your users in

Call embed-token from your backend whenever a user opens a page with the embed. The first call for a customer creates them as a project organization, the first call for a user creates them as a project user, and every later call finds the same rows by your ids and merges in the properties you send. A call that changes nothing writes nothing, so there is nothing to register in advance and nothing to store.
Response
The same call in Node:
Take the user and tenant from your own session, never from the request, and return only token and expiresAt to the browser.

3. Embed the iframe

The embed serves the workspace’s production version: publish the workspace and promote a version first.
  • URL-encode the token.
  • Fetch a new token once about 80% of its lifetime has passed (never sooner than 30 seconds) and set it as the new src. That reloads the embed; a workspace keeps the user’s conversation history. To replace it without a reload, use token handoff.
  • If your app sends a Content-Security-Policy, add https://ai-hub.upsolve.ai to frame-src.
A minimal React page:

Row-level security

The properties you send are what the workspace’s or application’s row-level security rules filter on. A rule like
shows each user only their own customer’s orders: {{organization.tenant_id}} is replaced with organization.properties.tenant_id, and {{user.<key>}} with user.properties.<key>. The Deploy page’s setup prompt lists the exact keys your production rules read. Write the rules in the workspace’s Data Model — see Row-Level Security — and check them by signing in as users of two different customers. A property the rules read but the user does not have makes the query fail rather than return everything.
If your database enforces row-level security itself, pass the value its policies read as dbAuthToken on an application embed: …/share/application/<APPLICATION_ID>?jwt=<token>&dbAuthToken=<value>. For Postgres and Redshift it is the value your session variable expects (a tenant or user id); for Supabase it is the user’s session access token (supabase.auth.getSession()). See RLS & Schema Filtering.

Keep the token out of the URL

A token in ?jwt= is written to every access log between your user and Upsolve. With token handoff the iframe asks your page for it over postMessage instead, and a refreshed token replaces the old one without reloading the embed. It works on /share/workspace, /share/application and /share/dashboard. Open the iframe with tokenHandoff=true and your page’s origin, and no jwt:
Post embed:set-token again with a fresh token before expiresAt to replace it in place. The iframe accepts a token only from the declared parentOrigin and its own parent window, keeps it in memory only, and shows No token received from the embedding page after 15 seconds without one. The full protocol — live filter sync and auto-height included — is in iframe messaging.

Iframe options

Troubleshooting

Lower-level endpoints

embed-token does in one call what register-organization, register-user and user-token do in three. Those still work, for integrations that manage Upsolve’s ids themselves; a token from user-token goes in the iframe the same way.