Connected apps
Let a third-party app act on behalf of a Telos user without handling their password or an API key. Standard authorization-code flow with PKCE; access tokens start telos_oat_and authenticate the REST API and MCP exactly like a personal key — the difference is the token's permissions are its granted scopes, nothing more.
Authorization code + PKCE
Send the user to the authorize screen. An org admin reviews the requested scopes and approves; Telos redirects back to your redirect_uri with a one-time code and your state. PKCE (S256) is required for public clients and recommended for all.
https://www.telos-app.com/oauth/authorize
?client_id=app_…
&redirect_uri=https://your-app.example.com/callback
&response_type=code
&scope=opportunity:read%20task:read%20insight:create
&state=<opaque-csrf-token>
&code_challenge=<base64url-sha256(verifier)>
&code_challenge_method=S256Exchange the code for a token
Exchange the code at the token endpoint. Public clients prove possession with the PKCE code_verifier; confidential clients send their client_secret. The endpoint speaks RFC 6749 form-encoding and returns RFC 6749 shapes — not the /api/v1 envelope.
curl -X POST 'https://www.telos-app.com/api/oauth/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d grant_type=authorization_code \
-d client_id=app_… \
-d code=<authorization-code> \
-d redirect_uri=https://your-app.example.com/callback \
-d code_verifier=<pkce-verifier> # public clients
# -d client_secret=<secret> # confidential clients{
"access_token": "telos_oat_…",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "…"
}Refresh
Access tokens are short-lived (expires_in seconds). Trade the refresh token for a new pair; refresh tokens rotate on use, so store the latest one each time.
curl -X POST 'https://www.telos-app.com/api/oauth/token' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d grant_type=refresh_token \
-d client_id=app_… \
-d refresh_token=<refresh-token>Registering an app
Apps are registered in-product under Configurations → Connected accounts by an org admin (the oauth_app:manage capability). You set the app name, one or more redirect_uris, the allowed scopes, and the client type: confidential (server-side, issued a secret you can rotate) or public(SPA/native, PKCE only, no secret). A granted token can never exceed the app's allowed scopes, and is re-intersected with the granting user's live permissions on every call — if that user is demoted or deactivated, the token shrinks or dies with them.
Scopes
Scopes are capability strings of the form resource:action. A token's scopes are its entire permission set. The full vocabulary (96 capabilities) is below; the ones marked admin can never be granted to an app or API key, only held by a signed-in user.
- api_key:read
- api_key:manageadmin
- comment:read
- comment:create
- comment:update
- comment:delete
- compensation:read
- compensation:update
- cost:read
- cost:update
- customer:read
- customer:create
- customer:update
- customer:delete
- file:read
- file:manage
- insight:read
- insight:create
- insight:update
- insight:delete
- intake:read
- intake:create
- intake:update
- intake:delete
- integration:read
- integration:manageadmin
- llm_config:read
- llm_config:update
- message:read
- message:create
- message:update
- message:delete
- metric:read
- metric:create
- metric:update
- metric:delete
- oauth_app:read
- oauth_app:manageadmin
- objective:read
- objective:create
- objective:update
- objective:delete
- opportunity:read
- opportunity:create
- opportunity:update
- opportunity:delete
- org:manageadmin
- prd_template:read
- prd_template:create
- prd_template:update
- prd_template:delete
- role:read
- role:manageadmin
- room:read
- room:create
- room:update
- room:delete
- strategy:read
- strategy:create
- strategy:update
- strategy:delete
- tag:read
- tag:create
- tag:update
- tag:delete
- task:read
- task:create
- task:update
- task:delete
- team:read
- team:create
- team:update
- team:delete
- time_entry:read
- time_entry:create
- time_entry:update
- time_entry:delete
- time_entry:read_others
- user:read
- user:update
- vision:read
- vision:create
- vision:update
- vision:delete
- webhook:read
- webhook:create
- webhook:update
- webhook:delete
- workflow:read
- workflow:create
- workflow:update
- workflow:delete
- workflow_category:read
- workflow_category:create
- workflow_category:update
- workflow_category:delete