Console
Service accounts
A service account is a machine identity for the control-plane API: your scripts and services exchange its credential for a short-lived token and act with real, scoped permissions.
Using one is three steps, and only the first happens in a browser:
- Create the account in the Console and store its credential.
- Exchange the credential for a short-lived access token.
- Call
api.upgreat.aiwith that token as a bearer.
Step 1 — Create the account
In the Console, go to Access → Service accounts → New service account. Name it after the system that will hold the secret (a CI pipeline, a backend service, an integration), then pick its scope:
- Organisation-scoped — acts across the organisation with a role, exactly like a member. Any role except
owner; start withmember(read-only) and attach policies if it needs specific write access. - Project-scoped — confined to one project. Read-only can inspect everything in the project; full accesscan also create and manage the project's resources (inference keys, chat instances, buckets). Neither can see the rest of the organisation, and neither can ever manage service accounts.
Creation shows three values:
client_id— the account's public identifier (e.g.sa-acme-x7k2mp). Not a secret; visible in the list later.client_secret— the credential itself. Shown once — copy it into your secret manager before leaving the page.token endpoint— the URL you exchange the credential at (step 2).
Treat the secret like a password
The secret is the account's only credential. Never commit it to source control or expose it in client-side code. If it leaks, rotate it in the Console — the old secret stops working immediately.Step 2 — Get a token
Exchange the credential with the OAuth2 client_credentials grant — a single POST, no browser, no redirect. The response contains an access_token valid for about 5 minutes (expires_in is in seconds). Fetch a fresh one per run, or cache it and refresh when it expires.
export UPGREAT_CLIENT_ID="sa-acme-x7k2mp"
export UPGREAT_CLIENT_SECRET="…" # from the create screen
TOKEN=$(curl -s -X POST \
https://identity.upgreat.io/realms/customers/protocol/openid-connect/token \
-d grant_type=client_credentials \
-d client_id="$UPGREAT_CLIENT_ID" \
-d client_secret="$UPGREAT_CLIENT_SECRET" | jq -r .access_token)Step 3 — Call the API
Send the token in the Authorization header. Every endpoint in the API reference works this way — what the account may do is decided server-side from its role and policies.
curl -s https://api.upgreat.ai/v1/orgs \
-H "Authorization: Bearer $TOKEN"{
"data": [
{
"id": "bdaca4bc-…",
"name": "Acme",
"slug": "acme",
"role": "member",
"created_at": "2026-06-14T12:53:19.165Z"
}
],
"has_more": false,
"next_cursor": null
}What scoping looks like in practice
Authorisation is enforced per request, and a refusal is always an explicit 403 naming the missing permission — useful when deciding which scope or role an account needs:
{
"error": {
"type": "forbidden",
"code": "forbidden",
"message": "not authorized to organization:read",
"request_id": "req-s"
}
}- An org-scoped account with the
memberrole can list projects, keys, members and usage — and gets403on anything that changes state. - A project-scoped account can call project endpoints (e.g.
/v1/projects/{projectId}/inference/keys) but gets403on everything org-level — including reading the organisation itself. Copy the project's id from the Console when configuring it.
Rotating and deleting
- Rotate regenerates the secret. The old secret stops working immediately; tokens already issued survive only until they expire (a few minutes).
- Deleteremoves the credential and the account's membership. Authorisation is revoked immediately — even a token that hasn't expired yet is refused.
Troubleshooting
- 401
invalid_clientfrom the token endpoint — wrong or rotated secret, or the account was deleted. Rotate in the Console to get a fresh secret. - 401
invalid tokenfrom the API — the access token expired. Fetch a new one; they only live a few minutes by design. - 403
forbidden— the account lacks that permission. The message names the missing action; widen the role, attach a policy, or use an account with the right scope.
Three different credentials
Humans sign in to the Console with UPGREAT Identity. Machines callapi.upgreat.ai with a service account. The LLM API (llm.upgreat.ai) uses a project inference key. They are not interchangeable.