Credentials give your app keys and connections that belong to an external service: an API key for Acme, an OpenAI key, a Google sign-in. Each user supplies their own, and the platform passes them to your app at run time.
A value that belongs to no service, such as a webhook signing token, is a plain secret instead.
→ Concepts: providers, credentials, secrets and vaults
Declaring credentials
List them under credentials: in inf.yml. Each entry names a provider, a capability, or both.
API keys from a provider
Name the provider and the keys your app reads:
1credentials:2 - provider: acme3 name: Acme CRM4 website: acme.com5 secrets: [ACME_API_KEY]6 description: Syncs contacts from your Acme workspaceWhen a user runs the app without an Acme key, the run stops and asks for ACME_API_KEY. The key they paste is saved as their workspace's Acme CRM credential. Its logo comes from acme.com, and it shows in the vault like any other connection. Later runs, and any other app that asks for acme, find it there.
The provider doesn't have to be one the platform lists. name and website describe it for users who haven't added it yet. For a provider the platform lists, such as openai, leave them out; the platform's name and logo win.
Who can list a provider for everyone
The platform's provider catalog is shared by every workspace, so only platform apps can add to it:
- A platform app (owned by a platform admin) that declares a provider the catalog doesn't have adds it on deploy, with the given
nameand the logo fromwebsite. Every workspace then sees it in the vault, ready to connect. This happens the same way platform apps are approved in the store automatically. - Any other app doesn't change the catalog. The provider still works for each workspace that runs the app: the key a user saves becomes their workspace's credential for it, under the app's
nameand logo. It just isn't listed for workspaces that haven't used it.
This keeps slugs from being claimed by whoever deploys first. To get a provider listed for everyone, ask a platform admin.
Leave out secrets to receive every key the provider's credential holds.
OAuth capabilities
For a service users sign in to, name the capability. It decides the access (the OAuth scopes) your app gets:
1credentials:2 - key: google.sheets3 description: Read and write your sales sheets45 - key: google.drive6 description: Attach exported files7 optional: trueUsers without a Google connection are asked to connect one. Users who have one without Sheets access are asked to grant it.
Properties
| Property | Type | Description |
|---|---|---|
provider | string | Slug of the provider whose credential supplies the keys, such as acme or openai. Lowercase letters, digits and single hyphens. |
name | string | Display name for a provider the platform doesn't list |
website | string | The provider's website, where its logo comes from (acme.com) |
secrets | string[] | Keys to pass to the app from the credential. They are also the fields users fill in when the key is missing. |
key | string | A capability of a provider the platform defines (google.sheets, x.tweet.write). When set, it decides how the entry is checked. |
scopes | string[] | OAuth scopes to require from the provider's credential, for an entry without key |
description | string | Shown to users when the credential is missing |
optional | boolean | If true, the app runs without it |
Each entry needs provider or key. A deploy with an invalid provider fails with a validation error.
The section was called integrations: before 2026-09-23. Current belt refuses that name and asks you to rename it.
Available capabilities
List the capability keys the platform defines:
1belt app credentials listCommon capabilities
| Key | Description |
|---|---|
google.sheets | Read/write Google Sheets |
google.sheets.readonly | Read-only Sheets access |
google.drive | Google Drive files |
google-sa.files | Service account access (Sheets, Docs, Drive) |
microsoft.mail.read | Read Outlook email |
notion.read | Read shared Notion pages |
salesforce.api | Salesforce REST API access |
reddit.read | Read Reddit posts and comments |
→ Credentials overview for setup guides (Google, Slack, Microsoft, Notion, Salesforce, Reddit, and more)
Accessing credentials
API keys
Each key listed under secrets arrives as an environment variable with the same name:
1import os23class App(BaseApp):4 async def setup(self, config):5 self.acme_key = os.environ["ACME_API_KEY"]OAuth Credentials
1import os, json23class App(BaseApp):4 async def setup(self, config):5 creds_json = os.environ.get("GOOGLE_OAUTH_CREDENTIALS")6 if creds_json:7 self.credentials = json.loads(creds_json)Service Account
1from google.oauth2 import service_account23sa_json = os.environ.get("GOOGLE_SA_CREDENTIALS")4if sa_json:5 self.credentials = service_account.Credentials.from_service_account_info(6 json.loads(sa_json)7 )Secrets vs credentials
secrets: | credentials: | |
|---|---|---|
| The value belongs to | No service | A provider |
| Users see | A key name to fill in | The provider, with its name and logo |
| Stored as | A plain secret | That provider's credential, with a scope and a status |
| Reused by | Apps that ask for the same key name | Every app that asks for the provider |
| Best for | Webhook tokens, feature flags | API keys, OAuth sign-ins |
Check before run
Validate that your workspace has the secrets and credentials an app requires before calling POST /run:
POST /credentials/check
Requires credentials:read scope. Send the same secrets and credentials arrays from your app's inf.yml:
1curl -X POST https://api.inference.sh/credentials/check \2 -H "Authorization: Bearer inf_your_key" \3 -H "Content-Type: application/json" \4 -d '{5 "secrets": [{ "key": "WEBHOOK_SECRET" }],6 "credentials": [7 { "provider": "acme", "secrets": ["ACME_API_KEY"] },8 { "key": "google.sheets" }9 ]10 }'When requirements are missing, the response matches the 412 body from POST /run (satisfied: false and an errors array). See REST overview — Missing requirements.
Connect from the CLI
Connect native OAuth and service-account providers without the dashboard:
1belt credentials connect google2belt credentials connect slack3belt credentials disconnect googleFor MCP connector servers, use belt mcp connect <slug> instead. List connected services with belt credentials list (belt creds is an alias).
When a provider supports multiple connection types (Google has OAuth at google and a separate service account at google-sa), use the provider key that matches the connection you need. Connect a Google service account from vaults → credentials (google-sa slug) or with belt credentials connect google-sa.
When you run an app or agent and requirements are still missing, the CLI prints the same errors[] categories with actionable commands — for example belt secrets set OPENAI_API_KEY <value> or belt credentials connect google.
→ CLI setup: Credentials · Credentials API
Best Practices
- Request minimal scopes - use
readonlyif you only read - Clear descriptions - explain why access is needed
- Handle missing gracefully - check if optional credentials exist
- Test without - ensure app works without optional credentials
REST API
Programmatic connect, disconnect, and requirements checks:
→ Credentials API — POST /credentials, POST /credentials/check, MCP tool proxy
Next
→ Troubleshooting - Common issues and solutions