Pages

Showing posts with label Automatio. Show all posts
Showing posts with label Automatio. Show all posts

Saturday, July 25, 2026

Agentforce for Developers: Building Your First Custom Action with Apex


Agentforce for Developers: Building Your First Custom Action with Apex

Everyone's talking about Agentforce from the admin side — click-based agent setup, prompt templates, topics and instructions. But if you're an Apex developer, the real question is different: how do I plug my own logic into an agent so it can actually do something in my org, not just talk about it?

TL;DR: Agentforce agents don't just answer questions — they take action by calling "actions" under the hood. The fastest way to give an agent real capability is an Apex class with an @InvocableMethod. Write the method, add a couple of annotations Agentforce reads to understand what your code does, deploy it, wire it up in Agentforce Builder, and your agent can now query, update, or trigger anything Apex can reach.

Why This Matters for Developers Right Now

Admins can build a lot with Agentforce out of the box — Flow actions, prompt templates, standard actions for common objects. But the moment a business process needs custom validation, a call to an external system, or logic too complex for a Flow, the agent needs your code. That's the developer's entry point into Agentforce, and it's honestly one of the most in-demand skills in the ecosystem right now — most teams have admins who can configure an agent, but far fewer have developers who know how to extend one safely.

The good news: if you already know how to write an invocable Apex method for Flow, you're 80% of the way there. Agentforce reuses the same annotation.

How an Agent Actually Calls Your Code

It helps to think of an agent as a planner, not a black box. When a user asks it something, the agent:

  1. Reads the instructions and topics it's been configured with.
  2. Decides which action (or actions) can help complete the request.
  3. Calls that action with whatever inputs it can infer from the conversation.
  4. Reads the output and decides what to say or do next.

An "action" can be a Flow, a prompt template, a REST-exposed Apex method, or — what we're building today — an Apex class annotated with @InvocableMethod. The annotation is what makes your class show up as a selectable action inside Agentforce Builder.

What We're Building

A support agent for a fictional subscription business needs to answer: "What's the status of order 00012345?" Instead of guessing, it should call real Apex that queries the actual record. Here's the class:

public with sharing class OrderStatusAction {

    @InvocableMethod(
        label='Get Order Status'
        description='Returns the current status, expected delivery date, and total for a given order number.'
    )
    public static List<OrderStatusResult> getOrderStatus(List<OrderStatusRequest> requests) {
        List<OrderStatusResult> results = new List<OrderStatusResult>();

        for (OrderStatusRequest req : requests) {
            OrderStatusResult result = new OrderStatusResult();

            Order__c ord = [
                SELECT Status__c, Expected_Delivery__c, Total_Amount__c
                FROM Order__c
                WHERE Order_Number__c = :req.orderNumber
                WITH USER_MODE
                LIMIT 1
            ];

            result.status = ord.Status__c;
            result.expectedDelivery = ord.Expected_Delivery__c;
            result.totalAmount = ord.Total_Amount__c;
            results.add(result);
        }

        return results;
    }

    public class OrderStatusRequest {
        @InvocableVariable(label='Order Number' description='The order number the customer
is asking about, e.g. 00012345.' required=true) public String orderNumber; } public class OrderStatusResult { @InvocableVariable(label='Status' description='Current fulfillment status of the order.') public String status; @InvocableVariable(label='Expected Delivery' description='The date the order is expected to arrive.') public Date expectedDelivery; @InvocableVariable(label='Total Amount' description='The total charged for this order.') public Decimal totalAmount; } }

A few details that matter more here than in ordinary Apex:

  • The description on @InvocableMethod and every @InvocableVariable isn't a comment — it's instructions the agent reads at run time to decide when to call this action and how to fill in its inputs. Vague descriptions produce agents that call the wrong action or leave inputs blank.
  • WITH USER_MODE enforces the running user's field- and object-level security, which matters even more with an agent in the loop, since you don't want it surfacing data the requesting user couldn't normally see.
  • Keep request/response wrapper classes flat and simple. Agents reason better over a handful of clearly-labeled fields than a deeply nested structure.

Wiring the Action into Agentforce Builder

Once the class is deployed:

  1. From Setup, open Agentforce Studio (or Agent Studio, depending on your org's release) and open the agent you want to extend, then start a new version.
  2. Under Actions, choose New Action, then set the reference type to Apex and the category to Invocable Method.
  3. Select OrderStatusAction from the list — Agentforce Builder will pre-fill the action's name, description, inputs, and outputs directly from your annotations.
  4. Check Show in conversation on any output field you want the agent to surface directly in its reply (for example, status), rather than just reasoning over silently.
  5. Save, commit the version, and activate it.

Testing Before You Ship It

Don't skip this step. Agentforce Builder has a Preview / Live Test Mode pane where you can chat with the draft agent before it goes live. Ask it the exact question a real user would ask — "Where's my order 00012345?" — and confirm two things:

  • It actually selects your action instead of hallucinating an answer.
  • The output it reads back matches what your Apex actually returned.

If it doesn't call the action reliably, the fix is almost always a clearer description, not more code. Agents lean heavily on that text to route correctly.

Permission Set Gotcha

This trips up a lot of developers coming from a pure-Apex background: an agent runs with the permissions of whatever user or agent user is assigned, not with elevated access. If the Apex class, the custom object, or the specific fields in OrderStatusAction aren't granted through a permission set assigned to that user, the action will silently fail to appear as usable — even though it's deployed and wired up correctly in Builder. If your action isn't behaving, check permissions before you touch the code.

From One Action to a Real Agent Skill

A single action is a good first step, but the pattern scales:

  • Chain actions together — one action to look up the order, another to check refund eligibility, another to actually issue the refund — and let the agent sequence them based on the conversation.
  • Use External Objects with Prompt Builder to ground the agent's generated responses in live data from systems outside Salesforce, instead of custom Apex callouts for every case.
  • Log agent actions back to Data Cloud so you can monitor which actions get called, how often they succeed, and where agents get stuck — treat it like observability for a new kind of user.

The Bottom Line

If you can write an invocable Apex method for a Flow, you already have the core skill Agentforce needs from a developer. The shift isn't really technical — it's about writing your method and field descriptions for an AI reader instead of a human one, and being deliberate about what the agent is and isn't allowed to touch. Start with one well-scoped action, test it in Live Test Mode until it behaves predictably, and expand from there.

Have you built a custom Agentforce action yet? Share what it does — or where it broke — in the comments below.