Connect OAuth services, service accounts, and MCP servers for your team. 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).
Deprecated alias: the former
/integrations/...paths (and/admin/integrations/...) still work and serve the same handlers. Responses carry aDeprecation: trueheader and aLinkheader pointing to the/credentialspath. Use/credentialsin new code.
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. Team- and user-scoped credentials are linked to the team's default vault when they are created. Team-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 — provider catalog joined with your team'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, grant) and, when connected, a nested credential object with live status, account info, and OAuth scopes. Each entry has a unique slug (for example google, google-sa, gcp, slack). User-scoped providers (grant: "credentials") 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 workspace 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 | Team can supply its own credentials instead of OAuth |
available | boolean | Provider is registered on this server |
has_managed | boolean | Platform has managed credentials configured (teams can use without BYOK) |
grant | string | When has_managed is true for OAuth: credentials (each user connects their own account) or token (ready-to-use access for the whole team). Omitted for team-level OAuth or non-OAuth types. See Managed credentials and grant type. |
credential | object | Connected credential object when your team (or you, for user-scoped 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 — each maps to exactly one connection type. MCP supports multiple connections per team, 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 team (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 — it 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 team connection), user (your personal connection), org (shared across all teams in the organization), platform (managed by the platform), or agent (agent-scoped) |
grant | string | For managed OAuth providers: credentials or token (see Managed credentials and grant type) |
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. Team-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 teams 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 team admin role unless you created it. When allows_byok is true on the provider config, a team can override an inherited credential with its own: OAuth providers via POST /credentials, and api_key providers by saving a team 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
When the platform configures managed OAuth credentials for a provider (has_managed: true), the grant field on GET /credentials/configs describes how those credentials are used:
grant | Meaning | Connection scope | Workspace UI |
|---|---|---|---|
| (omitted) | Team-level OAuth — one account shared by all members | team | connect {name} |
credentials | Platform supplies the OAuth app (client_id / client_secret); each member authorizes their own account | user | connect your {name} account; list shows (your account) suffix when collapsed, your account — via team's {name} app when expanded, and provided by your team — connect your account when not connected; detail page uses your account heading and disconnect your account |
token | Platform supplies a ready-to-use token or API key for the whole team | team | connect {name} |
grant=credentials is only valid for type: "oauth". When you connect a credentials provider, the API creates a user-scoped credential (scope: "user") tied to the signed-in member. Other team members connect separately with their own accounts.
Use grant from the config to customize setup copy — for example, show connect your {name} account instead of a generic connect button when each user must authorize individually. Check scope on the connected CredentialDTO to distinguish personal vs team 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}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 | Team 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 team | Team admin |
org | All teams in the organization | Org admin, calling from the org's own team |
platform | All teams on the platform | Platform admin, calling from the platform team |
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 team admin, or "org" without org admin |
validation_error | 400 | An unknown connection_scope, org when the team is not part of an organization, or org / platform requested from a team other than the org's or platform's own team. 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 team connections that used provider: "google" or provider: "gcp" with auth: "service_account" were migrated to google-sa in a one-time database update — no reconnect 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 team 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 team 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 team'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 team, 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 | Workspace deep link |
|---|---|---|
add_secret | User must add a team secret | Vault → 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 team'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