Partner API
Provision your customers, sign them in, and run their workflows from your server.
Keys
Every call from your server sends a partner key: Authorization: Bearer gre_…. An API token (grt_…) is refused. Make keys in Platform › Partner keys; you see each once, and up to 20 work at once.
A key can be limited to up to 20 addresses or ranges (203.0.113.0/24). That limits who may use the key, not which websites show the embed. Rotate a key with a grace period. Never send one to a browser: the page gets a login code instead.
Each call is checked in this order: the license (EMBED_NOT_LICENSED), the key (UNAUTHORIZED, IP_NOT_ALLOWED), then the limits.
The address
Every path starts with /api/embed/v1, on your installation’s own address: the one your people open, where /embed.js is. It is never on api.gorunner.io. These pages write it as https://automations.example.com.
/v1 is the Partner API’s version, gorunner-embed/1. See Versions and upgrades.
Bodies are JSON; a write with another Content-Type is refused (415 INVALID_CONTENT_TYPE). Times are in UTC.
GORUNNER="https://automations.example.com"
GORUNNER_EMBED_KEY="YOUR_PARTNER_KEY" # gre_…, from Platform › Partner keys
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"
}'Answers
A success is {"data": …}; a list adds pagination. A failure is {"error": …}. Branch on code; message is for a person and may change.
details says more where there is more: field (the input that is wrong), unknown (IDs that don’t exist), reason (why a session ended) or switch (the switch that is off).
{
"error": {
"code": "VALIDATION_ERROR",
"message": "These switches don't exist: stepData.",
"details": { "field": "turnOff", "unknown": ["stepData"] }
}
}The IDs are yours
Accounts, workspaces, people and managed connections are named by your own IDs: 1 to 255 bytes of UTF-8, no control characters, compared byte for byte. An ID may contain /, so URL-encode it in a path: /accounts/acct%2F42.
An email is only ever contact information: it never identifies a person or links two. A PUT creates or updates by your ID, so sending it twice leaves the same state.
Idempotency
These POSTs take an Idempotency-Key (up to 255 characters), so a retry after a dropped connection never acts twice: suspend, resume and restore an account; allow a website; install, enable and disable a workflow; cancel its waiting runs; cancel a run and run it again; disconnect an account’s or every AI app.
| When you send the key again | You get |
|---|---|
| With the same request, within 24 hours | The first answer again, with Idempotency-Replayed: true |
| With a different request | 422 VALIDATION_ |
| While the first is still running | 409 CONFLICT: retry shortly |
| After the first failed | A new try: only a success is kept |
Keys belong to the partner key that sent them. A login code and a token take none: an unused code runs out in a minute, and a stored answer would keep a token for a day, so a retry makes a second one that you can revoke. Starting a connection sign-in and signing a person in for an AI app take none either.
Lists
Lists page with a cursor, each in the order its page states. Send limit (1 to 100, 50 by default) and, for the next page, the cursor the last page gave. nextCursor is null on the last page; a page that comes back full can carry a cursor with nothing after it, and the next page is then empty. Send a cursor back exactly as it came.
{ "data": [ … ], "pagination": { "limit": 50, "nextCursor": "…" } }Limits
| Counted for | A minute | Setting |
|---|---|---|
| One partner key | 3,000 requests | EMBED_ |
| One customer account: the one in the path, or a login code’s | 300 requests | EMBED_ |
| One person of one account | 20 login codes | EMBED_ |
| One line of frame sessions | 4 renewals | EMBED_ |
| AI app sign-in requests, per key | 600 requests | EMBED_ |
The windows are fixed minutes, shared by every server of the installation. A request one limit refuses isn’t counted by the others, so one customer over its limit uses up nothing of your key’s. One address may also send at most four times API_RATE_LIMIT a minute to each server.
Over a limit, the answer is 429 RATE_LIMITED with Retry-After. X-RateLimit-Limit and X-RateLimit-Remaining describe the tightest window, and X-RateLimit-Scope names it: key, account, person or session.
Throttle your own login-code route for each person too. Every frame that opens, and every renewal through your page, is one login code; a frame renews by itself for up to 12 hours, so most renewals never reach your server.
The record
Every call with your key leaves a row in the audit log of the account it was about, except reading an AI app sign-in request: the route, the status, the request ID, the key, and whether it was a replay. Never a body. The changes themselves, such as an account created or a role changed, leave rows of their own.
Errors
| Code | Status | When |
|---|---|---|
VALIDATION_ERROR | 400, 422 | An input is wrong; details names it. 422 for an idempotency key used with another request. |
INVALID_ | 415 | A Content-Type other than application/json. |
PAYLOAD_TOO_LARGE | 413 | A body over 5 MiB. |
UNAUTHORIZED | 401 | No key, or one revoked, past its rotation or mistyped. |
EMBED_ | 403 | The license doesn’t include Embed, or the installation has no valid license. |
IP_NOT_ALLOWED | 403 | The key’s addresses don’t include yours. |
FEATURE_OFF | 403 | A switch the call needs is off for the account; details.switch names it. |
ORG_LIMIT, WORKSPACE_LIMIT | 403 | A new account or workspace would pass the license’s limit. |
PIECE_NOT_ALLOWED | 403, 422 | An app the account may not use. |
NOT_FOUND | 404 | No account, workspace or person with that ID. |
CONFLICT | 409 | The change clashes with the current state; the message says how. |
ACCOUNT_DELETED | 409 | The account is deleted. Restore it first, within 30 days. |
ACCOUNT_, RESTORE_EXPIRED | 409 | Restoring an account that isn’t deleted, or whose 30 days are over. |
ACCOUNT_SUSPENDED | 409 | Running a run again in a suspended account. |
WORKFLOW_ | 409 | Running a run again whose workflow is off. |
WEBSITE_EXISTS | 409 | The website is already on the list. |
TOKEN_LIMIT | 409 | The workspace already has 25 tokens that work. |
DEFAULT_WORKSPACE | 409 | An account’s default workspace can’t be deleted. |
INVALID_ORIGIN, TOO_MANY_WEBSITES | 422 | A website can’t be allowed as written, or the list is full: 200 on yours, 20 for one customer. |
CONNECTION_ | 422 | A connection given for a template’s slot is for another service. |
RATE_LIMITED | 429 | A limit is used up. See Retry-After. |
INTERNAL_ERROR | 500 | Something failed on the installation. Try again. |
PIECES_ | 503 | The apps allowed couldn’t be read. Nothing changed. |
Each endpoint lists the codes it answers. For every code, see Error codes.
The frame’s own routes
Five routes take no partner key, and the SDK and the frame call them for you. Check the installation can be embedded is public. Start a session swaps a login code for a session (gri_…), which can renew itself, sign out or turn more switches off.
Every endpoint 59
By name, path or method, such as runs or POST.
Sign-in 6
- Start a session
POST /api/embed/v1/sessions - Make a login code
POST /api/embed/v1/login-codes - Check the installation can be embedded
GET /api/embed/v1/bootstrap - End a session
DELETE /api/embed/v1/sessions/current - Turn switches off for a session
POST /api/embed/v1/sessions/current/turn-off - Renew a session
POST /api/embed/v1/sessions/current/renew
Accounts 7
- List accounts
GET /api/embed/v1/accounts - Get an account
GET /api/embed/v1/accounts/{accountId} - Create or update an account
PUT /api/embed/v1/accounts/{accountId} - Suspend an account
POST /api/embed/v1/accounts/{accountId}/suspend - Resume an account
POST /api/embed/v1/accounts/{accountId}/resume - Restore an account
POST /api/embed/v1/accounts/{accountId}/restore - Delete an account
DELETE /api/embed/v1/accounts/{accountId}
Tokens 3
Websites 7
- List an account’s websites
GET /api/embed/v1/accounts/{accountId}/websites - List allowed websites
GET /api/embed/v1/websites - Replace an account’s websites
PUT /api/embed/v1/accounts/{accountId}/websites - Allow a website for one account
POST /api/embed/v1/accounts/{accountId}/websites - Allow a website
POST /api/embed/v1/websites - Stop allowing a website for one account
DELETE /api/embed/v1/accounts/{accountId}/websites/{origin} - Stop allowing a website
DELETE /api/embed/v1/websites/{origin}
Workspaces 4
- List workspaces
GET /api/embed/v1/accounts/{accountId}/workspaces - Get a workspace
GET /api/embed/v1/accounts/{accountId}/workspaces/{workspaceId} - Create or rename a workspace
PUT /api/embed/v1/accounts/{accountId}/workspaces/{workspaceId} - Delete a workspace
DELETE /api/embed/v1/accounts/{accountId}/workspaces/{workspaceId}
People 6
- List an account’s members
GET /api/embed/v1/accounts/{accountId}/members - Get a person
GET /api/embed/v1/users/{userId} - Give a person a role
PUT /api/embed/v1/accounts/{accountId}/members/{userId} - Create or update a person
PUT /api/embed/v1/users/{userId} - Remove a member
DELETE /api/embed/v1/accounts/{accountId}/members/{userId} - Delete a person
DELETE /api/embed/v1/users/{userId}
Connections 6
- List connections
GET /api/embed/v1/accounts/{accountId}/connections - Get a managed connection
GET /api/embed/v1/accounts/{accountId}/connections/{connectionKey} - Check how a connection sign-in ended
GET /api/embed/v1/accounts/{accountId}/connections/oauth2/attempts/{attemptId} - Create or replace a managed connection
PUT /api/embed/v1/accounts/{accountId}/connections/{connectionKey} - Start a connection sign-in from your own button
POST /api/embed/v1/accounts/{accountId}/connections/oauth2/start - Delete a managed connection
DELETE /api/embed/v1/accounts/{accountId}/connections/{connectionKey}
Workflows 7
- List templates customers can install
GET /api/embed/v1/templates - List workflows
GET /api/embed/v1/accounts/{accountId}/workflows - Get a workflow
GET /api/embed/v1/accounts/{accountId}/workflows/{workflowId} - Install a template
POST /api/embed/v1/accounts/{accountId}/workflows - Enable a workflow
POST /api/embed/v1/accounts/{accountId}/workflows/{workflowId}/enable - Disable a workflow
POST /api/embed/v1/accounts/{accountId}/workflows/{workflowId}/disable - Cancel a workflow’s waiting runs
POST /api/embed/v1/accounts/{accountId}/workflows/{workflowId}/cancel-waiting
Runs 4
Usage 2
AI apps 7
- List an account’s AI apps
GET /api/embed/v1/accounts/{accountId}/ai-apps - Read a sign-in request
GET /api/embed/v1/oauth-requests/{requestId} - Sign a person in for an AI app
POST /api/embed/v1/oauth-requests/{requestId}/complete - Turn a sign-in request down
POST /api/embed/v1/oauth-requests/{requestId}/deny - Disconnect an AI app
DELETE /api/embed/v1/accounts/{accountId}/ai-apps/{grantId} - Disconnect an account’s AI apps
POST /api/embed/v1/accounts/{accountId}/ai-apps/revoke - Disconnect every AI app
POST /api/embed/v1/ai-apps/revoke