Named credentials
Store an outbound connection once — base URL plus authentication — and call it from functions, custom actions, flows and webhooks without your code ever seeing the secret.
A named credential is one of your organization's outbound connections: an
apiName, an https base URL and how to authenticate to it. Code and
configuration refer to it by name; SalesOS adds the authentication on its side
for every call, keeps the call under the base URL and logs it. Rotating a
partner's key means editing one credential.
Manage them under Settings → Developer → Connections, or with
/v1/named-credentials (org owners and admins, session only; part of API
access). Secrets are write-only: they are encrypted at rest and never returned
by any endpoint — a credential shows hasSecret / missingSecrets instead.
Authentication
authType | Configuration | Sent on each call |
|---|---|---|
NONE | — | nothing |
API_KEY_HEADER | headerName, secret | <headerName>: <secret> |
BEARER | secret | Authorization: Bearer <secret> |
BASIC | username, secret (the password) | Authorization: Basic … |
OAUTH2_CLIENT_CREDENTIALS | tokenUrl, clientId, clientSecret, optional scopes | Authorization: Bearer <access token> |
For client credentials SalesOS posts grant_type=client_credentials (with
client_id, client_secret and scope) to the token URL, reuses the access
token until shortly before expires_in, and on a 401 from the API fetches a
new token and retries once. staticHeaders are plain, non-secret headers (they cannot set
Authorization, Cookie, Host or X-SalesOS-*). A credential that needs a
secret cannot be turned on until it is set.
Where you use it
| From | How |
|---|---|
| Functions | await fetch('callout:erp/orders?status=open') or await salesos.callout('erp', '/orders', { method: 'POST', body: { id } }). The base URL is the allow-list — no allowedHosts entry needed — and the function never sees the secret. |
| Custom actions | namedCredentialId + calloutPath instead of url. The signed request goes to the base URL plus the path, with the credential's auth added. |
| Flows | The HTTP_CALLOUT element: credential, method, path and body templates, response fields into variables. |
| Webhooks | namedCredentialId on a webhook whose URL starts with the base URL: every delivery carries the credential's authentication as well as the signature. |
What SalesOS enforces
- SSRF-safe: https only; no credentials in URLs; internal hostnames and private, internal or reserved addresses are refused, checked against the address actually connected to, on every redirect.
- Stays under the base URL: a path may not be an absolute URL, start with
//, or contain.., encoded slashes or control characters, and every redirect is re-checked against the base URL's origin and path — the authentication is never sent anywhere else. - Secrets don't follow a moved credential: changing the base URL's host
(or the token URL) needs the secret entered again
(
400 CREDENTIAL_SECRET_REQUIRED), and a metadata deploy that moves it clears the secret and turns the credential off. The management API is session-only — API keys and OAuth tokens can't reach it. - Timeouts: the credential's timeout (1–10 s), capped by the caller's own deadline (a function's remaining time, a webhook's 10 s).
- Logged: every call writes a row with the source (function, action,
flow, webhook, test), method, path without the query string, status,
latency and error code — never headers, bodies or secrets. See them under
Calls on the credential, or
GET /v1/named-credentials/:id/calls(kept 30 days). - Test:
POST /v1/named-credentials/:id/test{ method, path }makes one real call and returns the status, response headers and the first 4 KB. - In use: a credential that a custom action or webhook still references
can't be deleted (
409 CREDENTIAL_IN_USE). A callout through a credential whose secret was never set fails withCREDENTIAL_SECRET_MISSING.
Metadata and apps
Credentials move between orgs as NAMED_CREDENTIAL components
(credentials/<apiName>.credential.json) with their configuration only:
secrets never move. A new credential that needs a secret arrives inactive
and the deploy result names the secret to set; an update keeps the target's
secrets and on/off state. App manifests can declare credentials under
namedCredentials (no secrets allowed): they install inactive and the
installing admin sets the secret under Connections, where the app's
credential accepts only its secrets and on/off.
Custom actions
Register your own HTTPS endpoint as a named action and call it from workflows, the assistant and record pages, with signed requests, schemas, retries and a full invocation log.
Before-save hooks
A synchronous call to your endpoint before a record is created, updated or deleted — allow it, reject it with a message, or patch it.