GoRunner docs
Search or askSearch⌘K

Start a session

POST/api/embed/v1/sessions

Swaps a login code for a session. The frame calls it; you rarely do.

Needs no key: the login code in the body is the credential.

Embed · Self-hosted with an Embed license

Parameters

Body

codeRequired · string

The login code, grl_…. The code is the credential.

parentOriginRequired · string

The page around the frame. It must be an allowed website, or one your server allowed for this code’s account. Missing: refused, and the code isn’t used up.

turnOffOptional · array of strings

Switches to turn off for this session. Unknown IDs are listed in ignored.

replacesOptional · string

The gri_… session this one renews. It ends only if it is the same person’s.

The session

token (gri_…) is sent as Authorization: Bearer. Keep it in memory, never in a cookie. It lasts 30 minutes.

Renew it at renewAfter (renewInSeconds counts from the server’s clock) with Renew a session, or with a new code and replaces. switches holds every switch’s value for it; me is who the frame is.

Responses

  • 201Created

    The session.

  • parentOrigin or another field is missing or not valid. The code isn’t used up.

  • The code is unknown, used or past its 60 seconds.

  • The code’s person no longer has that access (details.reason).

  • Embed isn’t licensed here, or sign-in is off (details.reason: not_licensed or sign_in_off). The code isn’t used up.

  • The page isn’t an allowed website for this account.

  • The account is deleted.

  • Something failed on the installation’s side. Try again.

Any call can also answer: 413 PAYLOAD_TOO_LARGE · 415 INVALID_CONTENT_TYPE · 429 RATE_LIMITED · 503 BUSY. See Errors.

Request

GORUNNER="https://automations.example.com"

curl -X POST "$GORUNNER/api/embed/v1/sessions" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "grl_…",
    "parentOrigin": "https://app.bakery.example"
  }'

Response · 201 Created, shortened

json
{
  "data": {
    "token": "gri_…",
    "expiresAt": "2026-10-25T09:30:00Z",
    "renewAfter": "2026-10-25T09:25:00Z",
    "renewableUntil": "2026-10-25T21:00:00Z",
    "renewInSeconds": 1500,
    "account": {
      "id": "acct-bakery",
      "status": "active"
    },
    "workspace": {
      "id": null,
      "default": true
    },
    "user": {
      "id": "ada-123"
    },
    "role": "editor",
    "switches": {
      "overview": false,
      "workflows": true,
      "runs": true,
      "…": true
    },
    "ignored": []
  }
}
Every field

Body

codeRequired · string
parentOriginRequired · string

The host page’s origin. Missing or empty is 400 VALIDATION_ERROR (details.field parentOrigin) and the login code is NOT used, so a retry with it works.

turnOffOptional · array of strings
replacesOptional · string

The gri_… token this one renews.

Response · 201 Created

dataobject
tokenstring

gri_… — send as Authorization: Bearer; keep in memory only.

expiresAttime
renewAftertime
renewableUntiltime

When renewing in the frame stops for this line of sessions (12 hours after the login code, the EMBED_SESSION_MAX_HOURS setting). Absent for a platform preview.

renewInSecondsinteger

renewAfter as whole seconds from this answer, by the server’s clock: schedule the renewal from it, so a device whose clock is off still renews on time.

accountobject
idstring
statusstring
workspaceobject
idstring or null

The partner’s workspace id; null for the default workspace.

defaultboolean
userobject
idstring
rolestring

One of viewer, operator, editor.

switchesobject

Every switch id with its effective value; a missing id is off.

{key}boolean

Each key’s value.

ignoredarray of strings
meobject

What GET /api/auth/me answers this session.