Connect OAuth services, service accounts, and MCP servers for your workspace. Credentials supply tokens and keys to apps and agents at run time.
→ Extend credentials — declare requirements in inf.yml
→ Connectors overview — MCP connectors and agent tools
Requires API key scopes credentials:read (list, capabilities, check) and credentials:write (connect, disconnect, call tools).
Paths under
/integrations(the name before 2026-09-23) answer410 Gonewith aLinkheader naming the/credentialspath.
Connect stores non-OAuth credentials (service accounts, MCP bearer tokens) and OAuth tokens in encrypted JSON on the credential row — tokens are never returned in API responses. Disconnect loads stored tokens, calls provider cleanup when supported, then soft-deletes the connection.
MCP tool proxy (/mcps/{slug}/tools) is not part of the credentials namespace.
Vaults
Credentials and secrets are grouped into vaults. Workspace- and user-scoped credentials are linked to the workspace's default vault when they are created. Workspace-scoped secrets are linked on create as well. Use GET /vaults/{id}/credentials and GET /vaults/{id}/secrets to list members, and the POST/DELETE membership endpoints to manage links without deleting the underlying credential or secret.
Capabilities catalog
GET /credentials/capabilities
Returns credential keys your apps can declare (for example google.sheets, google-sa.files). Each capability includes provider, type, OAuth scopes, and whether it is available on this server.
1curl https://api.inference.sh/credentials/capabilities \2 -H "Authorization: Bearer inf_your_key"Response:
1{2 "capabilities": [3 {4 "key": "google.sheets",5 "provider": "google",6 "type": "oauth",7 "scopes": ["https://www.googleapis.com/auth/spreadsheets"],8 "display_name": "Google Sheets",9 "available": true10 }11 ]12}Use this to build setup UIs or validate inf.yml credential keys before deploy.
Credential configs
GET /credentials/configs
Returns the merged credential view: the provider catalog joined with your workspace's connection state in one response. Each registered provider (OAuth, BYOK, service accounts) appears once with catalog metadata (display names, descriptions, icons, docs links, BYOK form fields, has_managed, connection_scope) and, when connected, a nested credential object with live status, account info, and OAuth scopes. OAuth providers may also include an app object — the OAuth application row (client id/secret), separate from the login in credential. Each entry has a unique slug (for example google, google-sa, gcp, slack). Providers whose default connection_scope is user include your personal connection in credential when you are authenticated.
Connected credentials without a catalog entry (MCP servers) are appended as standalone rows at the end of the array (compound provider values like mcp:mcp.linear.app).
Requires credentials:read.
1curl https://api.inference.sh/credentials/configs \2 -H "Authorization: Bearer inf_your_key"Response (array of config objects):
| Field | Type | Description |
|---|---|---|
slug | string | URL-friendly identifier for this provider (for example google, google-sa, gcp, slack). Used in the web app's detail page URLs (/credentials/{slug}). Defaults to provider when not set. |
provider | string | Provider key used in POST /credentials connect calls (for example google, google-sa, gcp, slack) |
type | string | Credential type (oauth, service_account, …) |
name | string | Display name |
short_name | string | Short label |
description | string | Provider description |
icon_url | string | Logo URL |
how_it_works | string[] | Setup steps shown in the UI |
docs_url | string | Link to provider docs |
secret_fields | array | BYOK form fields (key, label, placeholder, sensitive, optional) |
allows_byok | boolean | Workspace can supply its own credentials instead of OAuth |
available | boolean | Provider is registered on this server |
has_managed | boolean | Platform has managed credentials configured (workspaces can use without BYOK) |
connection_scope | string | Default owner for new connections: user (each member connects their own account) or team (shared workspace connection), plus org / platform where applicable. Drives connect-button copy — see Managed credentials and grant type. |
app | object | OAuth app credential (grant: "credentials") when logins go through a configured client id/secret (workspace, org, or platform). Omitted when the provider does not use an app row or none is set up yet. Configure with PUT /credentials/{provider}/app. |
auth_scheme_id | string | When the provider is a custom auth scheme the team defined — enables edit/remove in the UI |
credential | object | Connected credential object (the login) when your workspace (or you, for connection_scope: "user" providers) has connected this provider; omitted when not connected |
Native providers (OAuth, BYOK, service accounts) appear once per provider. MCP servers are not in the provider catalog, but connected MCP instances are included as additional entries with type: "mcp" and compound provider values (for example mcp:mcp.linear.app). To browse or connect new MCP servers, use the MCP servers API or POST /credentials with provider: "mcp".
For MCP browse and connect UIs, authenticated GET /mcps and GET /mcp-servers responses carry connection_status for each server_url. Use those endpoints instead of merging this configs array with MCP server lists.
Provider names are globally unique for native providers, and each maps to exactly one connection type. MCP supports multiple connections per workspace, so connected MCP rows use compound provider values (mcp:{hostname}). Use slug for dashboard links and provider for POST /credentials, GET /credentials/{provider}, and DELETE /credentials/{provider}.
JavaScript SDK: client.credentials.getConfigs()
Available providers
GET /credentials/available
Returns a simple list of provider names that can be connected on this server (for example google, google-sa, gcp, slack). Requires credentials:read.
1curl https://api.inference.sh/credentials/available \2 -H "Authorization: Bearer inf_your_key"JavaScript SDK: client.credentials.listAvailable()
List connected credentials
GET /credentials or POST /credentials/list
Cursor-paginated list of credentials connected for your workspace (and per-user connections when applicable). Use this when you need to page through all connections or look up a single provider by key. For setup UIs that show catalog metadata alongside connection state, prefer GET /credentials/configs, which returns the merged view in one call.
1curl https://api.inference.sh/credentials \2 -H "Authorization: Bearer inf_your_key"CLI equivalent: belt credentials list (add --json for the raw items array). The CLI calls POST /credentials/list.
GET /credentials/{provider} returns a single credential by provider key (for example google, google-sa, gcp, slack, mcp:mcp.linear.app). MCP servers use compound names because each connection is a separate instance.
1curl https://api.inference.sh/credentials/google \2 -H "Authorization: Bearer inf_your_key"34curl https://api.inference.sh/credentials/google-sa \5 -H "Authorization: Bearer inf_your_key"CLI equivalent: belt credentials get <provider> (for example belt credentials get google, belt credentials get google-sa, or belt credentials get mcp:mcp.linear.app). The CLI calls GET /credentials/{provider}.
JavaScript SDK: client.credentials.get(provider) — same response as the REST endpoint.
Credential object fields
Each connected credential (CredentialDTO) includes:
| Field | Type | Description |
|---|---|---|
scope | string | team (shared workspace connection), user (your personal connection), org (shared across all workspaces in the organization), platform (managed by the platform), or agent (agent-scoped) |
grant | string | For managed OAuth providers: credentials (OAuth app row — never a login) or token (a connection: OAuth login, API key, service account, MCP authorization). See Managed credentials and grant type. |
app_credential_id | string | When this row is a login (grant: "token") that signed in through an OAuth app, the id of that app credential row |
provider | string | Provider key |
type | string | Credential type |
auth | string | Authentication mechanism |
status | string | connected, disconnected, pending, expired, or error |
display_name | string | User-facing label |
scopes | string[] | Granted OAuth capability keys |
account_identifier | string | Connected account ID (email, username, …) |
account_name | string | Display name for the account |
expires_at | string | OAuth token expiry (ISO timestamp) |
error_message | string | Human-readable detail when status is expired or error (for example "No refresh token available") |
is_primary | boolean | Whether this is the primary credential for the provider |
vault_id | string | Optional vault reference for encrypted secret storage |
metadata | object | Provider-specific configuration (env var mapping, allowed hosts, …) |
pending means the credential row was created (often by an agent run that needs credentials) but OAuth or BYOK setup has not finished. Until status becomes connected, apps and agents that require the credential fail validation.
Raw tokens are never returned. Workspace-scoped credentials (scope: "team") are created by your connect flows; user-scoped rows (scope: "user") are personal connections when the platform provides OAuth app credentials (grant: "credentials"); org-scoped rows (scope: "org") are shared across all workspaces in the organization; platform-scoped rows (scope: "platform") use managed credentials when has_managed is true on the provider config. When several rows match, your own user connection is used first, then the team row, then org, then platform.
Only platform admins can replace or remove a platform credential, and only org admins an org credential. A shared team credential needs the workspace admin role unless you created it. When allows_byok is true on the provider config, a workspace can override an inherited credential with its own: OAuth providers via POST /credentials, and api_key providers by saving a workspace secret with the provider field set (see Create secret). For api_key providers the credential's status is connected while at least one linked key secret exists and disconnected after the last one is removed.
Managed credentials and grant type
Each config entry exposes connection_scope — who owns new connections by default. Use it for setup copy:
connection_scope | Meaning | Web app UI |
|---|---|---|
team | One shared workspace connection (or a ready-to-use platform token) | connect {name} |
user | Each member authorizes their own account | connect your {name} account; detail pages use your account / disconnect your account |
When the provider signs in through an OAuth application, app holds that app row (grant: "credentials" — client id/secret only, not a login). credential holds the login (grant: "token" for OAuth connections). Completed OAuth stores which app was used on the login as app_credential_id.
grant on CredentialDTO (including nested app and credential objects) distinguishes app rows from connection rows:
grant | Row kind | Typical scope |
|---|---|---|
credentials | OAuth application (client credentials) | team, org, or platform |
token | Connection (OAuth login, API key, service account, MCP authorization) | user, team, org, or platform |
grant=credentials is only valid for type: "oauth" app rows. Per-user OAuth providers use connection_scope: "user" on the config; each member's login appears in credential with scope: "user".
Check scope on the connected CredentialDTO to distinguish personal vs workspace connections in list and detail UIs.
Connect a credential
POST /credentials
Starts OAuth, creates a service account, or registers an MCP server connection.
OAuth providers
1{2 "provider": "google",3 "type": "oauth",4 "scopes": ["https://www.googleapis.com/auth/spreadsheets"]5}Response when the user must complete OAuth in a browser:
1{2 "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?...",3 "state": "state_abc123",4 "code_verifier": "..."5}Open auth_url, then complete the flow with POST /credentials/oauth/complete:
1{2 "provider": "google",3 "type": "oauth",4 "code": "authorization_code",5 "state": "state_abc123",6 "code_verifier": "..."7}Some providers add extra query parameters on the redirect (QuickBooks realmId, Shopify shop, and so on). Pass them in optional params on the complete request (every key except code and state, which stay top-level). Auth schemes read them as {{callback.*}} — see Callback query parameters on OAuth complete.
Omit code_verifier when you started connect with the same state — the API stores the PKCE verifier from POST /credentials and claims it when completing OAuth. Pass code_verifier explicitly when your client held it locally and did not use the server-stored challenge.
| Error | HTTP | When | Meaning |
|---|---|---|---|
already_exists | 409 | Connect | Workspace already connected this provider |
already_exists | 409 | Complete OAuth | A different account is already connected — disconnect first |
invalid_grant | 400 | Complete OAuth | OAuth state or PKCE challenge expired — restart connect |
invalid_provider | 400 | Connect | Unknown provider |
When reconnecting an expired or error credential, you can call POST /credentials with the same provider and an empty scopes array (or omit scopes). The API carries forward previously granted scopes in the OAuth consent URL so the user restores all permissions in one step instead of starting from zero.
Connection scope
Optional connection_scope on POST /credentials sets who owns the resulting credential. It is separate from scopes, which are OAuth permission scopes.
1{2 "provider": "google",3 "type": "oauth",4 "scopes": ["https://www.googleapis.com/auth/spreadsheets"],5 "connection_scope": "team"6}connection_scope | Who can use it | Requirement |
|---|---|---|
user | Only the connecting user | Any member |
team | The whole workspace | Workspace admin |
org | All workspaces in the organization | Org admin, calling from the organization workspace |
platform | All workspaces on the platform | Platform admin, calling from the platform workspace |
Omit connection_scope to use the provider's default: the scope the provider declares (user for MCP), user for grant=credentials providers, team otherwise.
There is no API that changes a credential's scope after creation. Choose connection_scope at connect time, or on POST /secrets when saving a BYOK API key with provider. To use a different scope, disconnect and reconnect.
For OAuth flows the chosen scope is stored server-side with the OAuth state and applied when oauth/complete runs. The completing client does not resend connection_scope.
| Error | HTTP | When |
|---|---|---|
team_role_required | 403 | connection_scope: "team" without workspace admin, or "org" without org admin |
validation_error | 400 | An unknown connection_scope, org when the workspace is not part of an organization, or org / platform requested from a workspace other than the organization or platform workspace. detail says which. |
forbidden | 403 | connection_scope: "platform" without platform admin |
Service accounts
Google Sheets/Docs/Drive service accounts use the google-sa provider (separate from Google OAuth's google and GCP WIF's gcp):
1{2 "provider": "google-sa",3 "type": "service_account"4}Returns credential when the connection is created immediately (no redirect). Declare google-sa.files in inf.yml (replaces the former google.sa and interim gcp.sa capability keys). Existing workspace connections that used provider: "google" or provider: "gcp" with auth: "service_account" were migrated to google-sa in a one-time database update, so no reconnect is required.
Custom MCP servers
Connect an arbitrary HTTPS MCP endpoint (same flow as belt mcp connect):
1{2 "provider": "mcp",3 "type": "mcp",4 "metadata": {5 "server_url": "https://mcp.example.com"6 }7}For bare origins, the API may resolve the MCP path via /.well-known/mcp-server-card or UCP discovery — see Browsing connectors.
CLI equivalent: belt credentials connect <provider> (for example belt credentials connect google). The CLI resolves the provider from GET /credentials/configs, opens a browser for OAuth, and polls until connected. MCP servers use belt mcp connect <slug> instead. belt creds and belt integrations are aliases for belt credentials.
Bearer token / API key connect
When the remote MCP server accepts a pre-issued bearer token (API key, personal access token, or similar) instead of OAuth, pass it in metadata.bearer_token. The API skips OAuth discovery, stores the token as an encrypted workspace secret, and returns credential immediately:
1{2 "provider": "mcp",3 "type": "mcp",4 "metadata": {5 "server_url": "https://mcp.example.com",6 "bearer_token": "your-api-key-or-pat",7 "display_name": "My MCP Server"8 }9}| Metadata field | Required | Description |
|---|---|---|
server_url | Yes | MCP endpoint or bare origin (resolved via discovery when needed) |
bearer_token | Yes (for this flow) | Token sent as Authorization: Bearer on MCP requests |
display_name | No | Label in the connected-apps list (defaults from server introspection or hostname) |
The connect response omits the token. Use GET /credentials/{provider} or belt credentials get mcp:{hostname} to confirm the connection is connected before calling tools.
→ Browsing connectors — API key servers
MCP OAuth client identity
When the remote MCP server requires OAuth, the API acts as a public OAuth client (PKCE, no client secret). Client identity is resolved in this order:
- BYOK:
oauth_client_idon a workspace MCP server registration, or a platform-managed secret keyed by hostname - Client ID Metadata Document (CIMD, SEP-991): when the authorization server advertises
client_id_metadata_document_supported, the API uses its hosted metadata document URL asclient_id(no Dynamic Client Registration) - Dynamic Client Registration (DCR): registers a new client when the server exposes a registration endpoint and CIMD is unavailable
The CIMD document is public (no API key):
1GET https://api.inference.sh/.well-known/mcp-client.json1{2 "client_id": "https://api.inference.sh/.well-known/mcp-client.json",3 "client_name": "inference.sh",4 "client_uri": "https://app.inference.sh",5 "redirect_uris": ["https://app.inference.sh/settings/secrets/oauth/mcp"],6 "grant_types": ["authorization_code", "refresh_token"],7 "response_types": ["code"],8 "token_endpoint_auth_method": "none"9}The client_id URL must match the document location. On self-hosted API deployments, set API_HOST to the public API base URL (for example https://api.example.com). If API_HOST is unset, CIMD is disabled and the connect flow falls back to DCR or BYOK credentials.
Add OAuth scopes
POST /credentials/{provider}/scopes
Request additional scopes for an existing OAuth credential (incremental authorization):
1{2 "scopes": ["https://www.googleapis.com/auth/drive.readonly"]3}Response (same shape as Connect a credential):
1{2 "auth_url": "https://accounts.google.com/o/oauth2/v2/auth?...",3 "state": "st_abc123",4 "code_verifier": ""5}Redirect the user to auth_url to approve the new scopes, then complete the flow with POST /credentials/oauth/complete (or your app's OAuth callback handler). Omit code_verifier when the API returned a non-empty value from connect or add-scopes — it is stored with the state challenge.
Incremental vs full re-authorization
Providers that support incremental authorization (for example google, microsoft, slack, salesforce, discord) return a consent URL that adds only the requested scopes. Existing grants are preserved.
Providers that do not support incremental auth (for example x) fall back to a full re-authorization URL that includes all existing scopes plus the new ones. The user must approve the combined scope list again.
Account pre-selection (login_hint)
When the credential has an account_identifier (email or username from the original connect), the API appends login_hint to auth_url for incremental-auth providers. OAuth providers such as Google use this to pre-select the same account so the user does not have to pick it again from an account chooser.
login_hint is omitted when account_identifier is empty (for example, some MCP or service-account credentials).
Disconnect
DELETE /credentials/{provider}
Revokes tokens with the provider when supported, then soft-deletes the workspace's connection for that provider. Vault membership links for the credential are removed as well. Apps that require the credential will fail until it is reconnected.
An optional identifier query parameter selects one connection by its account_identifier. belt mcp disconnect uses it with the MCP server URL:
1curl -X DELETE 'https://api.inference.sh/credentials/mcp?identifier=https%3A%2F%2Fmcp.linear.app%2Fsse' \2 -H "Authorization: Bearer inf_your_key"With identifier, the API looks for your own user-scoped connection first, then the shared workspace, org, and platform rows for the same account.
CLI equivalent: belt credentials disconnect <provider> (for example belt credentials disconnect google or belt credentials disconnect google-sa).
Check requirements (pre-flight)
POST /credentials/check
Validate secrets and credentials before calling POST /run. Returns 200 with a structured result (not HTTP 412):
1{2 "secrets": [3 { "key": "OPENAI_API_KEY", "optional": false }4 ],5 "credentials": [6 { "key": "google.sheets", "optional": false }7 ]8}Response:
1{2 "satisfied": false,3 "errors": [4 {5 "type": "secret",6 "key": "OPENAI_API_KEY",7 "message": "Missing secret: OPENAI_API_KEY",8 "action": { "type": "add_secret" }9 },10 {11 "type": "credential",12 "key": "google.sheets",13 "message": "connect Google Account to use this app",14 "action": {15 "type": "connect",16 "provider": "google",17 "provider_name": "Google Account",18 "scopes": ["https://www.googleapis.com/auth/spreadsheets"],19 "scope_descriptions": {20 "https://www.googleapis.com/auth/spreadsheets": "View and manage your spreadsheets"21 }22 }23 },24 {25 "type": "scope",26 "key": "google.sheets",27 "message": "Google Account connected but missing permissions: [https://www.googleapis.com/auth/spreadsheets]",28 "action": {29 "type": "add_scopes",30 "provider": "google",31 "provider_name": "Google Account",32 "scopes": ["https://www.googleapis.com/auth/spreadsheets"],33 "scope_descriptions": {34 "https://www.googleapis.com/auth/spreadsheets": "View and manage your spreadsheets"35 }36 }37 }38 ]39}Each errors[] entry has type (secret, credential, or scope), key, message, and optional action (add_secret, connect, add_scopes).
action.type | Meaning | Web app deep link |
|---|---|---|
add_secret | User must add a workspace secret | vaults → secrets |
connect | User must connect a credential | https://app.inference.sh/credentials/{slug} |
add_scopes | User must grant additional OAuth scopes | https://app.inference.sh/credentials/{slug} |
action field | When present | Purpose |
|---|---|---|
provider | connect, add_scopes | Provider key for API connect calls and CLI (for example google, google-sa, gcp, slack) |
provider_name | connect, add_scopes | Human-readable label for UI copy (for example Google Account, Slack) — also used in message |
scopes | connect, add_scopes | OAuth scopes to request or add |
scope_descriptions | connect, add_scopes | Map of scope key → friendly display name from provider capabilities (for UI lists without hardcoded labels) |
Use provider (not provider_name) when calling POST /credentials or belt credentials connect. Use provider_name or message when showing setup prompts to end users.
For dashboard links, resolve {slug} from GET /credentials/configs — match provider and the capability type from GET /credentials/capabilities. For most providers slug equals provider; Google OAuth uses google, the Sheets/Docs/Drive service account uses google-sa, and GCP WIF uses gcp. → Credentials overview — detail page
When requirements are missing at run time, POST /run returns 412 Precondition Failed with the same error shape. Use check when you want to surface setup steps without submitting a task.
CLI: belt app run and belt agent run catch 412 responses and print categorized hints — belt secrets set for missing secrets, belt credentials connect for OAuth providers, belt mcp connect for MCP requirements, or connect at: https://app.inference.sh/vaults when the requirement names no provider. Next to belt credentials connect <provider> the CLI also prints or: https://app.inference.sh/vaults/<provider>.
→ Secrets · CLI setup · Troubleshooting
MCP tool proxy
After connecting an MCP server (provider: "mcp"), call tools over HTTP:
| Endpoint | Method | Scope | Purpose |
|---|---|---|---|
/mcps/{slug}/tools | GET | credentials:read | List tools exposed by the server |
/mcps/{slug}/tools/{tool} | POST | credentials:write | Invoke a tool (body is forwarded to the MCP server) |
{slug} is the MCP server slug (for example linear from the connector directory). Tool calls are recorded in your workspace's credential history.
CLI equivalent: belt mcp tools <slug> and belt mcp run <slug>:<tool>.
→ Connectors browsing · MCP server
JavaScript SDK
1import { inference } from '@inferencesh/sdk';23const client = inference({ apiKey: 'inf_your_key' });45const caps = await client.credentials.getCapabilities();6const { auth_url } = await client.credentials.connect({7 provider: 'google',8 type: 'oauth',9 scopes: ['https://www.googleapis.com/auth/spreadsheets'],10});11await client.credentials.checkRequirements({12 secrets: [{ key: 'OPENAI_API_KEY' }],13 credentials: [{ key: 'google.sheets' }],14});→ SDK overview — client.credentials namespace
Related
- REST overview — authentication and response format
- Entitlements — connector limits on your plan
- Agent connector tools — use credentials from agents