Connectors
/
Salesforce
Live · 37 tools

Salesforce Integration for AI Agents

The Salesforce API is documented. Connecting your agent to it correctly — for real users, at scale — is the part that takes weeks.
Salesforce
Live

CRM

Sales Automation

Status
Live
Tools
37 pre-built
Auth
OAuth 2.0
Credential storage
Sandbox support

OAuth 2.0

Auto token refresh

Revocation detection

The real problem

Why this is harder than it looks

Most teams underestimate what "Salesforce OAuth" actually requires. The authorization flow itself is straightforward. The problems start after the user approves your app.

In production, each of your customers' employees connects their own Salesforce org — and orgs are not interchangeable. Access tokens are short-lived and org-scoped; your refresh logic has to run proactively before a call fails, and the token endpoint itself differs between sandbox and production environments. A token minted against login.salesforce.com won't work against test.salesforce.com, and the base URL for API calls is different again — it's the org's My Domain URL, which is unique per org. None of this is in the OAuth spec; it's Salesforce-specific behavior your code has to detect and handle per-user, not globally.

Then there's revocation. If a rep disconnects your Connected App from their Salesforce settings, or an admin resets OAuth tokens org-wide, your agent will start receiving 401s with no clear signal about which user is affected. Without explicit revocation detection, you end up making unauthorized calls or showing broken state. And if your Connected App has IP restrictions configured — common in enterprise orgs — tokens will fail silently for users outside those ranges, which looks identical to a revocation event.

Finally, if you're building a product rather than an internal tool, the consent screen should show your app name. That requires registering your own Salesforce Connected App, managing its credentials, and keeping them out of your application code. And once you've done all of this for Salesforce, you do it again for every other connector your customers ask for.

Scalekit is the infrastructure layer that handles all of it. Your agent names a tool and passes parameters. Scalekit takes care of which token to use, whether it's still valid, and what to do if it isn't.

Capabilities

What your agent can do with Salesforce

Once connected, your agent has 37 pre-built tools covering the full Salesforce object model — including data, analytics, and metadata:

  • Query anything with SOQL: filtered lists, aggregations, cross-object joins, custom fields, two distinct execution endpoints
  • Create and update pipeline records: accounts, opportunities, contacts as deals move through stages
  • Full-text search with SOSL: across multiple Salesforce objects simultaneously
  • Atomic batch operations: create a Contact and link an Opportunity in one round trip via the Composite API
  • Dashboard and report management: get live data, clone dashboards, create and update reports via the Analytics API
  • Tooling API access: query and manage Apex classes, triggers, custom objects, and other org metadata directly
  • Schema introspection at runtime: describe any SObject, check org API limits, read report structure
Setup context

What we're building

This guide connects a sales assistant agent to Salesforce — helping reps query accounts, surface open opportunities, and create records without leaving your product.

🤖
Example agent
Sales assistant managing pipeline on behalf of each rep
🔐
Auth model
B2B SaaS — each rep connects their own org. identifier = your user ID
⚙️
Scalekit account
app.scalekit.com — Client ID, Secret, Env URL
🐍
Runtime
Python 3.8+ · Node.js also available
Setup

1 Setup: One SDK, One credential

Install the Scalekit SDK. The only credential your application manages is the Scalekit API key — no Salesforce secrets, no user tokens, nothing belonging to your customers.

