Authentication
Choose between user API keys, automation accounts, delegated tokens, and human sessions.
Every authenticated API request resolves to a principal. Authorization then evaluates the principal type, organization boundary, scopes, resource visibility, ownership, and role.
User API keys
Any workspace member can open Settings → API Access → API Keys and create a key
that acts as them within that workspace. User keys start with gsmc_uk_ and use
the Bearer header. They need no X-Org-Id; a conflicting workspace is rejected.
Your key follows your current permissions. Promotion and demotion take effect on subsequent requests. Suspension, removal, expiry or revocation stops access. Removing a membership destroys its keys; rejoining does not restore them. Optional read-only keys can read accessible resources but cannot change them or start agents. Read-only restrictions cannot be removed and expiry cannot be extended.
Members see their own key metadata. Workspace owners and admins can see, restrict
and revoke every member's keys. A secret is displayed only when its owner creates
it; admins cannot recover it, transfer its ownership or create a replacement for
another person. Sign in to create credentials, including replacements. Read/write API keys can
list, restrict and revoke keys using the same owner/admin rules.
Account security, personal connection setup and explicit human attestations also
require a signed-in session. So do threads between agents in the Inbox: a
user key gets 403 there. So do a workspace's gravest changes, even with an
owner's or admin's key: deleting the workspace, changing its settings, changing
a member's role, removing a member (yourself included) and inviting an admin or
owner all answer 403 to a key. A key can still read the workspace, rename it,
and invite members and viewers.
A key's owner can give it a monthly budget from API Keys, signed in. It counts every run the key starts, every run those runs start, and the Inbox replies they set off, per UTC calendar month. At the limit the key starts nothing more and its running work pauses, unless the owner chose alerts only. The workspace's own budgets and limits still apply. A key can't change any key's budget, and admins can't set one on another member's key. Revoking the key, its expiry, or removing its owner from the workspace deletes the budget. The key list returns what each key spent this month and its budget.
A key manages its owner's personal memory of the agents they can view, and an agent's own memory only when its owner owns the agent and isn't a viewer, or is currently a workspace admin. Sharing an agent never shares the agent's own memory. User-key run results, workflow run history and produced artifacts remain private to the calling user. Personal Google execution requires separate supported consent; possession of a user key does not grant it.
Key expiry
When you create a key, choose when it expires: in 30, 90 or 180 days, in a year,
at the end of a day you pick, or never. Through the API, send expires_in_days
or expires_at, not both; expires_in_days: null means never. User keys last 90
days when you send neither, and automation account keys never expire unless you
choose. No key can be created to last more than a year, and no key's expiry can be
extended, so create a replacement and move to it before the old key expires.
Workspace owners and admins can limit how long keys last under Settings → API Access → Key lifetime. The limit covers user keys and automation account keys. New keys must then expire within it, and never isn't offered. Setting a shorter limit also shortens every key that would outlive it, to expire that many days from then. Removing the limit later doesn't lengthen them.
People are emailed a week before a key expires, again a day before, and when a limit shortened it. User keys notify their owner. Automation account keys notify the admin who created the key, or every admin when that person is no longer one. These emails go out even with notification emails turned off in Profile.
Turn API access off
Owners and admins of a shared workspace can turn off member API keys, automation
accounts, or both, under Settings → API Access. While a kind is off, its keys
are refused with 403, work they started stops at its next step, and no new keys
or automation accounts can be created. Members with a live API key, or for
automation accounts the other admins, get an email when it's turned off. Nothing
is deleted: turning it back on restores every key as it was, unless the key
expired or was revoked meanwhile. API clients aren't affected, and each change
is recorded in the audit log as org.update.
Automation accounts
Use an automation account for server-to-server automation owned by an organization. The API calls it a service principal. Its API key uses the gsmc_sk_ prefix and is sent as a Bearer token. Organization owners and admins create them from Settings → API Access, under Automation accounts.
Automation accounts have no human membership. Their access comes from their scopes and from the resources shared with them. They cannot administer other automation accounts.
An automation account key can call only the operations the API reference lists for automation accounts, and only while it holds every scope the operation names. Every other endpoint answers 403, however the account is scoped. A scope on a resource no listed operation uses, such as audit, usage, env_vars, knowledge, memory, schedules or webhooks, grants it nothing, so the app no longer offers those when you choose an automation account's or API client's permissions.
Private resources are invisible to automation accounts
Scopes are not sufficient on their own. An automation account can never read or invoke a resource whose visibility is private, no matter which scopes it holds — the visibility check runs first and denies outright.
Agents and workflows are created private by default, so a new automation account typically sees nothing until you act. Chats are never reachable: a chat belongs to the member who started it, so the chat operations take that member's user API key or a delegated token acting for them. An automation account reaches:
- an agent or workflow shared with the organization, which makes it visible to every member and to the organization's automation accounts; or
- an agent set to restricted visibility with that automation account added to it. An organization owner or admin adds it from the agent's sharing settings. For a restricted agent, the scope and the grant are both required.
Plan for this before granting scopes. A correctly scoped key against private resources produces an empty list, not an error.
Limit an automation account to specific agents and workflows
An organization owner or admin can narrow an automation account further with a resource allowlist: open the account's page under Settings → API Access → Automation accounts and choose Edit Allowlist. Without an allowlist, the account reaches anything shared with the workspace that its scopes cover. With one, it reaches only the listed agents and workflows, within its scopes. Private agents and workflows can't be listed.
While an allowlist is set, the account can't open runs or upload files. The allowlist doesn't limit creating new resources; its scopes alone decide that. An empty list means no allowlist. A restricted agent on the list still needs the automation account added to it.
Delegated clients and tokens
Use delegated access when an external application acts on behalf of a specific user. Delegated tokens use the gsmc_dt_ prefix, carry the user's identity for attribution and ownership, and remain restricted by granted scopes.
A delegated token can call only the operations the API reference lists for delegated tokens, and only while it holds every scope the operation names. Every other endpoint answers 403, however the token is scoped, even where its user could act in the app.
Each delegated token is locked to the organization that issued it. It does not
switch organizations with X-Org-Id; issue and consent to a token in each
organization the integration needs to reach.
A delegate is not a stand-in for the user's full account. It normally reaches resources through the user's ownership and its own scope grant rather than inheriting administrative powers. Organization-library MCP management is a narrow exception: it requires the exact mcp_servers:publish scope and the represented user must currently be an organization admin or owner.
Delegated access is appropriate when attribution and the user's own resources matter. It is not a substitute for an organization-owned background integration, and it cannot script admin operations outside the documented MCP library exception.
Provision user-owned configurations
Use a delegated token when an external application needs to create agents, workflows, or MCP connectors for a user. Creation requires the matching agents:create, workflows:create, or mcp_servers:create scope and binds the new resource to the delegated user; an automation account cannot create these resources because it has no user identity to own them.
With the corresponding :edit scope, a delegate can update only resources owned by its user. It does not inherit an administrator's ability to edit someone else's configuration. Workflow writes also require invoke access to every agent and workflow its steps reference, fallback agents included, so a delegate cannot build a workflow around another user's private agent.
A delegate's chat with the Concierge stays within the same consent: the
Concierge reads and changes only what the token's scopes cover, a wildcard
such as agents:* covering every scope under it, and the audit log records
its changes as the client acting for the user (actor_principal_type
user_delegate, with the client's oauth_client_id). See chat with an
agent.
For organization-library MCP connectors, grant mcp_servers:publish explicitly. Publishing, unpublishing, creating an organization-shared connector, or testing one with its saved credential also checks the represented user's current admin or owner role. The mcp_servers:* wildcard does not grant this permission.
Install with human consent
Installing a delegated integration starts with a signed-in user:
- An organization admin registers the client and stores the client secret, which is shown once. In the app, open Settings → API Clients and, under API clients this workspace registered, choose New API Client; through the API, call
POST /api/v1/oauth-clients. - A member reviews the requested scopes and grants the client access. In the app, open Settings → API Clients and choose Authorize on the client under Your authorizations; through the API, list installable clients with
GET /api/v1/oauth-clients/availableand grant access withPOST /api/v1/oauth-clients/{client_id}/grant. - The member can withdraw that consent with Withdraw Access in the same place, or with
DELETE /api/v1/oauth-clients/{client_id}/grant. Withdrawing also revokes their active tokens for the client.
These are onboarding and consent actions, so they use the member's short-lived user session. Never capture or store that session as an integration credential. After consent, the integration uses its client credentials only for token exchange, then sends the resulting delegated token to API operations.
Exchange client credentials for a token
After a user grants your client access, exchange the client credentials server-to-server:
curl https://api.guestmachines.com/api/v1/auth/token/exchange \
-H 'Content-Type: application/json' \
-d '{
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"user_id": "USER_UUID",
"scopes": ["agents:read", "agents:invoke"],
"expires_in_seconds": 3600
}'Do not send an existing Bearer token to this endpoint. The requested scopes must fit both the client's allowance and the user's active grant. The response returns a gsmc_dt_ token once in raw_token; store it securely and exchange again when it expires.
Drive human-in-the-loop runs
Use a delegated token for work that can call ask_user or pause for tool
approval. The token gives the run an attributed actor and can later retrieve
the pending interaction with runs:read and answer it with runs:edit.
Who may decide depends on the interaction. Only the user the run asks can read or answer a question: the user who started it, or the member its workflow step names. A tool approval can also be read and answered by a current organization owner or admin through their own session or user API key, unless the run is private: a run in a member's chat, one started by a private automation, and any run that uses a member's own accounts and credentials (their runs of their own private agent) stay with that member. A delegated token never carries admin power, so it can decide only for its own user's runs, and an automation account has no user identity to submit a decision. See human interactions for the complete flow.
Own uploaded run inputs
Artifact upload preserves the caller's identity boundary. A direct user-session or delegated-token upload is private and owned by that user. An automation-account upload is organization-shared because an automation account has no user identity; do not use one when the file must remain private to a person. The API never converts either kind of upload into a run-produced output.
The minimum upload scope for a machine credential is runs:create. To attach
the returned artifact through artifact_inputs, also grant runs:read and the
scope that invokes the target, such as agents:invoke or
workflows:invoke. Listing the workspace's ready artifacts needs runs:list.
Downloading or previewing one needs runs:read; deleting one needs runs:edit
and still follows its ownership and visibility rules. Direct viewers cannot
upload.
Human sessions
Browser session credentials are short-lived. The public Authentication API accepts them only for the documented human onboarding and consent operations. Do not copy them into an integration.
Key handling
- Store keys in a secret manager.
- Use separate principals for separate systems.
- Grant the narrowest useful scopes.
- Rotate keys without reusing names or values.
- Revoke a key immediately if it may have leaked.
- Never expose automation account keys to client-side JavaScript.