latestOpenAPI 3.1.0raw.githubusercontent.com2026-08-2183295744.1 KB

d3689bca6458

portal

Create portal session

Create a portal session for an end user and get the URL to redirect them to.

The URL carries a single-use exchange code valid for 15 minutes, which the portal redeems exactly once for a 24-hour access token via portal.exchangeCode.

Required Permissions

Authorization runs in two stages, and both must pass.

First, your root key must have one of the following permissions:

  • portal.*.create_portal_session (to mint sessions for any portal in the workspace)
  • portal.<portal_id>.create_portal_session (to mint sessions for a specific portal)

Second, a session can never carry a capability your root key does not itself hold. Each requested scope additionally requires the equivalent permission on every keyspace the portal resolves to:

  • keys:read requires api.<api_id>.read_key and api.<api_id>.read_api
  • keys:reroll and keys:create require api.<api_id>.create_key, plus api.<api_id>.encrypt_key when the keyspace stores encrypted keys
  • analytics:read requires api.<api_id>.read_analytics

The * form of each is also accepted. Requesting a scope you do not hold returns 403 for the whole request rather than minting a reduced session, so a missing grant is visible instead of surfacing later as a broken portal.

Missing the portal permission itself returns 404, not 403: a caller who cannot mint for a portal is not told whether it exists.

Your root key must also be associated with a workspace that has an enabled portal.

post/v2/portal.createSession

Request body

portalstring required

Identifies a resource by either its unique ID or its slug. Accepts a prefixed ID (such as 'proj_' or 'app_') or a slug.

externalIdstring required

The end user's identifier in the customer's system. Accepts arbitrary string values (user IDs, emails, UUIDs, etc.).

scopesstring[] required

The capabilities granted to the end user in the Portal, from a fixed vocabulary. All capabilities are scoped to this end user: key capabilities (keys:*) apply only to keys the end user owns within the keyspace configured on the portal, and analytics:read returns only the end user's own verification events. An end user can never see another identity's keys or analytics.

Tab visibility is derived from the scopes:

  • Keys tab: any keys:* scope
  • Analytics tab: analytics:read
  • Docs tab: visible when any scope is present

keys:create is accepted but has no portal route behind it yet. It is still authorized like the others, so a session minted with it required create_key on the keyspace at mint time, and a future portal create-key route inherits an enforced ceiling rather than trusting sessions minted while the capability was inert.

Each scope requires the equivalent permission on your own root key. See Required Permissions on this operation.

previewboolean

When true, creates a preview session for testing the portal experience.

returnUrlstring uri

Absolute URL the end user is sent back to when they leave the portal, or when their session expires mid-visit. Set per session rather than per portal, so one portal can serve several entry points and return each user to the page they came from.

When omitted, the portal shows no return link.

Example request

{
  "portal": "proj_1234abcd",
  "externalId": "user_123",
  "scopes": [
    "keys:read",
    "keys:reroll",
    "analytics:read"
  ],
  "returnUrl": "https://app.example.com/settings/api-keys"
}

Response

Session created successfully. Redirect the end user to the returned URL.

Example response

{
  "meta": {
    "requestId": "req_123"
  },
  "data": {
    "id": "ps_abc123def456",
    "url": "https://portal.unkey.com/?code=pst_abc123def456"
  }
}