Connect Salesforce
Verified against the Salesforce console, August 2026
Salesforce has no built-in Kody platform app. Every connection is
bring-your-own: you create a Connected App or External Client App in the org,
register Kody's redirect URI, then finish OAuth on /connect/oauth.
What you get
Once connected, you can ask Kody things like:
- "Run this SOQL query and summarize the results."
- "Describe the Contact sObject and list its custom fields."
- "Show the Opportunity records that closed this month."
Exact access depends on the Connected App scopes and the Salesforce user's permissions in that org.
Before you start
- You need permission in the org to create a Connected App or External Client App (typically a system administrator).
- There is one OAuth app per Salesforce org you want to call. Production and sandbox are different login hosts and different connections.
- The official helpers package is @kody/salesforce. A saved integration is credentials only; that package is the agent-facing surface.
See the OAuth guide for query parameters, confidential exchange, and reconnect behavior.
Create a Connected App or External Client App
Salesforce Setup offers both Connected Apps and External Client Apps. Either works. Enable OAuth and treat the consumer key / consumer secret as a confidential web app.
- In Salesforce Setup, open App Manager (Connected App) or External Client App Manager and create a new app with OAuth enabled.
- Set the callback / redirect URI to exactly
https://kody.codes/connect/oauth(a self-hosted deployment registers its own origin plus/connect/oauth). Matching is exact — a trailing slash orheykody.devhost fails. - Select OAuth scopes that include
api,refresh_token, andoffline_access. Add more only when a workflow needs them. - Copy the consumer key (client ID) and consumer secret (client secret). Paste
those into Kody's
/connect/oauthsetup form, not into chat.
Production orgs authorize at login.salesforce.com. Sandboxes authorize at
test.salesforce.com. Using the wrong host looks like a broken client, not a
wrong org.
Connect to Kody
Open this URL while signed in to Kody. It matches the official package's
prefilled connect link, with the production callback and connect page on
https://kody.codes/connect/oauth:
https://kody.codes/connect/oauth?provider=salesforce&authorizeUrl=https%3A%2F%2Flogin.salesforce.com%2Fservices%2Foauth2%2Fauthorize&tokenUrl=https%3A%2F%2Flogin.salesforce.com%2Fservices%2Foauth2%2Ftoken&apiBaseUrl=https%3A%2F%2Flogin.salesforce.com&scopes=api%20refresh_token%20offline_access&flow=confidential&allowedHosts=login.salesforce.com%2C*.salesforce.com%2C*.force.com%2C*.my.salesforce.comDecoded: authorize URL https://login.salesforce.com/services/oauth2/authorize,
token URL https://login.salesforce.com/services/oauth2/token, apiBaseUrl
https://login.salesforce.com, flow=confidential, scopes
api refresh_token offline_access, and allowedHosts covering the login host
plus *.salesforce.com, *.force.com, and *.my.salesforce.com so REST calls
can follow the org's instance URL.
For a sandbox, replace every login.salesforce.com with test.salesforce.com
in authorizeUrl, tokenUrl, apiBaseUrl, and allowedHosts. Use a distinct
provider name such as salesforce-sandbox so it does not overwrite the
production connection.
Paste the consumer key and secret into the setup form, then authorize as a user who can see the data the workflow needs.
More than one org
Each org is its own Kody integration. Give production, sandbox, and extra orgs
different provider values (salesforce, salesforce-sandbox,
salesforce-eu). Official package helpers take integrationName so a call
targets that connection instead of the default salesforce name.
Verify
After connecting, run the official smoke test from execute (pass
integrationName when the connection is not named salesforce):
import smokeTest from 'kody:@kody/salesforce/smoke-test'
export default async function main() {
return smokeTest()
}A successful response confirms OAuth without returning profile PII. Once that
passes, day-to-day calls go through package helpers such as ./query,
./describe-sobject, ./request, and ./triage-error.
Scopes
Space-delimited. The official connect link requests:
api— REST and SOAP API access for the authorized userrefresh_tokenandoffline_access— a refresh token so Kody can keep calling after the access token expires
Widen only when a later workflow needs extra Salesforce OAuth scopes, then
reconnect with the new scopes value. Missing refresh_token /
offline_access is the usual reason a connection works once and then cannot
refresh.
Troubleshooting
- Redirect URI mismatch: the Connected App / External Client App callback must
be exactly
https://kody.codes/connect/oauth. Do not registerheykody.dev— production callback and connect URLs are onkody.codes. - Sandbox authorize or token errors: the connect URL still points at
login.salesforce.com. Rebuild it withtest.salesforce.comand a distinct integration name. - No refresh token after a successful connect: the app is missing
refresh_tokenandoffline_access, or the user previously authorized a narrower grant. Add the scopes, revoke the old grant in Salesforce if needed, and reconnect. - API calls fail against
login.salesforce.comortest.salesforce.comafter connect: those are login hosts, not the org instance. Salesforce returns an instance URL (for example*.my.salesforce.com) from userinfo; the official package follows that URL. Keep the wildcard hosts from the connect link socreateAuthenticatedFetchcan reach the instance. invalid_client/ secret errors: confirm the consumer secret is current and thatflow=confidentialis set. Rotate the secret in Salesforce and reconnect if it was regenerated.
After you are connected, use the official @kody/salesforce package for identity, SOQL, sObject metadata, and confirmed record changes.