pip install scalekit-sdk-python
import scalekit.client import os from dotenv import load_dotenv load_dotenv() scalekit = scalekit.client.ScalekitClient( client_id=os.getenv("SCALEKIT_CLIENT_ID"), client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"), env_url=os.getenv("SCALEKIT_ENV_URL"), ) actions = scalekit.actions
Already have credentials?
Connected Accounts

2 Per-User Auth: Creating connected accounts

Each rep gets their own Connected Account, giving them a dedicated auth context. The identifier is any unique string from your system — a UUID, email, whatever you use internally.

response = actions.get_or_create_connected_account( connection_name="salesforce", identifier="user_sfdc_123" # your internal user ID ) connected_account = response.connected_account print(f"Status: {connected_account.status}") # Status: PENDING — user hasn't authorized yet

This call is idempotent — safe to call on every session start. Returns the existing account if one already exists.

Authorization Flow

3 The authorization flow

The rep authorizes your agent once. Scalekit generates the OAuth URL with correct scopes, PKCE challenge, and redirect handling pre-configured. After approval, you never see the token.

if connected_account.status != "ACTIVE": link = actions.get_authorization_link( connection_name="salesforce", identifier="user_sfdc_123" ) # Redirect user → Salesforce consent screen # Scalekit captures the token on callback return redirect(link.link)
Token management is automatic
After the user approves, Scalekit stores encrypted tokens and the connected account moves to ACTIVE. Access tokens refresh 5 minutes before expiry. If a rep revokes access in Salesforce, the account moves to REVOKED — no silent failures. Check account.status before critical operations.
Enterprise branding: Bring Your Own Credentials
For deployments where users should see your app name on the consent screen, register your own Salesforce Connected App credentials in the Scalekit dashboard. Token management stays fully handled.
Calling Salesforce

4 Calling Salesforce: What your agent writes

With the connected account active, your agent calls Salesforce actions using execute_tool. Name the tool, pass parameters. Scalekit handles token retrieval, request construction, and response parsing.

Fetch account details

Look up a specific account by ID. The fields parameter controls which Salesforce fields come back.

result = actions.execute_tool( identifier="user_sfdc_123", tool_name="salesforce_account_get", tool_input={ "account_id": "0015j00000AbCdEf", "fields": "Id,Name,Type,AnnualRevenue" } ) # { "Id": "...", "Name": "Acme Corp", "AnnualRevenue": 4500000 }

Query with SOQL

For filtered lists, aggregations, or cross-object joins — the agent passes the SOQL string directly.

result = actions.execute_tool( identifier="user_sfdc_123", tool_name="salesforce_query_soql", tool_input={ "query": """ SELECT Id, Name, Amount, StageName, CloseDate FROM Opportunity WHERE AccountId = '0015j00000AbCdEf' AND IsClosed = false ORDER BY Amount DESC """ } )

Create an opportunity

StageName and CloseDate are required. All other standard fields are optional.

result = actions.execute_tool( identifier="user_sfdc_123", tool_name="salesforce_opportunity_create", tool_input={ "Name": "Acme Corp — Enterprise Renewal 2026", "AccountId": "0015j00000AbCdEf", "StageName": "Proposal/Price Quote", "CloseDate": "2026-06-30", "Amount": 450000 } )

Atomic batch with the Composite API

Create a Contact and link an Opportunity in one request. If the Contact creation fails, the Opportunity is never created — one token, one HTTP call.

result = actions.execute_tool( identifier="user_sfdc_123", tool_name="salesforce_composite", tool_input={ "composite_request": { "compositeRequest": [ { "method": "POST", "url": "/services/data/v59.0/sobjects/Contact", "referenceId": "newContact", "body": { "FirstName": "Jane", "LastName": "Smith", "AccountId": "0015j00000AbCdEf" } }, { "method": "POST", "url": "/services/data/v59.0/sobjects/Opportunity", "referenceId": "newOpportunity", "body": { "Name": "Acme Corp — Enterprise 2026", "ContactId": "@{newContact.id}", "StageName": "Proposal/Price Quote", "CloseDate": "2026-06-30" } } ] } } )

Query org metadata via the Tooling API

Use salesforce_tooling_query_execute to query metadata objects like Apex classes and custom objects — not accessible via standard SOQL.

result = actions.execute_tool( identifier="user_sfdc_123", tool_name="salesforce_tooling_query_execute", tool_input={ "soql_query": """ SELECT Id, Name, Status, LastModifiedDate FROM ApexClass WHERE Status = 'Active' ORDER BY LastModifiedDate DESC LIMIT 20 """ } ) # Returns active Apex classes — not available via salesforce_query_soql
Framework wiring

5 Wiring into your agent framework

Scalekit's Salesforce tools load directly into LangChain. The agent decides which tools to call; Scalekit handles auth on every invocation. No token plumbing in your agent logic.

from langchain_anthropic import ChatAnthropic from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from scalekit.langchain import get_tools sf_tools = get_tools( connection_name="salesforce", identifier="user_sfdc_123" ) prompt = ChatPromptTemplate.from_messages([ ("system", "You are a CRM assistant. Use the available tools to help manage Salesforce data."), MessagesPlaceholder("chat_history", optional=True), ("human", "{input}"), MessagesPlaceholder("agent_scratchpad"), ]) agent = create_tool_calling_agent(ChatAnthropic(model="claude-sonnet-4-6"), sf_tools, prompt) result = AgentExecutor(agent=agent, tools=sf_tools).invoke({ "input": "Find all open opportunities for Acme Corp and summarize the pipeline" })
Other frameworks supported
Tool reference

All 37 Salesforce tools

Grouped by object and capability. Your agent calls tools by name — no API wrappers to write.

Accounts
salesforce_account_create
Create a new account with billing address, industry, revenue, and company metadata
salesforce_account_get
Retrieve a specific account by ID with field selection
salesforce_account_update
Update any account field — name, ownership, billing info, classification
salesforce_account_delete
Permanently delete an account record by ID
salesforce_accounts_list
List accounts with pagination using a pre-built SOQL query
Opportunities
salesforce_opportunity_create
Create an opportunity with stage, amount, close date, and account association
salesforce_opportunity_get
Retrieve a specific opportunity by ID with field selection
salesforce_opportunity_update
Update stage, amount, close date, or any other opportunity field
salesforce_opportunities_list
List opportunities with pagination
Contacts
salesforce_contact_create
Create a contact with name, email, phone, job title, and account association
salesforce_contact_get
Retrieve a specific contact by ID with field selection
Queries & Search
salesforce_query_soql
Execute any SOQL query — filters, joins, aggregations, custom fields
salesforce_soql_execute
Alternative SOQL execution endpoint for custom query patterns
salesforce_search_sosl
Full-text search across multiple Salesforce objects simultaneously
salesforce_search_parameterized
Simplified search with predefined parameters — object type, fields, search text
Generic SObject Operations
salesforce_sobject_create
Create a record for any SObject type — standard or custom objects
salesforce_sobject_get
Retrieve any SObject record by ID and type
salesforce_sobject_update
Update any SObject record. Only the fields provided are changed
salesforce_sobject_delete
Permanently delete any SObject record by ID
Dashboards
salesforce_dashboard_get
Retrieve live dashboard data and component results from all underlying reports. Supports up to three filter values
salesforce_dashboard_metadata_get
Retrieve metadata for a dashboard including components, filters, layout, and running user
salesforce_dashboard_clone
Clone an existing dashboard into the same or a different folder
salesforce_dashboard_update
Save sticky filter selections on a dashboard
Reports
salesforce_report_metadata_get
Retrieve structure, fields, groupings, and configuration for a specific report
salesforce_report_create
Create a new report via the Analytics API — specify type, filters, columns, groupings, and chart config
salesforce_report_update
Update an existing report's definition — name, filters, columns, and groupings
salesforce_report_delete
Permanently delete a report by ID
Batch & Schema
salesforce_composite
Execute multiple Salesforce API calls atomically in one request. Cross-request references supported
salesforce_global_describe
List all available SObjects in the org with basic metadata
salesforce_object_describe
Retrieve full field and relationship metadata for any SObject at runtime
salesforce_limits_get
Get org-level API usage limits so agents stay within safe boundaries
Tooling API
salesforce_tooling_query_execute
Execute SOQL queries against the Tooling API — accesses metadata objects like ApexClass, ApexTrigger, and CustomObject not available via standard SOQL
salesforce_tooling_sobject_describe
Retrieve field and relationship metadata for a specific Tooling API object type
salesforce_tooling_sobject_get
Retrieve a metadata record from any Tooling API object type by ID
salesforce_tooling_sobject_create
Create a metadata record — supports nested structures for complex types like CustomField
salesforce_tooling_sobject_update
Update an existing metadata record. Only fields provided are changed
salesforce_tooling_sobject_delete
Permanently delete a metadata record from the Tooling API by ID
Connector notes

Salesforce-specific behavior

Sandbox vs. production — handled automatically
Salesforce sandbox orgs use test.salesforce.com for OAuth and a distinct My Domain URL for API calls. Scalekit detects which environment the user authorizes through and routes all subsequent API calls to the correct base URL automatically. No code changes needed on your end.
Connected App IP restrictions cause silent 401s
If your Salesforce Connected App has IP range restrictions configured, tokens may fail silently for users outside those ranges. This is a Salesforce org configuration issue, not a Scalekit issue. If you see unexplained 401s after successful authorization, check the Connected App's IP restriction settings in Salesforce Setup before debugging elsewhere.
Tooling API vs. standard SOQL
The Tooling API exposes metadata objects — ApexClass, ApexTrigger, CustomObject, CustomField, and others — that are not queryable via salesforce_query_soql. Use salesforce_tooling_query_execute and the salesforce_tooling_sobject_* tools for anything in the metadata layer. Both groups share the same connected account; no additional authorization is needed.
Infrastructure decision

Why not build this yourself

The Salesforce OAuth flow is documented. Token storage isn't technically hard. But here's what you're actually signing up for:

PROBLEM 01
Org-specific token endpoints and sandbox vs. production URL handling that varies per user — not a global config
PROBLEM 02
Refresh token rotation behavior that differs by Connected App config — silent failures if handled wrong
PROBLEM 03
Revocation detection and graceful handling when users disconnect from Salesforce org settings or admins reset tokens
PROBLEM 04
Scoped, zero-trust credential architecture — your app stores zero Salesforce credentials by design

That's one connector. Your agent product will eventually need Slack, Gmail, HubSpot, Notion, and whatever else your customers ask for. Each has its own OAuth quirks and failure modes.

Scalekit maintains every connector. You maintain none of them.

Ready to ship

Connect your agent to Salesforce in minutes

Free to start. Token management fully handled.
Salesforce
Live

CRM

Sales Automation

Status
Live
Tools
37 pre-built
Auth
OAuth 2.0
Credential storage
Sandbox support