# Add agent actions

Source: https://support.storeconnect.com/articles/add-agent-actions · Last modified 21 August 2026

:::note
This topic relates to using AI agents to service your customers, not how to [use agents for building on StoreConnect](use-ai-agents-with-storeconnect).
:::

Actions translate an end user’s request into real agent action that updates your Salesforce CRM. For example, we can configure an action called **available\_products** that authorizes the agent to get the latest information about available products from Salesforce, and display them to the user.

There are multiple ways to add agent actions: from the Agentforce Toolkit, using Flow, or via Apex code.

## Add agent actions using Apex

In the procedure below, we will add an action using Apex. 

### Add an Apex class

1.  Create a new Apex class called AFPurchasableProducts. 

2.  Use your own code or copy and paste the sample code below.  


### Sample code

```
public class AFPurchasableProducts {

    public AFPurchasableProducts() {}

    // ==========
    // Input Variables
    // ==========
    public class Input {
        @InvocableVariable(
            label='Store Id'
            description='s_c__Store__c record Id to evaluate products for'
            required=true
        )
        public Id storeId;

        @InvocableVariable(
            label='Action Type'
            description='Action to perform: add (add to cart) or buy (go to checkout). Default is buy.'
        )
        public String type;

        @InvocableVariable(
            label='Preserve Cart'
            description='If true, preserves the existing cart contents when adding/buying.'
        )
        public Boolean preserve;

        @InvocableVariable(
            label='Return Behavior'
            description='Redirect behavior after action: true (referrer), false (stay on site), or a callback URL.'
        )
        public String ret;

        @InvocableVariable(
            label='Promotion Code'
            description='Promotion code (case-sensitive) applied to the action.'
        )
        public String code;
    }

    // ==========
    // Rich Link Item
    // ==========
    public class ProductRichLink {
        public String linkURL;
        public String linkTitle;
        public String linkImageURL;
        public String linkImageMimeType;
        public String linkDescriptionText;
    }

    // ==========
    // Rich Link Response Wrapper
    // ==========
    public class ProductRichLinkResponse {

        @InvocableVariable(
            label='Purchasable Product Details'
            required=true
        )
        public List productDetails;

        public ProductRichLinkResponse() {
            this.productDetails = new List();
        }
    }

    // ==========
    // Invocable Method
    // ==========
    @InvocableMethod(
        label='Quick: Get Purchasable Products as Rich Links'
        description='Given a store Id, returns, for each input, rich link details (URL, title, image URL, MIME type, description) for purchasable products.'
    )
    public static List execute(List inputs) {
        List responses = new List();

        if (inputs == null || inputs.isEmpty()) {
            return responses;
        }

        Set storeIds = new Set();
        for (Input i : inputs) {
            if (i != null && i.storeId != null) {
                storeIds.add(i.storeId);
            }
        }

        Map storesById = new Map(
            [
                SELECT Id,
                       s_c__Link__c,
                       s_c__Logo_Id__r.s_c__Url__c
                FROM s_c__Store__c
                WHERE Id IN :storeIds
            ]
        );

        // ---- Load all active Products ----
        List activeProducts = [
            SELECT Id,
                   Name,
                   ProductCode,
                   IsActive,
                   s_c__Features_Markdown__c,
                   s_c__Subscription_Term__c,
                   s_c__Subscription_Term_Count__c,
                   s_c__Subscription_Term_Unit__c,
                   s_c__Subscription_Type__c
            FROM Product2
            WHERE IsActive = true
        ];

        Set activeProductIds = new Set();
        for (Product2 p : activeProducts) {
            activeProductIds.add(p.Id);
        }
        Map productById = new Map(activeProducts);

        // ---- Product Media: first s_c__Product_Media__c per product (by position) ----
        Map mediaUrlByProductId = new Map();

        if (!activeProductIds.isEmpty()) {
            for (s_c__Product_Media__c pm : [
                SELECT s_c__Product_Id__c,
                       s_c__Media_Id__r.s_c__Url__c,
                       s_c__Position__c
                FROM s_c__Product_Media__c
                WHERE s_c__Product_Id__c IN :activeProductIds
                ORDER BY s_c__Product_Id__c, s_c__Position__c ASC
            ]) {
                Id pid = pm.s_c__Product_Id__c;
                // First row per product (lowest position) wins
                if (!mediaUrlByProductId.containsKey(pid)) {
                    mediaUrlByProductId.put(pid, pm.s_c__Media_Id__r.s_c__Url__c);
                }
            }
        }

        for (Input i : inputs) {
            ProductRichLinkResponse response = new ProductRichLinkResponse();
            responses.add(response);

            if (i == null || i.storeId == null) {
                continue;
            }

            s_c__Store__c store = storesById.get(i.storeId);
            if (store == null) {
                continue;
            }

            String baseLink = store.s_c__Link__c;
            String storeFallbackImageUrl = (store.s_c__Logo_Id__r != null)
                ? store.s_c__Logo_Id__r.s_c__Url__c
                : null;

            List reqs =
                new List();

            s_c.AFGetPurchasableProductIdsInvocable.Request req =
                new s_c.AFGetPurchasableProductIdsInvocable.Request();

            req.productIds = new List(activeProductIds);
            req.storeId = i.storeId;
            reqs.add(req);

            List purchResults;

            try {
                purchResults = s_c.AFGetPurchasableProductIdsInvocable.getPurchasableProductIds(reqs);
            } catch (Exception e) {
                continue;
            }

            if (purchResults == null || purchResults.isEmpty()) {
                continue;
            }

            s_c.AFGetPurchasableProductIdsInvocable.Result first = purchResults[0];
            if (first.error != null) {
                continue;
            }

            Set purchIds = new Set();
            if (first.productIds != null) {
                purchIds.addAll(first.productIds);
            }

            for (Id pid : purchIds) {
                Product2 p = productById.get(pid);
                if (p == null) {
                    continue;
                }

                ProductRichLink link = new ProductRichLink();

                link.linkURL = buildDirectToCartUrl(
                    baseLink,
                    p.ProductCode,
                    i.type,
                    i.preserve,
                    i.ret,
                    i.code
                );

                link.linkTitle = p.Name;

                String imageUrl = mediaUrlByProductId.get(p.Id);
                if (String.isBlank(imageUrl)) {
                    imageUrl = storeFallbackImageUrl;
                }
                link.linkImageURL = imageUrl;

                if (!String.isBlank(imageUrl)) {
                    link.linkImageMimeType = 'image/png';
                }

                if (!String.isBlank(p.s_c__Features_Markdown__c)) {
                    link.linkDescriptionText = p.s_c__Features_Markdown__c;
                } else {
                    link.linkDescriptionText = p.Name;
                }

                response.productDetails.add(link);
            }

        }

        return responses;
    }

    // ==========
    // Helper: build cart URL
    // ==========
    @TestVisible
    private static String buildDirectToCartUrl(
        String baseLink,
        String productCode,
        String typeParam,
        Boolean preserveParam,
        String returnParam,
        String codeParam
    ) {
        if (String.isBlank(baseLink) || String.isBlank(productCode)) {
            return null;
        }

        String normalizedBase = baseLink.endsWith('/')
            ? baseLink.removeEnd('/')
            : baseLink;

        String path = normalizedBase + '/cart/' +
            EncodingUtil.urlEncode(productCode, 'UTF-8');

        List params = new List();

        String finalType = String.isBlank(typeParam) ? 'buy' : typeParam.toLowerCase();
        if (finalType != 'buy' && finalType != 'add') {
            finalType = 'buy';
        }
        params.add('type=' + EncodingUtil.urlEncode(finalType, 'UTF-8'));

        if (preserveParam != null) {
            params.add('preserve=' + String.valueOf(preserveParam));
        }

        if (!String.isBlank(returnParam)) {
            // Allowed: "true", "false", or callback URL
            params.add('return=' + EncodingUtil.urlEncode(returnParam, 'UTF-8'));
        }

        if (!String.isBlank(codeParam)) {
            params.add('code=' + EncodingUtil.urlEncode(codeParam, 'UTF-8'));
        }

        return path + (params.isEmpty() ? '' : '?' + String.join(params, '&'));
    }
}
```


