Make a login code
This page needs your own installation with an Embed license.
POST/
Makes a one-time login code for a person, creating the person, account and workspace if they don’t exist.
Needs a partner key: Authorization: Bearer gre_…, from Platform › Partner keys. Call it from your server only.
Parameters
Body
userRequired · objectThe person: your
id(1 to 255 bytes), theirname(up to 200 characters) and, if you like,email. The email is for contact only, never who they are.accountRequired · objectThe account: your
idand itsname.workspaceOptional · objectA workspace: your
id, and itsnamethe first time. Left out: the account’s default workspace.roleRequired · stringviewer,operatororeditor.turnOffOptional · array of stringsSwitch IDs to turn off for this login only.
The code
Hand code to your page, which gives it to the frame. It works once, for 60 seconds. Never log it. See Login codes and sessions.
A suspended account still gets a code: its people can look, read only. A changed role ends the person’s older sessions in that workspace, which come back at the new role.
It takes no Idempotency-Key: an unused code simply runs out. One person of one account gets 20 codes a minute (EMBED_PERSON_RATE_LIMIT), so throttle your own login route per person too.
Responses
- 201Created
The code, and what was found or made.
A field isn’t valid.
details.fieldnames it.- 403
ORG_LIMITThe account is new, and the license’s organization limit is reached. Nothing is made.
A workspace would be made (a new account’s default one, or a new
workspace.id), and the license’s workspace limit is reached. Nothing is made.The account is deleted. Restore it first, within 30 days.
- 409
BUSYSomething else held what this call needs, and it gave up waiting. Nothing changed. Try again.
- 429
RATE_LIMITEDYour key’s, the account’s or this person’s login codes this minute are used up.
X-RateLimit-Scopesays which;Retry-Aftersays when. Something failed on the installation’s side. Try again.
Any call can also answer: 401 UNAUTHORIZED · 403 EMBED_NOT_LICENSED · 403 IP_NOT_ALLOWED · 413 PAYLOAD_TOO_LARGE · 415 INVALID_CONTENT_TYPE · 503 BUSY. See Errors.
Request
GORUNNER="https://automations.example.com"
GORUNNER_EMBED_KEY="YOUR_PARTNER_KEY" # gre_…
curl -X POST "$GORUNNER/api/embed/v1/login-codes" \
-H "Authorization: Bearer $GORUNNER_EMBED_KEY" \
-H "Content-Type: application/json" \
-d '{
"user": {
"id": "ada-123",
"name": "Ada Lovelace"
},
"account": {
"id": "acct-bakery",
"name": "Bakery Ltd"
},
"role": "editor"
}'const GORUNNER = "https://automations.example.com";
const KEY = process.env.GORUNNER_EMBED_KEY; // gre_…
const res = await fetch(
`${GORUNNER}/api/embed/v1/login-codes`,
{
method: "POST",
headers: {
Authorization: `Bearer ${KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
user: { id: "ada-123", name: "Ada Lovelace" },
account: {
id: "acct-bakery",
name: "Bakery Ltd",
},
role: "editor",
}),
},
);
const { data } = await res.json();import os, requests
GORUNNER = "https://automations.example.com"
KEY = os.environ["GORUNNER_EMBED_KEY"] # gre_…
res = requests.post(
f"{GORUNNER}/api/embed/v1/login-codes",
headers={"Authorization": f"Bearer {KEY}"},
json={
"user": {
"id": "ada-123",
"name": "Ada Lovelace",
},
"account": {
"id": "acct-bakery",
"name": "Bakery Ltd",
},
"role": "editor",
},
)
data = res.json()["data"]Response · 201 Created
{
"data": {
"code": "grl_…",
"expiresAt": "2026-10-25T09:01:00Z",
"expiresIn": 60,
"account": {
"id": "acct-bakery",
"status": "active",
"created": false
},
"workspace": {
"id": null,
"default": true,
"created": false
},
"user": {
"id": "ada-123",
"created": true
},
"role": "editor"
}
}Every field
Body
userRequired · objectidRequired · stringnameRequired · stringemailOptional · string or nullaccountRequired · objectidRequired · stringnameRequired · stringworkspaceOptional · objectOmitted = the account’s default workspace.
nameis needed the first time.idRequired · stringnameOptional · stringroleRequired · stringOne of
viewer,operator,editor.turnOffOptional · array of stringsSwitches off for this login only. An id that does not exist is 400
VALIDATION_ERROR(details.unknown).
Response · 201 Created
dataobjectcodestringgrl_…— single use, 60 seconds.expiresAttimeexpiresInintegeraccountobjectidstringstatusstringOne of
active,suspended.createdbooleanworkspaceobjectidstring or nulldefaultbooleancreatedbooleanuserobjectidstringcreatedbooleanrolestringOne of
viewer,operator,editor.