Skip to main content
Every embedded user is a project user, and what they may do on a dashboard comes from one place: their role. A role is a named set of permission flags in a project. Each project user has at most one.

View-only unless a role grants editing

A role grants editing only through a flag that says so: addChart, addFilter, createChart, editCharts, removeChart, addDashboard or canDuplicateDashboard set to true. readOnly overrides all of them. Every other user is view-only:
  • a role stored with no permissions ({}), or with none of those flags;
  • a role with readOnly: true;
  • a project user with no role at all.
A view-only user sees the dashboard and uses its filters. They get no Add, Actions or Save buttons, cannot create or duplicate dashboards, and the API refuses their dashboard writes. An edit never changes the shared dashboard. A user who can edit saves their changes to their own copy; the shared dashboard is edited by your builders in the Upsolve Hub.
This matches v1: a tenant registered without tenantEditingPermissions was view-only.

The permissions

“Unset” is what a flag means when the role does not mention it. A flag marked on if the role edits is on only when the role grants editing through another flag, and off on a view-only role. Spell out every flag you care about rather than relying on “Unset”. A role that says what it grants reads the same everywhere and survives a change of defaults.

Two common roles

A reader — sees and filters, changes nothing:
An editor of their own copies — builds on top of a shared dashboard without touching it:

Managing roles

In the Hub: Project settings → Roles. With the API, using the same API key as embed-token: Role names are unique within a project; creating a second role with a taken name answers 409.

Giving a user a role

  • At sign-in. embed-token takes user.userRoleId, applied on every call that sends it, and user.defaultUserRoleId, applied only to a user it creates. Send userRoleId when your product decides the role; send defaultUserRoleId when the role is managed in Upsolve after the first sign-in.
  • Later. PUT /v1/api/projects/{projectId}/users/{projectUserId} with userRoleId. null removes the role.

When a change takes effect

A user’s token carries their role’s permissions as they were when it was issued. After you change a role, or move a user to another one, the user’s next token has the new permissions; a token already issued keeps the old ones until it expires (1h by default). The API’s checks on dashboard writes read the role when the write arrives, so they apply at once.

Coming from the v1 SDK’s tenantEditingPermissions prop

In v1 an integration could give its users permissions in two places: in the register-tenant call, and in the tenantEditingPermissions prop of the SDK component. The SDK laid the prop over the token’s permissions in the browser. The prop was never stored, so a migration to v2 cannot see it: the roles it proposes come from what register-tenant was sent alone. In v2 an embed takes its permissions from the user’s role and nothing else, so the prop’s permissions have to go on the role. v1 and v2 read a flag nobody set differently. v1 turned it off. A v2 role that grants editing takes the “Unset” defaults above for the editing flags it leaves out. So a v1 prop of { "addFilter": true } copied onto a role as it is would also grant Add chart, Create chart, Remove chart and new dashboards. Write every editing flag out:
Add any other flag the prop set (aiInsight, drillDown, hideHeader, …) as the prop has it.

Already migrated

Update the role the migration created with the prop’s permissions, written out as above. Tenants registered without permissions all share one migrated role, so this is usually one call. Every user on the role gets the permissions on their next token.

Migrating now

Run the migration’s two role steps through the API with the prop, then continue in the Hub. The Hub’s migration page proposes roles without the prop.
  1. Propose the roles. POST /v1/api/migration/analyze-roles with your prop as sdkTenantEditingPermissions. Each proposed role is what v1 showed its users: their v1 token with the prop laid over it, every editing flag written out.
  2. Create them. POST /v1/api/migration/create-roles with each proposed role’s permissions and tenantIds, and a name of your choice.
  3. Continue on the Hub’s migration page from Create Project Users. The role steps are marked done, so the page does not run them again.
A tenant registered after Create Project Users that already owns dashboards is given the role of a tenant registered with the same permissions, so it picks up the prop’s permissions too. A tenant that first signs in after the migration gets its role from register-tenant, which never sees the prop: send register-tenant the prop’s permissions from then on, and it finds the same role.