### Add an action to a topic

1.  Open a topic, for example, the **Sales Representative** topic from the previous procedure.

2.  Go to the **This Topic’s Actions** tab.

3.  Select **New** and then **+Create New Action**.

    ![Add action to topic](https://res.cloudinary.com/hzkr6fi81/image/upload/v1765236274/knowledge/AgentforceAI/Set_up_agent_actions_1-create-new-action_yk3nuw.png)

4.  Select the **Action Reference Type** as **Apex**. 

5.  Set the **Reference Action Category** to **Invocable Method** and then select your reference action. If you used our example, this would be **Quick: Get Purchasable Products for Store**.

6.  Change the Agent API name from the auto generated value to available\_products. 

7.  Select **Next**.


### Configure the action

1.  On the **Configure your action for Agent** screen, instruct the agent on how to use the action. Provide instructions and validations on each input and output.

    ![Actions details screen](https://res.cloudinary.com/hzkr6fi81/image/upload/v1765236276/knowledge/AgentforceAI/Set_up_agent_actions_2-configure-action-for-agent_d9gxlm.png)

2.  For inputs:

    1.  To require customer input, select the **Require input** option. 

    2.  Check the **Collect data from the user** option. 

    3.  In the **Loading Text** field, add a placeholder message for when the agent is thinking, for example **Searching Catalog…**

3.  For outputs:

    1.  Where you want the agent to ignore an output, select the **Filter from agent action** option. 

    2.  If you want to expose the result to the user, select the **Show in Conversation** option.

    3.  Enter instructions, such as **The list of purchasable products found for this store**. 

    4.  Select **Next**.


### Add a storeid as a custom variable

1.  In the action record, go to the **StoreId input** variable. 

2.  Select **Assign a Variable**.

3.  Set the storeId custom variable and save it.

4.  Refresh your page to go back to the Agentforce Builder home.

---

## Follow StoreConnect

- [Email Newsletter](https://getstoreconnect.com/c/lp-newsletter)
- [LinkedIn Newsletter](https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7444956928444862464)
- [YouTube](https://www.youtube.com/channel/UCngKdP2x8l1wcbAKW3tvU8g)
- [LinkedIn](https://www.linkedin.com/company/storeconnect)
- [X / Twitter](https://x.com/storeconnecthq)

## Popular Links

- [Partners](https://getstoreconnect.com/partners)
- [News](https://getstoreconnect.com/articles/news)
- [Events](https://getstoreconnect.com/articles/events)
- [Feature Comparison](https://getstoreconnect.com/how-we-compare)
- [Download a free trial](https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FMkeKUAT)
- [Book a Demo](https://getstoreconnect.com/contact)

## Documentation

- [Help documentation](https://support.storeconnect.com/help-documentation)
- [AI agents](https://support.storeconnect.com/ai)
- [Videos & tutorials](https://support.storeconnect.com/videos-tutorials)
- [Developer reference](https://support.storeconnect.com/developer-reference)
- [Release notes](https://support.storeconnect.com/release-notes)
- [Troubleshooting](https://support.storeconnect.com/troubleshooting)
- [Trust Center](https://trust.getstoreconnect.com/)
- [Status Page](https://status.storeconnect.com/)

## Contact

- info@getstoreconnect.com
- US +1 415 745 3230
- AUS +61 2 8365 2308

100 S Ashley Dr, Suite 600-2461
Tampa FL 33602-600 USA

Level 22, Sydney Place
180 George Street
Sydney, NSW, 2000, AUS

---

StoreConnect Support — https://support.storeconnect.com/articles/add-agent-actions