You are here:
Create a Custom Agent Action
Create a reusable action, and then assign that action to the agent in the Archive app.
Before you configure the action in the Agent Builder, create the Apex class that contains the invocable method. This class handles the logic for querying the archived records. For more information, see Create an Apex Class
For example, create an Apex class named
ArchiveDataQueryActionWrapper.
public with sharing class ArchiveDataQueryActionWrapper {
public class SearchRequest {
@InvocableVariable(label='Object Name' description='Name of the object to search in, can be implicit or explicit' required=true)
public String objectName;
@InvocableVariable(label='Filters' description='List of field/value pairs for filtering (JSON string). Supports two formats: 1) Legacy: [{"field":"Status","value":"New"},{"field":"Status","value":"Closed"}] 2) New: {"Status":["New","Closed"]}' required=true)
public String filtersJson;
@InvocableVariable(label='Max Results' description='Maximum number of results to return')
public Integer maxResults = 100;
@InvocableVariable(label='Date Field' description='Date field name for date range filtering (optional)')
public String dateField;
@InvocableVariable(label='Start Date' description='Start date for filtering (yyyy-MM-dd format, optional, if exist must have enddate and datefield)')
public String startDate;
@InvocableVariable(label='End Date' description='End date for filtering (yyyy-MM-dd format, optional, if exist must have startdate and datefield)')
public String endDate;
}
public class SearchResponse {
@InvocableVariable(label='Success' description='Whether the search was successful')
public Boolean isSuccess;
@InvocableVariable(label='Total Count' description='Total number of matching records')
public Integer totalResultCount;
@InvocableVariable(label='Records JSON' description='JSON string of matching records')
public String recordsJson;
@InvocableVariable(label='Formatted Result' description='Formatted records in rich text with 5 key fields per record')
public String records;
@InvocableVariable(label='Error Message' description='Error message if search failed')
public String errorMessage;
@InvocableVariable(label='Message' description='Status message')
public String message;
@InvocableVariable(label='Warnings' description='Warning messages about schema validation and auto-fixes')
public String warnings;
public SearchResponse() {
this.isSuccess = false;
this.totalResultCount = 0;
this.recordsJson = '[]';
this.records = '';
this.errorMessage = '';
this.message = '';
this.warnings = '';
}
}
@InvocableMethod(
label='Search Archived Records'
description='Search archived records and return structured results for Agentforce agents.'
category='Data Management'
)
public static List<SearchResponse> searchArchivedRecords(List<SearchRequest> requests) {
List<SearchResponse> results = new List<SearchResponse>();
for (SearchRequest req : requests) {
SearchResponse res = new SearchResponse();
try {
Http http = new Http();
HttpRequest httpReq = new HttpRequest();
httpReq.setMethod('POST');
httpReq.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
httpReq.setHeader('Content-Type', 'application/json');
httpReq.setEndpoint(URL.getOrgDomainUrl().toExternalForm() +
'/services/data/v65.0/platform/data-resilience/archive/search/agentforce');
Map<String, Object> body = new Map<String, Object>{
'objectName' => req.objectName,
'filtersJson' => req.filtersJson,
'maxResults' => req.maxResults
};
if (String.isNotBlank(req.dateField) &&
String.isNotBlank(req.startDate) &&
String.isNotBlank(req.endDate)) {
body.put('dateField', req.dateField);
body.put('startDate', req.startDate);
body.put('endDate', req.endDate);
}
httpReq.setBody(JSON.serialize(body));
HttpResponse httpRes = http.send(httpReq);
Integer statusCode = httpRes.getStatusCode();
if (statusCode == 200 || statusCode == 201) {
Map<String, Object> responseMap = (Map<String, Object>) JSON.deserializeUntyped(httpRes.getBody());
res.isSuccess = Boolean.valueOf(responseMap.get('isSuccess'));
res.totalResultCount = Integer.valueOf(responseMap.get('totalResultCount'));
res.recordsJson = String.valueOf(responseMap.get('recordsJson'));
res.records = String.valueOf(responseMap.get('records'));
res.message = String.valueOf(responseMap.get('message'));
res.warnings = String.valueOf(responseMap.get('warnings'));
res.errorMessage = String.valueOf(responseMap.get('errorMessage'));
} else {
res.errorMessage = 'HTTP ' + statusCode + ': ' + httpRes.getBody();
}
} catch (Exception e) {
res.errorMessage = 'Exception: ' + e.getMessage();
}
results.add(res);
}
return results;
}
}Configure the Custom Agent Action
When the Apex class is deployed, create the agent action in the Salesforce setup.
Prerequisites:
- You have Salesforce Admin permissions with access to Agent configuration.
- Turn on Agentforce in your org.
- From Setup, in the Quick Find box, enter Agent.
- To view all the actions in your org, select Agent Actions.
- Click New Agent Action.
- From Reference Action Type, select Apex.
- From Reference Action Category, select Invocable Method.
-
From Reference Action, select Search Archived
Records.
Search Archived Records references the method in the
ArchiveDataQueryActionWrapperApex class that you created earlier. - The agent action label and API name are populated with the reference action name and API name. Review these fields and, if necessary, edit the values so that they accurately describe the action.
- Click Next.
-
The instructions for the custom action and each input and output are
populated with the descriptions from the reference action. Review these
fields and make changes. For more information, see Best Practices for Agent Action
Instructions.
The descriptions from the reference action are copied over to give you a head start, but agent action instructions differ from traditional descriptions. An agent uses a large language model (LLM) and the reasoning engine to determine when to start topics and actions in a conversation. The instructions for the action, the inputs, and the outputs tell an agent what your action does and when and how to use it. Effective instructions vary by action and use case. Plan to test and iterate on your instructions to make sure that your action performs as expected.
-
For each input and output, specify any applicable settings.
Setting Details Collect data from user Require this parameter to be provided by the user. Filter from copilot action When you create an agent action, all inputs and outputs from the reference action are added to the agent action. Activate this setting when you don't want to use a parameter from the reference action with your agent action. At least one output is required to use the agent action. Require input Require this parameter to run the action. All other inputs are treated as optional. If an input is required by the reference action, this setting turns on by default and is read-only. Show in conversation An agent can include this parameter in a response to a user. At least one output is required. Tip When an action changes a record, you can require an agent to ask the user to confirm the change before the agent runs it. On the record page for the action, activate the Require user confirmation setting.If you're using the Agentforce Agent, deselect Show in Conversation under Output.
To add the action to a standard topic, edit the topic configuration from the Topic Configuration tab.
- Click Finish.
After you create your action, assign the action to a topic for your agent.
To test your action and preview how the output appears in an agent conversation, open the agent in the Agent Builder and start a preview conversation. Enter phrases that you expect to trigger your action, and then adjust the agent action and topic instructions based on your results. Assign your action to an agent to test it.
Add a Custom Agent Action to a Topic
To add an agent action to a topic:
- From the Agents Setup page, open your agent in the Agent Builder.
- If active, turn off your agent.
- Select Topics.
- Click the name of the topic that you want to add an action to.
-
Go to This Topic's Actions.
If you're using the General CRM agent topic, select it.
- Click New.
-
Select any actions that you want to add to your agent from the actions
library, or create a custom agent action.
After you select any actions that you want to add to your agent from the actions library, activate and test your agent.
- Click Finish.
The actions you've added are assigned to your agent and are visible on the Topics panel of the Agent Builder. To test your topic with your newly assigned actions, restart the preview conversation to apply your changes.
Remove a Custom Archive Agent Action from a Topic
To remove an agent action from your topic:
- From the Topics panel of the Agent Builder, click the name of the topic you want to remove an agent action from.
- Go to This Topic's Actions.
- From the dropdown list next to the action, select Remove from Topic.
Missing Archive Agent Permissions
Archive permissions work similarly to Archive Widget Restriction Rules. Record-level access is enforced only if the object has been added to the Widget Restriction Rules within Archive Settings. If no objects are added to the restriction rules, users have public access to all archived records of that type.
For example, if no Case rules are set, a user who can't originally access a specific case can see it after it's archived. Permissions are based on the sharing settings at the moment of archival. Any changes to Sharing Rules after the record is archived aren't applied.

