- An API key, kept on your server.
- One backend call per sign-in —
POST /v1/api/projects/embed-token— which returns a token for the user. - 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
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
Callembed-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:
token and expiresAt to the browser.
3. Embed the iframe
- Workspace (AI chat)
- Application (dashboards)
- 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, addhttps://ai-hub.upsolve.aitoframe-src.
Row-level security
The properties you send are what the workspace’s or application’s row-level security rules filter on. A rule like{{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.
Database-native RLS (Postgres, Redshift, Supabase)
Database-native RLS (Postgres, Redshift, Supabase)
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:
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
- Workspace (AI chat)
- Application (dashboards)
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.