> For the complete documentation index, see [llms.txt](https://help.sdocs.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.sdocs.com/sdocs/visual-template-editor/advanced-data-executable-apex.md).

# Advanced Data: Executable Apex

### Leverage Apex to Pull Custom Data Into Your S-Docs Templates

In this tutorial, you will learn how to reference Salesforce data into an S-Docs visual template using a custom Apex class. By completing this process, you will connect Apex-defined data, including records outside your primary object hierarchy, directly into your templates.

#### Prerequisites

Before starting this tutorial, ensure you have the following:

* Salesforce Apex development experience&#x20;
* An active Apex class saved in your Salesforce org that utilizes the `SDOC.ApexExecutable` interface.
  * Ensure the class includes a declaration configured for either an **object** or a **list** appended (e.g.: `SDOC.ApexExecutableObject`  or `SDOC.ApexExecutableList` )

{% hint style="info" %}
**Helpful resources to get more familiar with Apex:**

[**Quick Start: Apex**](https://trailhead.salesforce.com/content/learn/projects/quickstart-apex)

[**Build Apex Coding Skills Trailmix**](https://trailhead.salesforce.com/content/learn/trails/build-apex-coding-skills)

[**Apex Basics for Admins**](https://trailhead.salesforce.com/content/learn/modules/apex-basics-for-admins?trail_id=build-apex-coding-skills)

[**Apex Developer Guide: Interfaces**](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_interfaces.htm)
{% endhint %}

#### Step 1: Create an Apex Class

1. Create a custom Apex class in your Salesforce org that utilizes the `SDOC.ApexExecutable`&#x20;
   1. Navigate to **Setup**
   2. Type **Apex** in the Quick Search
   3. Select **Apex Classes**
   4. Click **New**
2. Declare your Apex class structure to return either an object or a list. This declaration determines whether your data is applicable for Variables or Related Lists in the S-Docs template.&#x20;

{% hint style="info" %}
For this example, we will be creating a class for under the Objects tab, so the interface declaration will be `SDOC.ApexExecutableObject`
{% endhint %}

3. Define the data logic required to pull your target data, even if it resides outside the primary object hierarchy.
4. Click **Save**

The following is an example of a properly structured Apex Class for Visual Templates:

```
global with sharing class CalculateOpportunityRisk implements SDOC.ApexExecutableObject {

    global SDOC.ApexExecutableInfo getInfo() {
        return new SDOC.ApexExecutableInfo(
            'Calculate Opportunity Risk',
            'Calculates a risk score and category for an Opportunity from its amount and stage.'
        );
    }

    global List<SDOC.ApexExecutableInput> getInputs() {
        return new List<SDOC.ApexExecutableInput>{
            new SDOC.ApexExecutableInput('Opportunity Id', SDOC.ApexExecutableDataType.ID_TYPE, true),
            new SDOC.ApexExecutableInput('Base Multiplier', SDOC.ApexExecutableDataType.DOUBLE_TYPE, false),
            new SDOC.ApexExecutableInput('Include Historical Data', SDOC.ApexExecutableDataType.BOOLEAN_TYPE, true),
            new SDOC.ApexExecutableInput('Risk Profile', SDOC.ApexExecutableDataType.STRING_TYPE, false)
        };
    }

    global List<SDOC.ApexExecutableOutput> getOutputs() {
        return new List<SDOC.ApexExecutableOutput>{
            new SDOC.ApexExecutableOutput('RiskScore', 'Risk Score', SDOC.ApexExecutableDataType.INTEGER_TYPE),
            new SDOC.ApexExecutableOutput('RiskCategory', 'Risk Category', SDOC.ApexExecutableDataType.STRING_TYPE),
            new SDOC.ApexExecutableOutput('RequiresApproval', 'Requires Approval', SDOC.ApexExecutableDataType.BOOLEAN_TYPE)
        };
    }

    global Map<String, Object> execute(Map<String, Object> inputs) {
        Map<String, Object> results = new Map<String, Object>();

        Id opportunityId = (Id) inputs.get('Opportunity Id');
        if (opportunityId == null) {
            return results;
        }

        // Optional inputs are absent when the template author doesn't map them
        Double baseMultiplier = (Double) inputs.get('Base Multiplier');
        if (baseMultiplier == null) {
            baseMultiplier = 1.0;
        }
        Boolean includeHistorical = inputs.get('Include Historical Data') == true;
        String riskProfile = (String) inputs.get('Risk Profile');

        List<Opportunity> opportunities = [
            SELECT Amount, StageName
            FROM Opportunity
            WHERE Id = :opportunityId
            WITH USER_MODE
            LIMIT 1
        ];
        if (opportunities.isEmpty()) {
            return results;
        }

        Opportunity opportunity = opportunities[0];
        Integer score = 0;

        if (opportunity.Amount > 1000000) {
            score += 50;
        } else if (opportunity.Amount > 100000) {
            score += 25;
        }
        if (opportunity.StageName == 'Prospecting' || opportunity.StageName == 'Qualification') {
            score += 30;
        }
        if (includeHistorical) {
            score += 15;
        }
        if (riskProfile == 'Conservative') {
            score += 20;
        }
        score = (Integer) (score * baseMultiplier);

        results.put('RiskScore', score);
        results.put('RiskCategory', score >= 60 ? 'High' : (score >= 30 ? 'Medium' : 'Low'));
        results.put('RequiresApproval', score >= 60);

        return results;
    }
}
```

{% hint style="warning" %}
The Apex class example above is for demonstration purposes only and is not designed to fit any organizations unique use case.&#x20;
{% endhint %}

#### Step 2: Accessing Apex Configuration in the Visual Template Editor

1. Navigate to the *S-Docs Templates* tab
2. Open the template you want to update or create a new template.
3. Launch the editor by clicking the *Template Editor* button.

{% hint style="info" %}
Executable Apex is a feature only available in the **Visual Template Editor**. Existing templates that have been built in the classic template editor will continue to launch the classic S-Docs template editor.&#x20;
{% endhint %}

4. Navigate to the *Variables* panel ![](https://1548664070-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWKNnJmhJBQwhdk5WBFsi%2Fuploads%2FXZtitwYuD2Qrulrfmk4O%2FScreenshot%202026-07-07%20at%204.18.58%E2%80%AFPM.png?alt=media\&token=79715bcf-be59-48b8-bd2f-1b8f2061fb0e)  and click the *Advanced Data* icon ![](https://1548664070-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWKNnJmhJBQwhdk5WBFsi%2Fuploads%2FfHmGPqkktApUvNhxTSip%2FScreenshot%202026-07-07%20at%204.20.58%E2%80%AFPM.png?alt=media\&token=67ebb578-3ffe-4b40-b919-5c861c80e2b6).
5. Select either the *Objects* or *Lists* tab, depending on how your Apex class was declared.
6. Locate the *Apex* subcategory.
7. Select the **Click to Add** option to launch the Edit Apex configuration panel.

{% columns %}
{% column width="50%" valign="middle" %}

<figure><img src="https://1548664070-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWKNnJmhJBQwhdk5WBFsi%2Fuploads%2FLcVdCDde1j2bnmXQA9nq%2FScreenshot%202026-08-27%20at%2011.52.20%E2%80%AFAM.png?alt=media&amp;token=34277f58-6974-46f1-92c4-afe76d9d4df0" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column width="50%" %}

<figure><img src="https://1548664070-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWKNnJmhJBQwhdk5WBFsi%2Fuploads%2Fpd5GXIAfdqrMcKp9zWag%2FScreenshot%202026-08-27%20at%2011.52.37%E2%80%AFAM.png?alt=media&amp;token=d9a183ba-0ded-45b4-9407-5c57bb23d429" alt=""><figcaption></figcaption></figure>
{% endcolumn %}
{% endcolumns %}

#### Step 3: Configure and Map the Apex Class Data

1. On the right side of the panel, locate the *Apex Class Selection* drop-down menu and select the Apex class configured in Step 1.&#x20;

{% hint style="info" %}
The Apex Class selector in the Visual Template Editor includes the **Name** and **Description** defined in the Apex class for easier navigation:

<p align="center"><img src="https://1548664070-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWKNnJmhJBQwhdk5WBFsi%2Fuploads%2FQFZUwfH7onRKLY1Q5JeU%2FScreenshot%202026-08-27%20at%2011.58.40%E2%80%AFAM.png?alt=media&amp;token=081a4608-8bbd-478e-b228-55b63fbafa77" alt=""></p>
{% endhint %}

2. Enter a descriptive name in the *Label* field.
3. Map the fields returned by your Apex class to the appropriate template fields using the drop-down menus in the *Inputs* section:

<p align="center"><img src="https://1548664070-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWKNnJmhJBQwhdk5WBFsi%2Fuploads%2FV27MeJSIt5OtUYm6SXlS%2FScreenshot%202026-08-27%20at%2011.58.54%E2%80%AFAM.png?alt=media&amp;token=8f1d04e4-0972-4171-91af-d9c1b684cf07" alt=""><br></p>

4. Select a *Preview Record* and click **Validate** to ensure the Apex class is collecting the expected results and they're mapped correctly.
5. Click **Add Data Source.**

#### Using Apex Collected Data in a Template

{% columns %}
{% column %}

<figure><img src="https://1548664070-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FWKNnJmhJBQwhdk5WBFsi%2Fuploads%2FTl0igQHt6RCZWG5HmQ0Z%2FScreenshot%202026-08-27%20at%2012.02.35%E2%80%AFPM.png?alt=media&amp;token=ddf49033-2923-4a5d-95ae-1b3a364b2613" alt=""><figcaption></figcaption></figure>
{% endcolumn %}

{% column %}
Since this example utilizes an Apex class defined for *Objects,* the resulting data variables will populate in the Variables panel under a new subcategory labeled with the same name as the label that was configured in the **Edit Apex** panel.

Click on a variable to add it to the template body.

Alternatively, the variables will display in the inline @ mention interface directly in the template body under the **Data Source Relationships** category.

{% hint style="info" %}
When defining for *Lists* the resulting data variables will populate in as an option for *Related List Source* selection.
{% endhint %}

{% endcolumn %}
{% endcolumns %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://help.sdocs.com/sdocs/visual-template-editor/advanced-data-executable-apex.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
