API Authentication - Synthreo Builder
Authentication guide for the Builder API - create an API key, exchange it for a Bearer access token with the OAuth 2.0 client credentials grant, and call the API in multi-tenant environments.
The Synthreo Builder API authenticates with OAuth 2.0. You create an API key in the Synthreo web app, then exchange that key for a short-lived JWT access token using the standard client_credentials grant. The access token is then sent in the Authorization header of every Builder API request.
Overview
Section titled “Overview”Authenticating is a two-step process:
- Once: create an API key in the Synthreo web app and note its key id and secret.
- Per token: exchange the key at the token endpoint for an access token, then send that token as a Bearer credential.
| Value | Where it comes from |
|---|---|
client_id | apikey-{your key id} - for example, key id 42 gives apikey-42 |
client_secret | The key secret (sak_...), shown once when you create the key |
| Token endpoint | https://auth.synthreo.ai/connect/token |
| Access token lifetime | 15 minutes (no refresh token - request a new one when it expires) |
Step 1 - Create an API Key
Section titled “Step 1 - Create an API Key”API keys are managed per user, in the Synthreo web app:
- Sign in to Threo (
https://threo.synthreo.ai). - Open the account menu (your initials, top right) and choose Profile.
- Select the API Keys tab.
- Click Add key, enter a Label (for example,
CI pipeline), optionally set an expiry date, and click Create key. - Copy the secret now. It starts with
sak_and is shown only once - it can never be retrieved again. If you lose it, revoke the key and create a new one.
A key you create is scoped to your user and customer (tenant). The token it mints carries your own account’s roles and permissions.
Step 2 - Find Your client_id
Section titled “Step 2 - Find Your client_id”Your OAuth client_id is your key id with an apikey- prefix:
client_id = apikey-{key id}The key id is the numeric identifier of the key you created (for example, key id 42 gives client_id apikey-42). The client_id numeric part must match your key exactly - an incorrect id is rejected as invalid_client.
Your client_id is shown directly in the Synthreo web app: in the reveal dialog when you create a key (next to the secret), and in the Client ID column of the API Keys list.
Step 3 - Exchange the Key for an Access Token
Section titled “Step 3 - Exchange the Key for an Access Token”Send a POST request to the token endpoint using the OAuth 2.0 client credentials grant. The request is form-encoded (application/x-www-form-urlencoded), not JSON.
Endpoint
Section titled “Endpoint”POST https://auth.synthreo.ai/connect/token
Request Parameters
Section titled “Request Parameters”| Parameter | Required | Description |
|---|---|---|
grant_type | Yes | Always client_credentials |
client_id | Yes | apikey-{your key id} (for example, apikey-42) |
client_secret | Yes | Your key secret (the sak_... value shown once at creation) |
target_app | Yes | The application the token is for: builder, threo, or tenant. Use builder for the Builder API. |
account_id | No | Scopes the token to a specific account when your identity can access more than one. Omit to use your default account. |
Example Request (cURL)
Section titled “Example Request (cURL)”curl -X POST 'https://auth.synthreo.ai/connect/token' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_id=apikey-42' \ --data-urlencode 'client_secret=sak_your_key_secret_here' \ --data-urlencode 'target_app=builder'Successful Response (200 OK)
Section titled “Successful Response (200 OK)”{ "access_token": "eyJhbGciOiJFUzI1NiIsImtpZCI6...", "token_type": "Bearer", "expires_in": 900}Response Fields
Section titled “Response Fields”| Field | Type | Description |
|---|---|---|
access_token | string | The JWT access token to send on Builder API requests |
token_type | string | Always Bearer |
expires_in | integer | Token lifetime in seconds (900 = 15 minutes) |
There is no refresh_token - the client credentials grant is not refreshable. When a token expires, request a new one by repeating this exchange.
Error Responses
Section titled “Error Responses”| Status | error | Common cause |
|---|---|---|
401 Unauthorized | invalid_client | Wrong, revoked, or expired key; or a client_id whose numeric id doesn’t match the key |
400 Bad Request | invalid_request | Missing target_app, an unknown target_app, or a scope parameter was sent |
403 Forbidden | access_denied | The key’s user has no access to the requested target_app / account_id |
Step 4 - Call the Builder API
Section titled “Step 4 - Call the Builder API”Include the access token in the Authorization header of every request, prefixed with Bearer:
Authorization: Bearer YOUR_ACCESS_TOKENcurl -X POST 'https://builder-api.synthreo.ai/CognitiveDiagram/12345/Execute' \ -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"Action":"Execute","UserSays":"[{\"userSays\":\"Hello!\"}]"}'Token Expiration and Management
Section titled “Token Expiration and Management”Access tokens expire after 15 minutes. There is no refresh token; renew by exchanging your API key again. A typical client caches the token and re-requests it shortly before expiry (or on a 401).
from datetime import datetime, timedelta, timezoneimport requests
class SynthreoApiClient: TOKEN_URL = "https://auth.synthreo.ai/connect/token"
def __init__(self, key_id, key_secret, target_app="builder", account_id=None): self.client_id = f"apikey-{key_id}" self.key_secret = key_secret self.target_app = target_app self.account_id = account_id self.token = None self.token_expiry = None
def _token_expired(self): if not self.token or not self.token_expiry: return True # Refresh a minute early to absorb clock skew and request latency. return datetime.now(timezone.utc) > (self.token_expiry - timedelta(minutes=1))
def ensure_valid_token(self): if self._token_expired(): self.authenticate()
def authenticate(self): data = { "grant_type": "client_credentials", "client_id": self.client_id, "client_secret": self.key_secret, "target_app": self.target_app, } if self.account_id is not None: data["account_id"] = self.account_id resp = requests.post(self.TOKEN_URL, data=data, timeout=30) resp.raise_for_status() body = resp.json() self.token = body["access_token"] self.token_expiry = datetime.now(timezone.utc) + timedelta(seconds=body["expires_in"])
def make_request(self, url, method="GET", headers=None, **kwargs): self.ensure_valid_token() req_headers = {"Authorization": f"Bearer {self.token}", **(headers or {})} resp = requests.request(method, url, headers=req_headers, **kwargs) if resp.status_code == 401: # The token may have been revoked or expired early. Re-exchange the key # ONCE and retry. authenticate() raises for an invalid/revoked key, so a # genuinely bad credential fails fast instead of looping. self.authenticate() req_headers["Authorization"] = f"Bearer {self.token}" resp = requests.request(method, url, headers=req_headers, **kwargs) return respMulti-Account Authentication
Section titled “Multi-Account Authentication”A single Synthreo identity can have access to more than one account, across multiple customers (tenants) and application instances. By default the token targets your primary account. To scope a token to a specific account, pass its account_id in the token request:
curl -X POST 'https://auth.synthreo.ai/connect/token' \ -H 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=client_credentials' \ --data-urlencode 'client_id=apikey-42' \ --data-urlencode 'client_secret=sak_your_key_secret_here' \ --data-urlencode 'target_app=builder' \ --data-urlencode 'account_id=1234'The same API key can also target other Synthreo apps by changing target_app (threo, tenant), subject to your account’s access. If you’re unsure which account or app to use, contact your Synthreo representative.
Security Best Practices
Section titled “Security Best Practices”- Treat the key secret like a password. Store it in environment variables or a secret manager - never in client-side code or version control.
- Never expose the secret in a browser or mobile app. The client credentials grant is for server-to-server use.
- Do not log tokens or secrets.
- Rotate keys by creating a new key and revoking the old one from the API Keys tab.
- Revoke immediately if a key is ever exposed. Revocation takes effect at once; existing tokens still expire within 15 minutes.
- Use HTTPS exclusively for all API communication.
Related pages:
- Introduction to the Builder API - overview of the API and key concepts
- Cognitive Diagrams API - executing AI workflows after authenticating
- Best Practices - token management patterns for production integrations

