Agentforce Apex Actions — @InvocableMethod Guide 2026
Apex Actions —
Full Developer Power for Your Agent
Write @InvocableMethod Apex classes your agent calls directly. Complex SOQL with multiple objects, aggregate queries, and business logic that Flow can't handle. Your XYZ Sales Assistant becomes a true developer-grade AI agent.
1. What Are Apex Actions?
@InvocableMethod — the bridge between AI agent and Apex power
@InvocableMethod that agents can call directly. They give agents access to the full power of Apex: complex multi-object SOQL, aggregate queries, external callouts, business logic too complex for Flow. When Standard Actions and Flow Actions can't handle the requirement — Apex Actions can.
| Capability | Standard Actions | Flow Actions | Apex Actions |
|---|---|---|---|
| Complex SOQL (joins, aggregates) | ❌ | Limited | ✅ Full power |
| External HTTP callouts | ❌ | ❌ | ✅ Yes (callout=true) |
| Business logic complexity | ❌ | Medium | ✅ Unlimited |
| Multi-object relationships in one query | ❌ | Limited | ✅ Full SOQL |
| SOQL aggregate functions (COUNT, SUM) | ❌ | ❌ | ✅ Yes |
| Code required | None | None | Yes — Apex developer |
| Test class required | No | No | Yes — 75%+ coverage |
✅ Aggregate queries (COUNT, SUM, AVG by stage, region, industry)
✅ External HTTP callouts to ERP, payment systems, external APIs
✅ Business logic requiring loops, collections, complex conditions
✅ Any operation Flow Builder can't express cleanly
❌ Don't use for simple CRUD — use Standard Actions instead. Apex = last resort for complexity.
2. Anatomy of an Apex Action — Every Annotation Explained
Master the structure before writing your first action
2. Must accept List<YourInputClass> — even if only one record processed
3. Must return List<YourOutputClass> — always a list
4. Only one @InvocableMethod per class — one class = one agent action
5. Input/Output classes must be inner classes — not separate top-level classes
6. Always with sharing — never bypass security
3. Build Apex Action 1 — Get Account with Opportunities
Complex SOQL joining Account + child Opportunities in one query
Common error: "Variable does not exist: IsClosed" — change
IsClosed = :(!showClosed) to use a Boolean variable declared before the query.
1. Accepts accountName (required) + includeClosed (optional) from agent
2. Runs complex SOQL: Account WHERE Name LIKE '%searchTerm%' WITH child Opportunities subquery
3. WITH SECURITY_ENFORCED — respects FLS and sharing rules (security!)
4. Formats Account data into readable text with ₹ INR formatting
5. Formats each Opportunity: Name | Stage | Amount | Close Date | Probability
6. Returns fullResult (combined) + success flag + errorMessage
4. Build Apex Action 2 — Pipeline Summary
Aggregate SOQL — COUNT and SUM deals by stage
• Industry: Healthcare
• Type: Customer
• Location: Mumbai, Maharashtra, India
• Phone: +91-22-12345678
• Employees: 500
• Annual Revenue: ₹5.00 Cr
• Notes: Leading pharma manufacturer, key XYZ Company silicone customer since 2019
๐ OPEN OPPORTUNITIES (1):
▸ ABC Pharma - Silicone Tubing Q3 2026
Stage: Proposal/Price Quote | Amount: ₹25.00 L | Close: 31 Jul 2026 | Probability: 60%
Would you like me to draft a follow-up email for this opportunity?
▸ Qualification
Deals: 1 | Value: ₹3.50 L
▸ Negotiation/Review
Deals: 1 | Value: ₹18.00 L
▸ Proposal/Price Quote
Deals: 1 | Value: ₹25.00 L
๐ฐ TOTAL PIPELINE: 3 deals | ₹46.50 L
The strongest deal is the MedTech Device Seals contract at 80% probability. Would you like a deeper look at any specific stage or account?
[account details...]
๐ ALL OPPORTUNITIES (2):
▸ ABC Pharma - Silicone Tubing Q3 2026
Stage: Proposal/Price Quote | Amount: ₹25.00 L | Close: 31 Jul 2026 | Probability: 60%
▸ ABC Pharma - Gasket Supply 2025
Stage: Closed Won | Amount: ₹9.80 L | Close: 31 Dec 2025 | Probability: 100%
5. Apex Action Best Practices
Production-quality patterns every Agentforce developer must know
| Practice | Why | How |
|---|---|---|
| Always use with sharing | Agent actions run as the current user — must respect sharing rules | public with sharing class MyAction — never without sharing |
| Always use WITH SECURITY_ENFORCED | Enforces FLS in SOQL — agent can't return fields user can't see | Add WITH SECURITY_ENFORCED to every SOQL query |
| Always return an output | Agent needs something to say to the user after calling the action | Every ActionOutput must have a result/message String field |
| Wrap in try-catch | Uncaught exceptions crash the agent conversation | Wrap all logic in try-catch, set success=false + errorMessage in catch |
| Use String.escapeSingleQuotes() | Dynamic SOQL injection prevention | Always escape user-provided strings before dynamic SOQL: String.escapeSingleQuotes(inp.name) |
| LIMIT your SOQL results | Agents can't process 10,000 records — keep it concise | Add LIMIT 10 to record queries. Agents need summaries, not data dumps. |
| Format output for humans | Agent shows your output string directly to user | Format with emojis, line breaks, labels — make it readable without extra work by the agent |
| One @InvocableMethod per class | Salesforce allows only one per class | Separate classes: GetAccountAction, GetPipelineAction, CreateTaskAction — not one class with many methods |
6. Troubleshooting Apex Actions
Every error you'll hit — and the fix
| Problem | Root Cause | Fix |
|---|---|---|
| Apex Action not appearing in Agent Builder | Class has compile errors OR no @InvocableMethod OR not public | Setup → Apex Classes → check for errors. Method must be: public static, annotated @InvocableMethod, accepts List input |
| "Insufficient Privileges" error at runtime | with sharing class blocking access, OR SOQL missing WITH SECURITY_ENFORCED | Check user's FLS on queried fields. Temporarily test without WITH SECURITY_ENFORCED to isolate — then fix field permissions. |
| Agent calls action but returns blank result | Output variable not decorated with @InvocableVariable OR wrong variable name | Check all output fields have @InvocableVariable annotation. Check Agent Builder Action configuration shows the output field. |
| SOQL injection vulnerability warning | User input directly concatenated into dynamic SOQL | Always wrap user input: String.escapeSingleQuotes(userInput) before using in dynamic SOQL strings. |
| Test class fails with "Attempt to de-reference a null object" | Test data not created properly or queried incorrectly | Add null checks in Apex: if(accounts != null && !accounts.isEmpty()). Verify @TestSetup data is inserting correctly. |
| callout=false but method makes HTTP callout | Apex restriction — callouts not allowed without callout=true | Change annotation: @InvocableMethod(label='...' callout=true) |
7. Apex Actions — Interview Questions
Most asked questions about Apex Actions in Agentforce interviews
| Interview Question | Best Answer |
|---|---|
| What annotation makes an Apex method callable by an Agentforce agent? | @InvocableMethod(label='...' description='...' callout=true/false). Method must be public static, accept List<InputClass>, return List<OutputClass>. Inner class variables must have @InvocableVariable annotation. |
| How does the AI decide which Apex Action to call? | It reads the description parameter of @InvocableMethod — just like Topic Classification Descriptions. Write it clearly: "Use when user asks about X, Y, Z." The description is what the AI uses for action selection. |
| What is the structure of an @InvocableMethod? | One public static method accepting List<InputClass>, returning List<OutputClass>. Two inner classes (Input + Output) with @InvocableVariable on each field. required=true for mandatory inputs. Always with sharing, always try-catch, always return formatted output. |
| Why must @InvocableMethod accept and return Lists? | Because Flows and agents can call @InvocableMethod in bulk — processing multiple records in one call. Even if only one record processed, the List contract must be maintained. Salesforce enforces this for bulkification consistency. |
| How do you make Apex Actions secure for Agentforce? | with sharing class (enforces sharing rules), WITH SECURITY_ENFORCED in SOQL (enforces FLS), try-catch (prevents crashes), String.escapeSingleQuotes() for dynamic SOQL (prevents injection). All four are mandatory for production agents. |
Module 9 Summary
Developer-grade AI agent — Apex powering complex queries!
- ✅@InvocableMethod anatomy — label, description, callout, @InvocableVariable, required=true, with sharing
- ✅Golden Rules — public static, List input/output, one per class, with sharing, try-catch, WITH SECURITY_ENFORCED
- ✅Apex Action 1 — GetAccountWithOpportunities: complex SOQL joining Account + child Opportunities, INR formatting
- ✅Apex Action 2 — GetPipelineSummary: aggregate SOQL (COUNT + SUM GROUP BY StageName)
- ✅Test Classes Written — 6 test methods, 85%+ coverage, all passing
- ✅Both Actions Connected — to Sales Assistant Topic with clear descriptions for AI selection
- ✅Live Tested — 3 conversations with complex SOQL results returned from real Dev Org data
- ✅8 Best Practices — with sharing, SECURITY_ENFORCED, LIMIT, escapeSingleQuotes, formatted output
✅ Aggregate pipeline summaries (COUNT/SUM) | ✅ Generate AI emails | ✅ Summarize records
✅ Create follow-up Tasks | ✅ Update Opportunity stages
Module 10 adds the final action type — API Actions for calling external systems like Business Central ERP. Then Modules 11-15 cover Data Cloud, deployment, escalation, testing, and the full project!
๐ Ready for Module 10?
Next: API Actions — Call external REST APIs directly from your agent. Connect XYZ Sales Assistant to Business Central ERP to get live order status, inventory levels, and invoice data — all in conversation. Your agent bridges Salesforce and your entire enterprise system!
Module 10: API Actions →