VRPlatformVRPlatform
Embed the Hosted UI

Issue Sessions

Issue one-time embedded bootstrap URLs without exposing partner secrets

Call from your trusted backend:

POST https://hostaway.api.vrplatform.app/partner/embed-sessions?autoProvision=true
x-api-key: <partner-api-key>
Content-Type: application/json
{
  "sub": "partner-user-123",
  "teamId": "4f8f94de-2cc0-4ec7-a7f8-f0c7f560e59a",
  "bundles": ["embed:reports:v1", "embed:exports:v1"],
  "viewPath": "/reports/profit-and-loss?view=non-zero-rows"
}

sub is your immutable external user ID. teamId is the managed team the embedded UI opens. viewPath must start with /reports or /statements and is resolved against the VRPlatform portal origin configured for the Worker. bundles selects the read-only view capabilities required for this session:

  • embed:reports:v1
  • embed:statements:v1
  • embed:exports:v1, only together with a matching read bundle

The requested embedded scopes must be a subset of the partner API key's grant. autoProvision=true creates the partner-scoped embedded user and team membership on first use. Omit it when unknown users should be rejected. It only ever creates memberships that do not exist: a membership that was revoked (set inactive) is never reactivated — the request fails with 403 until access is restored explicitly.

The response contains a ready-to-mount embedUrl, its bootstrap expiry, teamId, and the resolved VRPlatform userId:

{
  "embedUrl": "https://portal.vrplatform.app/reports/trial-balance#code=<one-time-code>",
  "expiresAt": "2026-07-19T12:01:00.000+00:00",
  "teamId": "4f8f94de-2cc0-4ec7-a7f8-f0c7f560e59a",
  "userId": "018f9c2b-7f4b-7d72-bf2e-9ab983f07018"
}

Mount this URL without extracting or moving the code. The code is valid for 60 seconds and succeeds once. The iframe exchanges it directly for a 15-minute, team-bound bearer token, removes the fragment, and keeps the token in memory. Your backend and parent page never receive that bearer token.

Embedded identities use sub instead of an email address. Their GET /me profile therefore returns user.email: null. Keep using the same stable sub; do not invent an email address for session issuance.

Backend Flow

  1. Authenticate the user in your product.
  2. Authorize their access to the selected team.
  3. Request the smallest required embedded bundles and exact view path.
  4. Return the response fields to your frontend without logging embedUrl.
  5. Mount the URL promptly; request a new URL whenever the iframe is remounted.

Never return the partner API key. Do not accept a browser-supplied team ID without checking it against the signed-in user's access in your own product.

Failures

  • 400: invalid bundle combination, missing canonical teamId, or a path outside reports and statements.
  • 401: missing, invalid, wrong-audience, inactive, or expired partner key.
  • 403: the key cannot grant a requested bundle, the embedded user is unknown or inactive, or the partner lacks access to the selected team.
  • 404: the selected team does not exist in the credential's scope.

Correct the credential, user provisioning, bundle, or access assignment; do not retry with a different team automatically.

See the generated Create embed session contract.

On this page