Agentforce
Calling a REST API from Agentforce without Apex: External Services and OpenAPI actions
Your agent needs to hit Jira, a shipping-quote API, or an internal microservice, and every tutorial reaches for Apex or MuleSoft. If the API has an OpenAPI spec and a Named Credential can log in, you need neither. External Services turns each operation into an agent action with no code.
Your agent needs to do something that lives in another system. Pull a shipping quote. Open a Jira ticket. Check stock in a service your team wrote three years ago.
The system has a REST API, and you are staring at four ways to reach it: write an Apex action, build a Flow, publish it through MuleSoft, or stand up an MCP server. Three of those are more work than the job needs.
If that API ships an OpenAPI specification, and a Named Credential can authenticate to it, register it as an External Service. Every operation in the spec becomes an Agentforce action. No Apex class, no MuleSoft license, no server to host. You paste a schema, point it at a login, and the agent gets a set of typed actions it can call.
External Services isn’t new. It has been the declarative-integration surface for Flow for years. The part that matters here landed in Spring ‘25: an agent can invoke an External Service action directly, with no Flow or Apex wrapper in between. That closed the gap that used to push everyone toward code.
Where External Services sits among the action types
Agentforce can reach an external API several ways, and picking wrong costs you either code you didn’t need or a capability the tool can’t give. The split is about what you have and what the call has to do.
- Apex when the call needs logic the API doesn’t do for you: chaining two requests, transforming a payload, enforcing a rule before the callout. Custom Apex actions are the most powerful option and the most work.
- Flow when an admin owns the integration and it fits a declarative shape, including HTTP Callout in Flow for a single endpoint. Flow actions are the no-code default for orchestration you can draw.
- MuleSoft when the API is one of dozens your integration team already governs, and you want a curated, reused catalog. MuleSoft for Agentforce publishes an API once and lets every agent reuse it.
- MCP when the tool provider ships a Model Context Protocol server and you want the agent to discover its tools instead of registering each one.
External Services is the door most teams skip, because they never learned it existed for agents. It fits a specific, common case. You have a plain third-party or internal REST API. It publishes an OpenAPI spec. No MuleSoft is in the picture, and you don’t want to write Apex.
That covers a large share of “make the agent talk to system X” requests. When it fits, it is the least code of any option.
The build: schema in, actions out
The whole setup is three moving parts: authenticate to the service, register its spec, and add the generated actions to a topic.
Start with the Named Credential. External Services never holds a raw secret. You create a Named Credential, backed by an External Credential for the auth scheme and the token, that describes how to log in to the API. The platform then composes the URL, attaches the auth header, and handles the token on every call.
OAuth, an API key, or mutual TLS all live in the credential, out of the schema and out of any code.
Then register the spec. In Setup, open External Services, choose New, then From API Specification. Select the Named Credential and either paste the OpenAPI schema as JSON or upload the file. Salesforce validates the structure. On a clean parse it generates one invocable action per operation the spec defines.
A spec with getShippingQuote, createTicket, and getTicketStatus gives you three actions, named from the operations, with inputs and outputs typed from the schema.
Two constraints on the schema are worth knowing before you paste. The schema definition is capped at 100,000 characters, so a sprawling spec with fifty endpoints may need trimming to the operations the agent uses. And the spec has to be OpenAPI. If a vendor only publishes a Postman collection or hand-written docs, you write the OpenAPI yourself first.
Trimming is the more common problem, and it works in your favour. The fewer operations you register, the smaller the agent’s action surface, and the less room it has to call the wrong one.
The last step is to add the actions to the agent. A generated action is an action like any other. In Agentforce Builder, add it to the relevant topic, and write the instruction that tells the agent when to call it and what each input means.
That instruction decides whether the agent ever calls the action correctly, the same discipline a custom Apex action needs. The reasoning engine reads your description, not your schema comments. “Call this to get a live delivery estimate when the customer asks about shipping time; destinationZip is the customer’s postal code” earns a correct call. A bare operation name earns a guess.
Here is the shape of a minimal spec that produces one clean action. The operation summary and parameter descriptions become the metadata Agentforce reasons over.
{
"openapi": "3.0.0",
"info": { "title": "Shipping Quote Service", "version": "1.0.0" },
"paths": {
"/quote": {
"get": {
"operationId": "getShippingQuote",
"summary": "Return a live delivery estimate and price for a destination.",
"parameters": [
{
"name": "destinationZip",
"in": "query",
"required": true,
"description": "Destination postal code, five digits.",
"schema": { "type": "string" }
},
{
"name": "weightKg",
"in": "query",
"required": true,
"description": "Parcel weight in kilograms.",
"schema": { "type": "number" }
}
],
"responses": {
"200": {
"description": "A quote.",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"etaDays": { "type": "integer" },
"priceUsd": { "type": "number" }
}
}
}
}
}
}
}
}
}
}
The running-user trap that returns nothing
The failure that eats the most time is not a bad schema. The action registers, the agent calls it, and the response comes back empty or with a 401, on an API that works fine when you test the callout yourself.
The cause is almost always identity. An Agentforce action runs as the agent’s running user, not as you and not as the person chatting. That user needs access to the Named Credential and to the External Service.
If the Named Credential is per-user rather than org-wide, the running user has no stored token. The login the agent tries to make has no credential behind it, and the call fails before it leaves the platform.
The fix is a decision, not a patch. For a service where every conversation should authenticate the same way, a shipping API, an internal lookup, use a Named Credential with a named principal: one identity the org calls as, with the agent user granted access to it.
Reserve per-user credentials for the case where the call has to act as the individual employee. That only works on channels where the employee is authenticated, which rules out an anonymous web or messaging agent. Get the principal wrong and you don’t see the word “identity” anywhere. You get an empty result the agent then narrates as if the customer’s parcel doesn’t exist.
The limits that shape the design
Two numbers set the boundary of what an External Service action can be.
A synchronous External Services callout times out at 120 seconds, and the whole transaction shares a cumulative 120-second callout budget. For an agent action that is generous, since most REST calls return in well under a second.
But it rules out pointing an action at a long-running report job or a batch export that takes minutes. If the underlying work is slow, the action should start the job and return a handle, and something else polls for the result.
The response also has to fit what the reasoning engine can carry back into the conversation. A call that returns a 5,000-row array is not something the agent can read to a customer, and it wastes the token budget the whole turn runs on.
Design the API operation, or a filtered variant of it, to return the few fields the agent needs to answer. Push the filtering into the call, the way you would in a Data 360 query rather than trim in the client. If the API only offers a firehose endpoint, wrap it. That wrapper is one of the moments External Services hands the job back to Apex.
Where External Services stops and Apex starts
External Services is a thin, declarative pass-through. It authenticates, it calls, it types the payload, and it does nothing between the agent and the endpoint. The moment the job needs something in that gap, you are writing Apex, and that is the right call.
Reach for Apex when one action has to make two calls and combine them, when the response needs reshaping before the agent can use it, when you have to enforce a rule the API won’t before the callout fires, or when the endpoint is slow enough to need an async pattern.
Reach for MuleSoft when the API is one of many your integration team wants to govern and reuse across agents rather than register per-agent.
Everything short of that, a clean REST API with a spec and a login, is what External Services was built for. Reaching for code there is effort you are choosing to spend.
Start any “connect the agent to system X” request by checking two things: whether the API publishes an OpenAPI spec, and whether a Named Credential can authenticate to it. If both hold and the call is a simple in-and-out, register it as an External Service, add the actions, write the instructions, and set the running user’s principal before you write a line of Apex you didn’t need.
Understanding the basics
Can Agentforce call an external REST API without Apex?
Yes. If the API publishes an OpenAPI specification and a Named Credential can authenticate to it, you register it as an External Service in Setup, and Salesforce generates one invocable action per operation in the spec. Since Spring ‘25 an agent can call those actions directly, without a Flow or Apex wrapper. You only need Apex when a single action has to chain calls, transform a payload, enforce a pre-callout rule, or handle a long-running job asynchronously.
What is the difference between an External Service action and a MuleSoft action in Agentforce?
Both turn a REST API into agent actions from an OpenAPI spec, and both use a Named Credential for auth. External Services is the lightweight path for a single API you register yourself, with no added licensing. MuleSoft for Agentforce is the governed path when the API is one of many your integration team curates through the API Catalog and reuses across agents. Use External Services for a one-off integration, MuleSoft when API governance and reuse at scale is the point.
Why does my Agentforce External Service action return nothing or a 401?
The most common cause is the running user’s identity. An agent action runs as the agent’s assigned user, and that user needs access to both the External Service and its Named Credential. If the Named Credential is configured per-user, the running user has no stored token and the call fails authentication before it leaves Salesforce. Use a Named Credential with a named principal for a service that should authenticate the same way every time, and grant the agent user access to it.
Is there a size or time limit on External Services in Agentforce?
Two limits shape the design. The registered OpenAPI schema definition is capped at 100,000 characters, so trim a large spec to the operations the agent uses. A synchronous callout times out at 120 seconds, and the transaction shares a cumulative 120-second callout budget, so an External Service action suits fast request-response calls, not long-running jobs. Verify both against the current Agentforce Actions and External Services limits references for your release before you build on them.
Deciding whether an agent’s next capability is an External Service, an Apex action, a Flow, or a MuleSoft API, and wiring it so the running user, the credential, and the action instruction all line up? Talk to us. Getting an agent to touch the systems that run your business without a pile of code you’ll maintain forever is exactly the work we do.