---
title: "Generate and Send Document via SignNow"
url: "https://docs.signnow.com/docs/apex-generate-and-send-document"
type: "page"
section: "Integrations"
slug: "apex-generate-and-send-document"
---

# Generate and Send Document via SignNow

# Apex action: Generate and Send Document via SignNow

> [!NOTE]
> Before configuring this Apex action, review the [prerequisites](/docs/salesforce-apex-actions#prerequisites) for SignNow Apex actions and complete the required setup steps.

The **Generate and Send Document via SignNow** action dynamically generates a document by merging a .docx template with Salesforce record data, then sends it for signature based on a Salesforce event.

> [!NOTE]
> This action reads its .docx file from Salesforce Files and requires a File ID. It does not accept a document generation template stored in SignNow Admin Tools: to send one of those, use the [Send SignNow Template](/docs/apex-send-template) action. For an overview of all document generation paths in Salesforce, see [Document generation](/docs/salesforce-document-generation).

> [!NOTE]
> **Asynchronous action:** This action runs in the background after the flow completes. If you need to use the action's output in subsequent flow steps, use the synchronous version instead: **Generate and Send Document via SignNow (sync)**.

> [!NOTE]
> **Generate and Send Document via SignNow (sync)** works the same way but runs within the current flow transaction on a single record. Use it in screen flows when you need the action's output. It returns the **Document Group ID** and **Invite ID**, which you can use in subsequent flow steps.

For example, let's configure the action to generate and send a sales invoice whenever an Opportunity is moved to the **Closed Won** stage.

---

## Step 1. Create a .docx template with tags

Prepare a .docx file as the document template. Tags in the template are placeholders that are replaced with Salesforce field values when the document is generated.

Tags use the same syntax as document generation templates in SignNow Admin Tools. For tables, lists, system tags, number formatting, value formats, and fillable field tags, see [Prepare the .docx template](/docs/salesforce-document-generation#prepare-the-docx-template). This section covers what is specific to this action: the data comes from your SOQL query.

### Find Salesforce API field names

Tags in the template must use the **API field name**, not the field's display label. To find the API field name:

- In Salesforce, go to **Setup > Object Manager**.
- Select the object you are working with, or a related object (e.g., **Opportunity**).
- Click **Fields & Relationships**.
- Locate the field by its label. The **Field Name** column shows the API name.

![apex_docgen_1_2.png](/reference-assets/images/SignNow_Salesforce/apex_docgen/apex_docgen_1_2.png)

For standard fields (e.g., `Name`, `AccountNumber`), the API name matches the field label without spaces. For custom fields, the API name ends with `__c` (e.g., `OrderNumber__c`).

To access fields on related objects, use dot notation: `Account.Name`, `Owner.Name`.

> [!IMPORTANT]
> Tags are **case-sensitive** and must match the field's API name exactly. For example, `{{Owner.Name}}` is filled with data, while `{{Owner.name}}` stays unfilled in the generated document.

> [!NOTE]
> **Compound address fields:** Some fields in the Object Manager appear as a single compound entry with the data type **Address** (e.g., `BillingAddress`). These compound fields cannot be used directly in tags. Instead, use the individual component field names following the pattern **[prefix] + [component]**. For example, `BillingAddress` breaks down into `BillingStreet`, `BillingCity`, `BillingState`, `BillingPostalCode`, and `BillingCountry`. These names are Salesforce conventions and do not appear as separate entries in the Object Manager UI. See the [Salesforce Address Compound Fields documentation](https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/compound_fields_address.htm) for the full list.

### Fields from related and child records

On this path, a tag can reach any field your SOQL query returns, including fields of related records. Select the field in the query, then tag it with the same path:

| What to insert | Tag | What the SOQL query selects |
|---|---|---|
| Field on the record | `{{OrderNumber__c}}` | `OrderNumber__c` |
| Field on a parent record | `{{Account.Name}}`, `{{Account.Owner.Email}}` | `Account.Name`, `Account.Owner.Email` |
| Field in a table row | `{{Quantity}}` inside `{{table(OpportunityLineItems)}}` | `(SELECT Quantity FROM OpportunityLineItems)` |
| Related record's field in a table row | `{{Product2.Name}}` inside `{{table(OpportunityLineItems)}}` | `(SELECT Product2.Name FROM OpportunityLineItems)` |
| Field on a specific child record | `{{OpportunityContactRoles[0].Contact.Name}}` | `(SELECT Contact.Name FROM OpportunityContactRoles)` |

To reference a specific child record, put its position in the list in square brackets. The index is zero-based: `[0]` is the first child record, `[1]` is the second, and so on.

> [!WARNING]
> **This action does not validate the template.** A tag whose field is missing from the query, misspelled, or written in the wrong letter case stays unfilled in the generated document, and the action reports no error. To check a template's tag names before you use it here, upload it in **SignNow Admin Tools > Document Generation** and check that its status is **Ready**. To compare your tags with the data, insert `{{toJson($sysConstants)}}` anywhere in the template: the generated document prints the full query result with exact field names. Remove the tag before you use the template for real.

> [!WARNING]
> **Role name in signature and text field tags:** The `o:"RoleName"` parameter specifies the signer role assigned to this field. For example, `o:"Manager"` assigns the field to the recipient with the **Manager** role. The role name must match a role defined in your SignNow document flow. The field will be filled by the recipient assigned to that role. Do not use spaces in role names: use `Recipient1` instead of `Recipient 1`, or `SalesManager` instead of `Sales Manager`.

### Invoice template example

Below is an example of a .docx template for a sales invoice that pulls data from a Salesforce Opportunity and its related line items.

![docgen_docx_template_tags.png](/reference-assets/images/SignNow_Salesforce/salesforce_docgen/docgen_docx_template_tags.png)


Let's break down each section of the template in detail.

**Header fields** (from the Opportunity, its parent Account, and the Opportunity owner):

```
{{Account.Name}}
{{Account.BillingStreet}}
{{Account.BillingCity}}, {{Account.BillingState}} {{Account.BillingPostalCode}}
{{Account.BillingCountry}}

Invoice Number: {{OrderNumber__c}}
Date: {{$today}}

Bill To:
{{Owner.Name}}
{{Owner.Email}}
```

**Line items table** (repeating rows from `OpportunityLineItems`):

The table must include the `{{table(...)}}` and `{{endtable}}` tags as rows:

| Item | Quantity | Unit Price | Amount |
|---|---|---|---|
| `{{table(OpportunityLineItems)}}` | | | |
| `{{Name}}` | `{{Quantity}}` | `{{numFormat(UnitPrice, ‘$#,###.00’)}}` | `{{numFormat(TotalPrice, ‘$#,###.00’)}}` |
| `{{endtable}}` | | | |
| **Subtotal** | | | `{{numFormat($sumabove, ‘$#,###.00’)}}{{$total=$sumabove}}` |

**Conditional discount and [fillable fields](/docs/document-generations#fillable-field-tags):**

```
{{if($total > 5000.00)}}Your discount is 10%.
{{else}}Your discount is 5%.
{{endif}}

Sales manager signature  {{t:s;r:y;o:"Manager";w:100;h:20;}}
Sales manager name       {{t:t;r:y;o:"Manager";w:100;h:20;}}
```

---

## Step 2. Upload the .docx template to Salesforce Files

Once the template is ready, upload it to Salesforce Files so the Apex action can reference it by ID.

The file can be stored as an **Attachment** or a **ContentDocument**. It does not need to be attached to the triggering record. You can upload it anywhere in Salesforce Files.

To upload the file:

- Go to any Salesforce record or the **Files** tab.
- Click **Upload Files** and select your .docx file.

![apex_docgen_3.png](/reference-assets/images/SignNow_Salesforce/apex_docgen/apex_docgen_3.png)

### Get the file ID

The Apex action requires the **File ID** as an input. To retrieve it:

- Navigate to the record where the file is stored.
- Click the dropdown arrow next to the file. Select **View File Details**.

![apex_docgen_4.png](/reference-assets/images/SignNow_Salesforce/apex_docgen/apex_docgen_4.png)

- Copy the file ID from the browser URL.

![apex_docgen_5.png](/reference-assets/images/SignNow_Salesforce/apex_docgen/apex_docgen_5.png)

---

## Step 3. Configure the flow trigger

Go to **Flows > New Flow**.

Select **Start From Scratch** or **Use a Template**. Click **Next**.

Select **Record-Triggered Flow**. Click **Create**.

Configure the flow trigger:

- Select the object whose record triggers the flow. For our example, it is **Opportunity**.
- Select when the flow should be triggered. For our example, `A record is updated`.
- Set entry conditions. For our example, the condition field is `Stage`, the operator is `Equals`, and the value is `Closed Won`.
- Under **When to Run the Flow for Updated Records**, select the option that fits your use case.
- Under **Optimize Flow for**, select **Actions and Related Records**. This is required for external callouts.

![apex_docgen_6.png](/reference-assets/images/SignNow_Salesforce/apex_docgen/apex_docgen_6.png)

---

## Step 4. Configure the Generate and Send Document action

Click the **+** icon to add an action to the flow.

Start typing *signnow* in the input field and select **Generate and Send Document via SignNow**.

Configure the action inputs:

- **File ID:** the ID of the .docx template file uploaded in Step 2.
- **Record ID:** the Salesforce record ID used as the data source. For our example, select **Triggering Opportunity > Opportunity ID**.
- **SignNow Document Flow ID:** the ID of the pre-configured [SignNow document flow](/docs/document-flows) that defines recipients and the signing scenario.

> [!NOTE]
> Copy the SignNow document flow ID from **SignNow Admin Tools > Document Flows**.

> [!WARNING]
> The roles configured in the document flow must match the role names used in the .docx template's fillable field tags. For our example, the document flow must have a role named **Manager** to match the `o:"Manager"` parameter in the signature and text field tags.

- **SOQL Query:** a SOQL query that retrieves the data to merge into the template. Build it as described in Step 5, then return here to finish the action.

![apex_docgen_7.png](/reference-assets/images/SignNow_Salesforce/apex_docgen/apex_docgen_7.png)

---

## Step 5. Build the SOQL query

The SOQL query fetches Salesforce data and makes it available as tags in the .docx template. Every field referenced in the template must be included in the SOQL query.

**Rules for building the query:**

- The `FROM` clause must match the object of the triggering record (e.g., `FROM Opportunity`).
- The `WHERE` clause must be `WHERE Id = <record_id>`. The `<record_id>` placeholder is automatically replaced with the triggering record's ID at runtime.
- Direct fields are listed as-is: `Name`, `OrderNumber__c`.
- Fields on parent objects use dot notation: `Account.Name`, `Owner.Name`.
- Child records, used in `{{table()}}` and `{{for()}}` loops or referenced by index, are included as subqueries: `(SELECT ... FROM ChildRelationshipName)`. The subquery must select every field the template uses on those records, including fields of their related records. For example, `{{OpportunityContactRoles[0].Contact.Name}}` needs `(SELECT Contact.Name FROM OpportunityContactRoles)`.
- In the SOQL subquery, use the **relationship name** (e.g., `OpportunityLineItems`). Use the same relationship name in the template's table tag: `{{table(OpportunityLineItems)}}`.

### Invoice example SOQL

```sql
SELECT
    Account.Name,
    Account.BillingStreet,
    Account.BillingCity,
    Account.BillingState,
    Account.BillingPostalCode,
    Account.BillingCountry,
    OrderNumber__c,
    Owner.Name,
    Owner.Email,
    (SELECT Name, Quantity, UnitPrice, TotalPrice FROM OpportunityLineItems)
FROM Opportunity
WHERE Id = <record_id>
```

**How the SOQL maps to template tags:**

| SOQL field | Template tag |
|---|---|
| `Account.Name` | `{{Account.Name}}` |
| `Account.BillingCity` | `{{Account.BillingCity}}` |
| `OrderNumber__c` | `{{OrderNumber__c}}` |
| `Owner.Name` | `{{Owner.Name}}` |
| `Owner.Email` | `{{Owner.Email}}` |
| `(SELECT ... FROM OpportunityLineItems)` | `{{table(OpportunityLineItems)}}` |
| `Name` *(inside subquery)* | `{{Name}}` *(inside table loop)* |
| `Quantity` *(inside subquery)* | `{{Quantity}}` *(inside table loop)* |

> [!NOTE]
> Inside a table loop, `{{Name}}` returns the line item's name, which Salesforce builds from the opportunity name and the product name, for example `Burlington Textiles Weaving Plant Generator GenWatt Diesel 1000kW`. To show only the product name, add `Product2.Name` to the subquery and tag it as `{{Product2.Name}}` in the table row. The same works for any field of a record related to the child, for example `{{PricebookEntry.Name}}`.

---

## Step 6. Save and activate the flow

Once the query is entered in the action, click **Save**, then click **Activate**.

---

## Result

![apex_docgen_result_upd.png](/reference-assets/images/SignNow_Salesforce/apex_docgen/apex_docgen_result_upd.png)


Each time an Opportunity is moved to the **Closed Won** stage, the action generates a PDF from the .docx template with the Opportunity's data merged in and sends it for signature to the recipients configured in the SignNow document flow.

---

View the full list of [SignNow Apex actions](/docs/salesforce-apex-actions).


---
*Full page: https://docs.signnow.com/docs/apex-generate-and-send-document*
