> You are reading the Docusign Developer Documentation. For clean Markdown of any page, append .md to the page URL.
>
> Documentation indexes by section:
> - APIs and SDKs: https://docusign.docs.buildwithfern.com/docs/llms.txt
> - Platform 101: https://docusign.docs.buildwithfern.com/platform/llms.txt
> - Extension Apps: https://docusign.docs.buildwithfern.com/extension-apps/llms.txt
> - Docusign CLI: https://docusign.docs.buildwithfern.com/docusign-cli/llms.txt
>
> Authentication (OAuth, JWT Grant, M2M): https://docusign.docs.buildwithfern.com/platform/auth
> Webhooks and Connect: https://docusign.docs.buildwithfern.com/platform/webhooks
>
> OpenAPI specifications: https://docusign.docs.buildwithfern.com/openapi.json
> MCP server: https://docusign.docs.buildwithfern.com/_mcp/server

# How to request a signature by email with document generation

> This topic demonstrates how to request a remote signature with dynamic data fields using document generation.

eSignature REST API 2.1 only

This topic demonstrates how to request a signature for an envelope created from a template that uses the [Document generation](/docs/esign-rest-api/esign101/concepts/documents/document-generation) feature. This feature enables you to create agreements that can be populated with customized data. The template includes a document that contains placeholders, known as [sender fields](/docs/esign-rest-api/esign101/concepts/documents/document-generation#sender-field-types). For each envelope created from the template, the sender fields in the document are dynamically populated with data specified by the sender. The document in this example also includes a [dynamic table](/docs/esign-rest-api/esign101/concepts/documents/document-generation#dynamic-tables)—a feature that enables senders to supply values for a table that can have a different number of rows for each envelope. The signature request in this how-to is sent to the recipient via email, a process known as *remote signing*.

If you have created a template using the recommended [Agreement Template Builder](https://support.docusign.com/s/document-item?bundleId=als1679428547895\&topicId=jct1697745471160.html) or the [Docusign Template Assistant for Word](https://support.docusign.com/s/document-item?bundleId=als1679428547895\&topicId=kyy1679958874136.html) add-in, you can skip steps 2 through 4 in this how-to.

**Important:** You must have document generation enabled for your account. See [Document generation](/docs/esign-rest-api/esign101/concepts/documents/document-generation) for more information.

> **Note**
>
> Run this code example from our [Quickstart](/docs/esign-rest-api/quickstart) or launcher projects: [Bash](https://github.com/docusign/code-examples-bash), [C#](https://github.com/docusign/code-examples-csharp), [Java](https://github.com/docusign/code-examples-java), [Node.js](https://github.com/docusign/code-examples-node), [PHP](https://github.com/docusign/code-examples-php), [PowerShell](https://github.com/docusign/code-examples-powershell), [Python](https://github.com/docusign/code-examples-python), or [Ruby](https://github.com/docusign/code-examples-ruby).

## Required data

Running the code in this how-to requires this data:

| Data element                 | Description                                                                                                                                                                                                                                                                                                                                                                                     |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| \{API_ACCOUNT_ID}            | A [GUID](http://guid.one/) value that identifies your account. This value is automatically generated by Docusign for any account you create. Copy the value from the **API Account ID** field on the [Apps and Keys](https://admindemo.docusign.com/authenticate?goTo=appsAndKeys) page.                                                                                                        |
| \{BASE_PATH}                 | A string value that forms the root of the URL required to make API calls. The base path value in the example code is set to target the developer environment at https\://\<domain>/restapi Where \<domain> is demo.docusign.net for the developer environment and is the result of the GetUserInfo call in production.                                                                          |
| DOCX file with sender fields | You must provide at least one document to be signed that includes document generation [sender fields](/docs/esign-rest-api/esign101/concepts/documents/document-generation#sender-field-types). Currently, only DOCX files are supported. Document used in this how-to:- [DOCX file](https://github.com/docusign/code-examples-bash/blob/master/demo_documents/Offer_Letter_Dynamic_Table.docx) |
| \{SIGNER_EMAIL}              | A string value for the email address where the signer will receive a notification of the signing request.                                                                                                                                                                                                                                                                                       |
| \{SIGNER_NAME}               | A string value for the full name of the signer.                                                                                                                                                                                                                                                                                                                                                 |

## Step 1. Obtain your OAuth token

To make the API calls shown in this how-to, you need a valid OAuth access token. Docusign supports access tokens for three different recommended OAuth grant types: Public Authorization Code Grant, Confidential Authorization Code Grant, and JSON Web Token (JWT) Grant. Choose the OAuth grant type appropriate for your scenario.

> **Note**
>
> See [Confidential Authorization Code Grant](/platform/auth/authcode#confidential-authorization-code-grant) for guidance on your options to get an Confidential Authorization Code Grant  OAuth token.

![Three icons that represent the three methods a user can use to obtain an OAuth token: JSON Web Token (JWT), Public Authorization Code Grant (ACG), and Confidential Authorization Code grant](/_fern-files/_img/64f473773042ee439449a096bf7673292b1585b86a4ccc55f82ba0dda41f61a1.webp)

## Step 2. Create a template

This template definition includes a `signer` role that serves as a placeholder for the envelope recipients. This placeholder role contains an ID, a role name, and a routing order that determines the order of delivery. The template definition also includes a description, name, email subject, recipients, and [status](/docs/esign-rest-api/reference/envelopes/envelopes/liststatus). The template document and signer tabs will be defined in subsequent steps. Create the template using the [Templates:create](/docs/esign-rest-api/reference/templates/templates/create) API call, substituting your API account ID for ACCOUNT_ID, your base path for BASE_PATH, and the access token from step 1 for ACCESS_TOKEN.

**`Bash`**

```bash title="Bash"
printf \
'{
    "description": "Example template created via the API",
    "name": "Example document generation template",
    "shared": false,
    "emailSubject": "Please sign this document",
    "status": "created",
    "recipients": {
         "signers": [
              {
                 "recipientId": "1", "roleName": "signer", "routingOrder": "1"
              }
          ]
    }
}' >> $request_data

Status=$(curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data-binary @${request_data} \
    --request POST ${base_path}/v2.1/accounts/${account_id}/templates \
    --output ${response})

if [[ "$Status" -gt "201" ]] ; then
  echo ""
	echo ""
	cat $response
	exit 0
fi

# pull out the template id
template_id=`cat $response | grep templateId | sed 's/.*\"templateId\":\"//' | sed 's/\",.*//'`
```

**`C#`**

```csharp title="C#"
TemplatesApi templatesApi = new TemplatesApi(docuSignClient);
var template = templatesApi.CreateTemplateWithHttpInfo(accountId, MakeTemplate());
template.Headers.TryGetValue("X-RateLimit-Remaining", out string remaining);
template.Headers.TryGetValue("X-RateLimit-Reset", out string reset);

if (reset != null && remaining != null)
{
    DateTime resetDate = DateTimeOffset.FromUnixTimeSeconds(long.Parse(reset)).UtcDateTime;
    Console.WriteLine("API calls remaining: " + remaining);
    Console.WriteLine("Next Reset: " + resetDate);
}

string templateId = template.Data.TemplateId;
        public static EnvelopeTemplate MakeTemplate()
        {
Signer signer = new Signer
{
    RoleName = "signer",
    RecipientId = "1",
    RoutingOrder = "1",
};

Recipients recipients = new Recipients
{
    Signers = new List<Signer> { signer },
};

return new EnvelopeTemplate
{
    Description = "Example template created via the API",
    Name = "Example Template",
    Shared = "false",
    EmailSubject = "Please sign this document",
    Recipients = recipients,
    Status = "created",
};
        }
```

**`Java`**

```java title="Java"
var template = templatesApi.createTemplateWithHttpInfo(accountId, makeTemplate());
Map<String, List<String>> headers = template.getHeaders();
java.util.List<String> remaining = headers.get("X-RateLimit-Remaining");
java.util.List<String> reset = headers.get("X-RateLimit-Reset");

if (remaining != null & reset != null) {
    Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0)));
    System.out.println("API calls remaining: " + remaining);
    System.out.println("Next Reset: " + resetInstant);
}
String templateId = template.getData().getTemplateId();
    private EnvelopeTemplate makeTemplate() {
Signer signer = new Signer();
signer.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME);
signer.setRecipientId(DEFAULT_ID);
signer.setRoutingOrder("1");

Recipients recipients = new Recipients();
recipients.setSigners(Collections.singletonList(signer));

EnvelopeTemplate template = new EnvelopeTemplate();
template.setEmailSubject("Please sign this document");
template.setName("Example Template");
template.setDescription("Example template created via the API");
template.setRecipients(recipients);
template.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_CREATED);

return template;
    }
```

**`Node.js`**

```javascript title="Node.js"
const templateData = makeTemplate();
const template = await templatesApi.createTemplate(accountId, { envelopeTemplate: templateData }, (error, data, response) => {
    const headers = response?.headers;

    const remaining = headers?.['x-ratelimit-remaining'];
    const reset = headers?.['x-ratelimit-reset'];

    if (remaining && reset) {
      const resetInstant = new Date(Number(reset) * 1000);

      console.log(`API calls remaining: ${remaining}`);
      console.log(`Next Reset: ${resetInstant.toISOString()}`);
    }
});
const templateId = template.data.templateId;
const makeTemplate = () => {
const signer = docusign.Signer.constructFromObject({
  roleName: 'signer',
  recipientId: '1',
  routingOrder: '1',
});
const recipients = docusign.Recipients.constructFromObject({
  signers: [signer]
});

// create the envelope template model
const templateRequest = docusign.EnvelopeTemplate.constructFromObject({
  name: 'Example document generation template',
  description: 'Example template created via the API',
  emailSubject: 'Please sign this document',
  shared: 'false',
  recipients: recipients,
  status: 'created'
});

return templateRequest;
};
```

**`PHP`**

```php title="PHP"
$templatesApi = $clientService->getTemplatesApi();

$envelopeTemplate = DocumentGenerationService::makeTemplate();
$templatesListResponse = $templatesApi->createTemplateWithHttpInfo($args['account_id'], $envelopeTemplate);

$remaining = $templatesListResponse[2]['X-RateLimit-Remaining'] ?? null;
$reset = $templatesListResponse[2]['X-RateLimit-Reset'] ?? null;

if ($remaining !== null && $reset !== null) {
    $resetInstant = (new DateTime())->setTimestamp((int)$reset);
    error_log("API calls remaining: $remaining");
    error_log("Next Reset: " . $resetInstant->format(\DateTime::ATOM));
}
$templateId = $templatesListResponse[0]['template_id'];
    public static function makeTemplate(): EnvelopeTemplate
    {
$signer = new Signer([
     'role_name' => 'signer',
     'recipient_id' => '1',
     'routing_order' => '1',
]);

return new EnvelopeTemplate(
    [
        'description' => 'Example template created via the API',
        'name' => 'Example Template',
        'email_subject' => 'Please sign this document',
        'recipients' => new Recipients([
            'signers' => [$signer]
        ]),
        'status' => 'created',
        'shared' => 'false'
    ]
);
    }
```

**`PowerShell`**

```text title="PowerShell"
@{
    description = "Example template created via the API";
    name = "${templateName}";
    shared = "false";
    documents = @(
        @{
            documentBase64 = "$(Get-Content $doc1Base64)";
            documentId = "1";
            fileExtension = "docx";
            order = "1";
            pages = "1";
            name = "Offer Letter Demo";
            isDocGenDocument = "true";

            };
        );
        emailSubject = "Please sign this document";
        recipients = @{
            signers = @(
                @{
                    recipientId = "1";
                    roleName = "signer";
                    routingOrder = "1";
                };
            );
        };
        status = "created";
    } | ConvertTo-Json -Depth 32 > $requestData

Write-Output "${apiUri}/v2.1/accounts/${accountId}/templates"

Invoke-RestMethod `
    -Uri "${apiUri}/v2.1/accounts/${accountId}/templates" `
    -Method 'POST' `
    -Headers @{
    'Authorization' = "Bearer $accessToken";
    'Content-Type'  = "application/json";
} `
    -InFile (Resolve-Path $requestData).Path `
    -OutFile $response

# pull out the template id
$templateId = $(Get-Content $response | ConvertFrom-Json).templateId
```

**`Python`**

```python title="Python"
template_data = cls.make_template()
(template, status, headers) = templates_api.create_template_with_http_info(account_id, envelope_template=template_data)

remaining = headers.get("X-RateLimit-Remaining")
reset = headers.get("X-RateLimit-Reset")

if remaining is not None and reset is not None:
    reset_date = dt.fromtimestamp(int(reset), tz=timezone.utc)
    print(f"API calls remaining: {remaining}")
    print(f"Next Reset: {reset_date}")

template_id = template.template_id
    @classmethod
    def make_template(cls):
# Create recipient
signer = Signer(
    role_name="signer",
    recipient_id="1",
    routing_order="1",
)
recipients = Recipients(
    signers=[signer]
)

# Create the envelope template model
template_request = EnvelopeTemplate(
    name="Example document generation template",
    description="Example template created via the API",
    email_subject="Please sign this document",
    shared="false",
    recipients=recipients,
    status="created"
)
return template_request
```

**`Ruby`**

```ruby title="Ruby"
template, _status, headers = template_api.create_template_with_http_info(account_id, template_data)

remaining = headers['X-RateLimit-Remaining']
reset = headers['X-RateLimit-Reset']

if remaining && reset
  reset_date = Time.at(reset.to_i).utc
  puts "API calls remaining: #{remaining}"
  puts "Next Reset: #{reset_date}"
end

template_id = template.template_id
  def template_data
# Create recipients
signer = DocuSign_eSign::Signer.new(
  roleName: 'signer',
  recipientId: '1',
  routingOrder: '1'
)
recipients = DocuSign_eSign::Recipients.new(
  signers: [signer]
)

# Create the envelope template model
DocuSign_eSign::EnvelopeTemplate.new(
  name: 'Example document generation template',
  description: 'Example template created via the API',
  emailSubject: 'Please sign this document',
  shared: 'false',
  recipients: recipients,
  status: 'created'
)
  end
```

## Step 3. Add a document with sender fields to your template

The document provided in this call should have sender fields, which will be automatically detected. See [Methods for creating documents](/docs/esign-rest-api/esign101/concepts/documents/document-generation#methods-for-creating-documents) for more information on how to create a document with a dynamic table and sender fields. For your sender fields to be automatically detected, you must add your document to the template separately from the [Templates:create](/docs/esign-rest-api/reference/templates/templates/create) call in Step 2. After adding a Base64-encoded document to the request body, call [TemplateDocuments:update](/docs/esign-rest-api/reference/templates/templatedocuments/update), substituting the template ID obtained from the [Templates:create](/docs/esign-rest-api/reference/templates/templates/create) API call for TEMPLATE_ID.

**`Bash`**

```bash title="Bash"
# Fetch document and encode
cat demo_documents/Offer_Letter_Dynamic_Table.docx | base64 > $doc1_base64

printf \
'{
  "documents": [
        {
            "documentBase64": "' >> $request_data
            cat $doc1_base64 >> $request_data
            printf '",
            "documentId": "1", "fileExtension": "docx", "order":"1","pages":"1",
            "name": "OfferLetterDemo.docx"
        }
    ]
}' >> $request_data

Status=$(curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --header "Accept: application/json" \
  --data-binary @${request_data} \
  --request PUT ${base_path}/v2.1/accounts/${account_id}/templates/${template_id}/documents/1 \
  --output ${response})
```

**`C#`**

```csharp title="C#"
var updateDocumentResponse = templatesApi.UpdateDocumentWithHttpInfo(accountId, templateId, DefaultId, AddDocumentTemplate(offerDocDocx));
updateDocumentResponse.Headers.TryGetValue("X-RateLimit-Remaining", out remaining);
updateDocumentResponse.Headers.TryGetValue("X-RateLimit-Reset", out reset);

if (reset != null && remaining != null)
{
    DateTime resetDate = DateTimeOffset.FromUnixTimeSeconds(long.Parse(reset)).UtcDateTime;
    Console.WriteLine("API calls remaining: " + remaining);
    Console.WriteLine("Next Reset: " + resetDate);
}

        public static EnvelopeDefinition AddDocumentTemplate(string offerDocumentDocx)
        {
string documentBase64 = Convert.ToBase64String(System.IO.File.ReadAllBytes(offerDocumentDocx));
Document document = new Document
{
    DocumentBase64 = documentBase64,
    Name = "OfferLetterDemo.docx",
    FileExtension = "docx",
    DocumentId = "1",
    Order = "1",
    Pages = "1",
};

return new EnvelopeDefinition
{
    Documents = new List<Document> { document },
};
        }
```

**`Java`**

```java title="Java"
private static EnvelopeDefinition addDocumentTemplate(String offerDocDocx) throws IOException {
    String documentName = "OfferLetterDemo.docx";
    Document document = EnvelopeHelpers.createDocumentFromFile(offerDocDocx, documentName, DEFAULT_ID);
    document.setOrder("1");
    document.pages("1");

    EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition();
    envelopeDefinition.setDocuments(Collections.singletonList(document));

    return envelopeDefinition;
}
    var updateResponse = templatesApi.updateDocumentWithHttpInfo(accountId, templateId, DEFAULT_ID,
            addDocumentTemplate(offerDocDocx), templatesApi.new UpdateDocumentOptions());
    headers = updateResponse.getHeaders();
    remaining = headers.get("X-RateLimit-Remaining");
    reset = headers.get("X-RateLimit-Reset");

    if (remaining != null & reset != null) {
        Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0)));
        System.out.println("API calls remaining: " + remaining);
        System.out.println("Next Reset: " + resetInstant);
    }
```

**`Node.js`**

```javascript title="Node.js"
const documentData = templateDocument(envelopeArgs);
const documentId = '1';
await templatesApi.updateDocument(accountId, templateId, documentId, { envelopeDefinition: documentData }, (error, data, response) => {
    const headers = response?.headers;

    const remaining = headers?.['x-ratelimit-remaining'];
    const reset = headers?.['x-ratelimit-reset'];

    if (remaining && reset) {
      const resetInstant = new Date(Number(reset) * 1000);

      console.log(`API calls remaining: ${remaining}`);
      console.log(`Next Reset: ${resetInstant.toISOString()}`);
    }
});
const templateDocument = (args) => {
// read file
const docBytes = fs.readFileSync(args.docFile);

// create the document object
const document = docusign.Document.constructFromObject({
  documentBase64: Buffer.from(docBytes).toString('base64'),
  name: 'OfferLetterDemo.docx',
  fileExtension: 'docx',
  documentId: 1,
  order: 1,
  pages: 1,
});

const envelopeDefinition = docusign.EnvelopeDefinition.constructFromObject({
  documents: [document],
});

return envelopeDefinition;
};
```

**`PHP`**

```php title="PHP"
$response = $templatesApi->updateDocumentWithHttpInfo(
    $args['account_id'],
    "1",
    $templateId,
    self::addDocumentTemplate($documentPath)
);

$remaining = $response[2]['X-RateLimit-Remaining'] ?? null;
$reset = $response[2]['X-RateLimit-Reset'] ?? null;

if ($remaining !== null && $reset !== null) {
    $resetInstant = (new DateTime())->setTimestamp((int)$reset);
    error_log("API calls remaining: $remaining");
    error_log("Next Reset: " . $resetInstant->format(\DateTime::ATOM));
}
    public static function addDocumentTemplate(string $documentPath): EnvelopeDefinition
    {
$documentFile = $GLOBALS['DS_CONFIG']['offer_doc_docx'];
$contentBytes = file_get_contents($documentPath . $documentFile);
$base64FileContent = base64_encode($contentBytes);

$document = new Document([
     'document_base64' => $base64FileContent,
     'name' => 'OfferLetterDemo.docx',
     'file_extension' => 'docx',
     'document_id' => '1',
     'order' => '1',
     'pages' => '1',
]);

return new EnvelopeDefinition([
        'documents' => [$document],
]);
    }
```

**`PowerShell`**

```text title="PowerShell"
@{
  documents = @(
      @{
          documentBase64 = "$(Get-Content $doc1Base64)";
          documentId = "1";
          fileExtension = "docx";
          order = "1";
          pages = "1";
          name = "Offer Letter Demo";

      };
  );
} | ConvertTo-Json -Depth 32 > $requestData

Invoke-RestMethod `
    -Uri "${apiUri}/v2.1/accounts/${accountId}/templates/${templateId}/documents/1" `
    -Method 'PUT' `
    -Headers @{
    'Authorization' = "Bearer $accessToken";
    'Content-Type'  = "application/json";
} `
    -InFile (Resolve-Path $requestData).Path  `
    -OutFile $response
```

**`Python`**

```python title="Python"
document_id = '1'
(response, status, headers) = templates_api.update_document_with_http_info(
    account_id, document_id, template_id,
    envelope_definition=cls.template_document(envelope_args)
)

remaining = headers.get("X-RateLimit-Remaining")
reset = headers.get("X-RateLimit-Reset")

if remaining is not None and reset is not None:
    reset_date = dt.fromtimestamp(int(reset), tz=timezone.utc)
    print(f"API calls remaining: {remaining}")
    print(f"Next Reset: {reset_date}")
    @classmethod
    def template_document(cls, args):
with open(args["doc_file"], "rb") as file:
    content_bytes = file.read()
base64_file_content = base64.b64encode(content_bytes).decode("ascii")

# Create the document model
document = Document(
    document_base64=base64_file_content,
    name="OfferLetterDemo.docx",
    file_extension="docx",
    document_id=1,
    order=1,
    pages=1
)

envelope_definition = EnvelopeDefinition(
    documents=[document]
)
return envelope_definition
```

**`Ruby`**

```ruby title="Ruby"
document_id = '1'
_results, _status, headers = template_api.update_document_with_http_info(account_id, document_id, template_id, template_document(envelope_args))

remaining = headers['X-RateLimit-Remaining']
reset = headers['X-RateLimit-Reset']

if remaining && reset
  reset_date = Time.at(reset.to_i).utc
  puts "API calls remaining: #{remaining}"
  puts "Next Reset: #{reset_date}"
end
  def template_document(args)
# Create the document model
document = DocuSign_eSign::Document.new(
  documentBase64: Base64.encode64(File.binread(args[:doc_file])),
  name: 'OfferLetterDemo.docx',
  fileExtension: 'docx',
  documentId: 1,
  order: 1,
  pages: 1
)

DocuSign_eSign::EnvelopeDefinition.new(
  documents: [document]
)
  end
```

## Step 4. Add tabs to the template

Now that the template contains a document, add tabs for the placeholder recipient. In the request body, define a `signHere` tab and a `dateSigned` tab using [Auto-place (anchor tagging)](/docs/esign-rest-api/esign101/concepts/tabs/auto-place). Then make a call to [TemplateRecipientTabs:create](/docs/esign-rest-api/reference/templates/templaterecipienttabs/create).

**`Bash`**

```bash title="Bash"
printf \
'{
    "signHereTabs": [
        {
            "anchorString": "Employee Signature",
            "anchorUnits": "pixels",
            "anchorXOffset": "5",
            "anchorYOffset": "-22"
        }
    ],
    "dateSignedTabs": [
        {
            "anchorString": "Date Signed",
            "anchorUnits": "pixels",
            "anchorYOffset": "-22"
        }
    ]
}' >> $request_data

Status=$(curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @${request_data} \
  --request POST ${base_path}/v2.1/accounts/${account_id}/templates/${template_id}/recipients/1/tabs \
  --output ${response})
```

**`C#`**

```csharp title="C#"
var createTabsResponse = templatesApi.CreateTabsWithHttpInfo(accountId, templateId, DefaultId, PrepareTabs());
createTabsResponse.Headers.TryGetValue("X-RateLimit-Remaining", out remaining);
createTabsResponse.Headers.TryGetValue("X-RateLimit-Reset", out reset);

if (reset != null && remaining != null)
{
    DateTime resetDate = DateTimeOffset.FromUnixTimeSeconds(long.Parse(reset)).UtcDateTime;
    Console.WriteLine("API calls remaining: " + remaining);
    Console.WriteLine("Next Reset: " + resetDate);
}

        public static TemplateTabs PrepareTabs()
        {
SignHere signHere = new SignHere
{
    AnchorString = "Employee Signature",
    AnchorUnits = "pixels",
    AnchorXOffset = "5",
    AnchorYOffset = "-22",
};

DateSigned dateSignedTabs = new DateSigned
{
    AnchorString = "Date Signed",
    AnchorUnits = "pixels",
    AnchorYOffset = "-22",
};

return new TemplateTabs
{
    SignHereTabs = new List<SignHere> { signHere },
    DateSignedTabs = new List<DateSigned> { dateSignedTabs },
};
        }
```

**`Java`**

```java title="Java"
var tabsResponse = templatesApi.createTabsWithHttpInfo(accountId, templateId, DEFAULT_ID, prepareTabs());
headers = tabsResponse.getHeaders();
remaining = headers.get("X-RateLimit-Remaining");
reset = headers.get("X-RateLimit-Reset");

if (remaining != null & reset != null) {
    Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0)));
    System.out.println("API calls remaining: " + remaining);
    System.out.println("Next Reset: " + resetInstant);
}
    private TemplateTabs prepareTabs() {
SignHere signHere = createSignHere();
DateSigned dateSigned = createDateSigned();

TemplateTabs templateTabs = new TemplateTabs();
templateTabs.setSignHereTabs(Collections.singletonList(signHere));
templateTabs.setDateSignedTabs(Collections.singletonList(dateSigned));

return templateTabs;
    }

    private SignHere createSignHere() {
SignHere signHere = new SignHere();

signHere.setAnchorString("Employee Signature");
signHere.setAnchorUnits(ANCHOR_UNITS);
signHere.setAnchorXOffset("5");
signHere.setAnchorYOffset("-22");

return signHere;
    }

    private DateSigned createDateSigned() {
DateSigned dateSigned = new DateSigned();

dateSigned.setAnchorString("Date Signed");
dateSigned.setAnchorUnits(ANCHOR_UNITS);
dateSigned.setAnchorYOffset("-22");

return dateSigned;
    }
```

**`Node.js`**

```javascript title="Node.js"
const tabs = recipientTabs(envelopeArgs);
const recipientId = '1';
await templatesApi.createTabs(accountId, templateId, recipientId, { templateTabs: tabs }, (error, data, response) => {
    const headers = response?.headers;

    const remaining = headers?.['x-ratelimit-remaining'];
    const reset = headers?.['x-ratelimit-reset'];

    if (remaining && reset) {
      const resetInstant = new Date(Number(reset) * 1000);

      console.log(`API calls remaining: ${remaining}`);
      console.log(`Next Reset: ${resetInstant.toISOString()}`);
    }
});
const recipientTabs = () => {
const signHere = docusign.SignHere.constructFromObject({
  anchorString: 'Employee Signature',
  anchorUnits: 'pixels',
  anchorXOffset: '5',
  anchorYOffset: '-22'
});

const dateSigned = docusign.DateSigned.constructFromObject({
  anchorString: 'Date Signed',
  anchorUnits: 'pixels',
  anchorYOffset: '-22'
});

const tabs = docusign.Tabs.constructFromObject({
  signHereTabs: [signHere],
  dateSignedTabs: [dateSigned]
});

return tabs;
};
```

**`PHP`**

```php title="PHP"
$response = $templatesApi->createTabsWithHttpInfo($args['account_id'], "1", $templateId, self::prepareTabs());

$remaining = $response[2]['X-RateLimit-Remaining'] ?? null;
$reset = $response[2]['X-RateLimit-Reset'] ?? null;

if ($remaining !== null && $reset !== null) {
    $resetInstant = (new DateTime())->setTimestamp((int)$reset);
    error_log("API calls remaining: $remaining");
    error_log("Next Reset: " . $resetInstant->format(\DateTime::ATOM));
}
    public static function prepareTabs(): TemplateTabs
    {
$signHere = new SignHere([
    'anchor_string' => 'Employee Signature',
    'anchor_units' => 'pixels',
    'anchor_x_offset' => '5',
    'anchor_y_offset' => '-22'
]);

$dateSigned = new DateSigned([
    'anchor_string' => 'Date Signed',
    'anchor_units' => 'pixels',
    'anchor_y_offset' => '-22'
]);

return new TemplateTabs([
     'sign_here_tabs' => [$signHere],
     'date_signed_tabs' => [$dateSigned],
]);
    }
```

**`PowerShell`**

```text title="PowerShell"
@{
    signHereTabs   = @(
        @{
            anchorString = "Employee Signature";
            anchorUnits = "pixels";
            anchorXOffset = "5";
            anchorYOffset = "-22";
        };
    );
    dateSignedTabs   = @(
        @{
            anchorString = "Date Signed";
            anchorUnits = "pixels";
            anchorYOffset = "-22";
        };
    );
} | ConvertTo-Json -Depth 32 > $requestData

Invoke-RestMethod `
    -Uri "${apiUri}/v2.1/accounts/${accountId}/templates/${templateId}/recipients/1/tabs" `
    -Method 'POST' `
    -Headers @{
    'Authorization' = "Bearer $accessToken";
    'Content-Type'  = "application/json";
} `
    -InFile (Resolve-Path $requestData).Path `
    -OutFile $response
```

**`Python`**

```python title="Python"
recipient_id = '1'
(response, status, headers) = templates_api.create_tabs_with_http_info(
    account_id, recipient_id, template_id,
    template_tabs=cls.recipient_tabs()
)

remaining = headers.get("X-RateLimit-Remaining")
reset = headers.get("X-RateLimit-Reset")

if remaining is not None and reset is not None:
    reset_date = dt.fromtimestamp(int(reset), tz=timezone.utc)
    print(f"API calls remaining: {remaining}")
    print(f"Next Reset: {reset_date}")
    @classmethod
    def recipient_tabs(cls):
# Create tabs
sign_here = SignHere(
    anchor_string="Employee Signature",
    anchor_units="pixels",
    anchor_x_offset="5",
    anchor_y_offset="-22"
)
date_signed = DateSigned(
    anchor_string="Date Signed",
    anchor_units="pixels",
    anchor_y_offset="-22"
)
tabs = Tabs(
    sign_here_tabs=[sign_here],
    date_signed_tabs=[date_signed]
)
return tabs
```

**`Ruby`**

```ruby title="Ruby"
recipient_id = '1'
_results, _status, headers = template_api.create_tabs_with_http_info(account_id, recipient_id, template_id, recipient_tabs)

remaining = headers['X-RateLimit-Remaining']
reset = headers['X-RateLimit-Reset']

if remaining && reset
  reset_date = Time.at(reset.to_i).utc
  puts "API calls remaining: #{remaining}"
  puts "Next Reset: #{reset_date}"
end
  def recipient_tabs
# Create tabs
sign_here = DocuSign_eSign::SignHere.new(
  anchorString: 'Employee Signature',
  anchorUnits: 'pixels',
  anchorXOffset: '5',
  anchorYOffset: '-22'
)
date_signed = DocuSign_eSign::DateSigned.new(
  anchorString: 'Date Signed',
  anchorUnits: 'pixels',
  anchorYOffset: '-22'
)
DocuSign_eSign::Tabs.new(
  signHereTabs: [sign_here],
  dateSignedTabs: [date_signed]
)
  end
```

## Step 5. Create an envelope draft from a template

When creating an envelope definition from a template, you must specify the template ID that was returned from the [Templates:create](/docs/esign-rest-api/reference/templates/templates/create) call in Step 2. If you created the template using the [Agreement Template Builder](https://support.docusign.com/s/document-item?bundleId=als1679428547895\&topicId=jct1697745471160.html) or the [Docusign Template Assistant for Word](https://support.docusign.com/s/document-item?bundleId=als1679428547895\&topicId=kyy1679958874136.html), you can obtain the template ID by logging in to the [eSignature web app](https://apps-d.docusign.com/send/templates/), selecting **Templates** from the top navigation menu, opening the template, and selecting the **Template ID** link. You also must provide the name and email of the party acting in the `signer` role that the template specifies. Set the [status](/docs/esign-rest-api/reference/envelopes/envelopes/liststatus) field to `created` since you will be updating this draft in the following steps. Then create the envelope draft with a call to [Envelopes:create](/docs/esign-rest-api/reference/envelopes/envelopes/create), substituting your signer’s email for SIGNER_EMAIL and their name for SIGNER_NAME.

**`Bash`**

```bash title="Bash"
printf \
'{
    "templateId": "'"${template_id}"'",
    "templateRoles": [
        {
            "email": "'"${SIGNER_EMAIL}"'",
            "name": "'"${SIGNER_NAME}"'",
            "roleName": "signer"
        }
    ],
    "status": "created"
}' >> $request_data

echo ""
echo "Sending the envelope request to DocuSign..."

Status=$(curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @${request_data} \
  --request POST ${base_path}/v2.1/accounts/${account_id}/envelopes \
  --output ${response})

if [[ "$Status" -gt "201" ]] ; then
  echo ""
	echo "Envelope creation failed."
	echo ""
	cat $response
	exit 0
fi

envelope_id=`cat $response | grep envelopeId | sed 's/.*\"envelopeId\":\"//' | sed 's/\",.*//'`
```

**`C#`**

```csharp title="C#"
EnvelopesApi envelopesApi = new EnvelopesApi(docuSignClient);
var envelopeResponse = envelopesApi.CreateEnvelopeWithHttpInfo(accountId, MakeEnvelope(candidateEmail, candidateName, templateId));
envelopeResponse.Headers.TryGetValue("X-RateLimit-Remaining", out remaining);
envelopeResponse.Headers.TryGetValue("X-RateLimit-Reset", out reset);

if (reset != null && remaining != null)
{
    DateTime resetDate = DateTimeOffset.FromUnixTimeSeconds(long.Parse(reset)).UtcDateTime;
    Console.WriteLine("API calls remaining: " + remaining);
    Console.WriteLine("Next Reset: " + resetDate);
}

string envelopeId = envelopeResponse.Data.EnvelopeId;
        public static EnvelopeDefinition MakeEnvelope(string candidateEmail, string candidateName, string templateId)
        {
TemplateRole signer = new TemplateRole
{
    Email = candidateEmail,
    Name = candidateName,
    RoleName = "signer",
};

return new EnvelopeDefinition
{
    TemplateRoles = new List<TemplateRole> { signer },
    Status = "created",
    TemplateId = templateId,
};
        }
```

**`Java`**

```java title="Java"
var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(
        accountId,
        makeEnvelope(candidateEmail, candidateName, template.getData().getTemplateId()),
        envelopesApi.new CreateEnvelopeOptions());
headers = envelopeSummary.getHeaders();
remaining = headers.get("X-RateLimit-Remaining");
reset = headers.get("X-RateLimit-Reset");

if (remaining != null & reset != null) {
    Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0)));
    System.out.println("API calls remaining: " + remaining);
    System.out.println("Next Reset: " + resetInstant);
}
;
String envelopeId = envelopeSummary.getData().getEnvelopeId();
    private EnvelopeDefinition makeEnvelope(String candidateEmail, String candidateName, String templateId) {
TemplateRole signerRole = new TemplateRole();
signerRole.setName(candidateName);
signerRole.setEmail(candidateEmail);
signerRole.setRoleName(EnvelopeHelpers.SIGNER_ROLE_NAME);

EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition();
envelopeDefinition.setTemplateRoles(Collections.singletonList(signerRole));
envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_CREATED);
envelopeDefinition.setTemplateId(templateId);

return envelopeDefinition;
    }
```

**`Node.js`**

```javascript title="Node.js"
const envelopeData = makeEnvelope(templateId, envelopeArgs);
const envelope = await envelopesApi.createEnvelope(accountId, { envelopeDefinition: envelopeData }, (error, data, response) => {
    const headers = response?.headers;

    const remaining = headers?.['x-ratelimit-remaining'];
    const reset = headers?.['x-ratelimit-reset'];

    if (remaining && reset) {
      const resetInstant = new Date(Number(reset) * 1000);

      console.log(`API calls remaining: ${remaining}`);
      console.log(`Next Reset: ${resetInstant.toISOString()}`);
    }
});
const envelopeId = envelope.data.envelopeId;
const makeEnvelope = (templateId, args) => {
// create the signer model
const signer = docusign.TemplateRole.constructFromObject({
  email: args.candidateEmail,
  name: args.candidateName,
  roleName: 'signer'
});

// create the envelope model
const envelopeDefinition = docusign.EnvelopeDefinition.constructFromObject({
  templateRoles: [signer],
  status: 'created',
  templateId: templateId
});

return envelopeDefinition;
};
```

**`PHP`**

```php title="PHP"
$envelopeApi = $clientService->getEnvelopeApi();
$envelopeResponse = $envelopeApi->createEnvelopeWithHttpInfo(
    $args['account_id'],
    DocumentGenerationService::makeEnvelope($args["form_data"], $templateId)
);

$remaining = $envelopeResponse[2]['X-RateLimit-Remaining'] ?? null;
$reset = $envelopeResponse[2]['X-RateLimit-Reset'] ?? null;

if ($remaining !== null && $reset !== null) {
    $resetInstant = (new DateTime())->setTimestamp((int)$reset);
    error_log("API calls remaining: $remaining");
    error_log("Next Reset: " . $resetInstant->format(\DateTime::ATOM));
}
$envelopeId = $envelopeResponse[0]["envelope_id"];
    public static function makeEnvelope(array $args, $templateId): EnvelopeDefinition
    {
$signer = new TemplateRole([
    'email' => $args['candidate_email'],
    'name' => $args['candidate_name'],
    'role_name' => "signer"
]);

return new EnvelopeDefinition(
    [
        'status' => "created",
        'template_roles' => [$signer],
        "template_id" => $templateId
    ]
);
    }
```

**`PowerShell`**

```text title="PowerShell"
@{
    templateId    = "${templateId}";
    templateRoles = @(
        @{
            email    = $variables.SIGNER_EMAIL;
            name     = $variables.SIGNER_NAME;
            roleName = "signer";
        };
    );
    status        = "created";
} | ConvertTo-Json -Depth 32 > $requestData

Invoke-RestMethod `
    -Uri "${apiUri}/v2.1/accounts/${accountId}/envelopes" `
    -Method 'POST' `
    -Headers @{
    'Authorization' = "Bearer $accessToken";
    'Content-Type'  = "application/json";
} `
    -InFile (Resolve-Path $requestData).Path  `
    -OutFile $response

# pull out the envelope id
$envelopeId = $(Get-Content $response | ConvertFrom-Json).envelopeId
```

**`Python`**

```python title="Python"
envelope_definition = cls.make_envelope(template_id, envelope_args)
(envelope, status, headers) = envelopes_api.create_envelope_with_http_info(account_id, envelope_definition=envelope_definition)

remaining = headers.get("X-RateLimit-Remaining")
reset = headers.get("X-RateLimit-Reset")

if remaining is not None and reset is not None:
    reset_date = dt.fromtimestamp(int(reset), tz=timezone.utc)
    print(f"API calls remaining: {remaining}")
    print(f"Next Reset: {reset_date}")

envelope_id = envelope.envelope_id
    @classmethod
    def make_envelope(cls, template_id, args):
# Create the signer model
signer = TemplateRole(
    email=args["candidate_email"],
    name=args["candidate_name"],
    role_name="signer"
)

# Create the envelope model
envelope_definition = EnvelopeDefinition(
    template_roles=[signer],
    status="created",
    template_id=template_id
)
return envelope_definition
```

**`Ruby`**

```ruby title="Ruby"
envelope_definition = make_envelope(template_id, envelope_args)
envelope, _status, headers = envelope_api.create_envelope_with_http_info(account_id, envelope_definition)

remaining = headers['X-RateLimit-Remaining']
reset = headers['X-RateLimit-Reset']

if remaining && reset
  reset_date = Time.at(reset.to_i).utc
  puts "API calls remaining: #{remaining}"
  puts "Next Reset: #{reset_date}"
end

envelope_id = envelope.envelope_id
  def make_envelope(template_id, args)
# Create the signer model
signer = DocuSign_eSign::TemplateRole.new(
  email: args[:candidate_email],
  name: args[:candidate_name],
  roleName: 'signer'
)

# Create the envelope model
DocuSign_eSign::EnvelopeDefinition.new(
  templateRoles: [signer],
  status: 'created',
  templateId: template_id
)
  end
```

## Step 6. Get DocGenFormFields

Make a call to [DocumentGeneration:getEnvelopeDocGenFormFields](/docs/esign-rest-api/reference/envelopes/documentgeneration/getenvelopedocgenformfields) to receive a list of the `docGenFormFields` on the document. You will also need the `documentId` value returned in the response of this API call to complete the next step.

**`Bash`**

```bash title="Bash"
Status=$(curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
      --header "Accept: application/json" \
      --request GET ${base_path}/v2.1/accounts/${account_id}/envelopes/${envelope_id}/docGenFormFields \
      --output ${response})

echo $Status
if [[ "$Status" -gt "201" ]] ; then
  echo ""
	echo "Failed to fetch docGenFormFields."
	echo ""
	cat $response
	exit 0
fi

echo "DocGenFormFields: "
cat $response

# Retrieve the document id
document_id=`cat $response | grep documentId | sed 's/.*\"documentId\":\"//' | sed 's/\",.*//'`
```

**`C#`**

```csharp title="C#"
var formFieldsResponse = envelopesApi.GetEnvelopeDocGenFormFieldsWithHttpInfo(accountId, envelopeResponse.Data.EnvelopeId);
formFieldsResponse.Headers.TryGetValue("X-RateLimit-Remaining", out remaining);
formFieldsResponse.Headers.TryGetValue("X-RateLimit-Reset", out reset);

if (reset != null && remaining != null)
{
    DateTime resetDate = DateTimeOffset.FromUnixTimeSeconds(long.Parse(reset)).UtcDateTime;
    Console.WriteLine("API calls remaining: " + remaining);
    Console.WriteLine("Next Reset: " + resetDate);
}
```

**`Java`**

```java title="Java"
var formFieldResponse = envelopesApi.getEnvelopeDocGenFormFieldsWithHttpInfo(accountId, envelopeId);
headers = formFieldResponse.getHeaders();
remaining = headers.get("X-RateLimit-Remaining");
reset = headers.get("X-RateLimit-Reset");

if (remaining != null & reset != null) {
    Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0)));
    System.out.println("API calls remaining: " + remaining);
    System.out.println("Next Reset: " + resetInstant);
}
;

String documentId = "";
if (!formFieldResponse.getData().getDocGenFormFields().isEmpty()) {
    DocGenFormFields docGenFormFields = formFieldResponse.getData().getDocGenFormFields().get(0);
    if (docGenFormFields != null) {
        documentId = docGenFormFields.getDocumentId();
    }
}
```

**`Node.js`**

```javascript title="Node.js"
const docGenFormFieldsResponse = await envelopesApi.getEnvelopeDocGenFormFields(accountId, envelopeId, (error, data, response) => {
    const headers = response?.headers;

    const remaining = headers?.['x-ratelimit-remaining'];
    const reset = headers?.['x-ratelimit-reset'];

    if (remaining && reset) {
      const resetInstant = new Date(Number(reset) * 1000);

      console.log(`API calls remaining: ${remaining}`);
      console.log(`Next Reset: ${resetInstant.toISOString()}`);
    }
});
const documentIdGuid = docGenFormFieldsResponse.data.docGenFormFields[0].documentId;
```

**`PHP`**

```php title="PHP"
$documents = $envelopeApi->getEnvelopeDocGenFormFieldsWithHttpInfo($args['account_id'], $envelopeId);

$remaining = $documents[2]['X-RateLimit-Remaining'] ?? null;
$reset = $documents[2]['X-RateLimit-Reset'] ?? null;

if ($remaining !== null && $reset !== null) {
    $resetInstant = (new DateTime())->setTimestamp((int)$reset);
    error_log("API calls remaining: $remaining");
    error_log("Next Reset: " . $resetInstant->format(\DateTime::ATOM));
}
$documentId = $documents[0]["doc_gen_form_fields"][0]["document_id"];
```

**`PowerShell`**

```text title="PowerShell"
Invoke-RestMethod `
  -Uri "${apiUri}/v2.1/accounts/${accountId}/envelopes/${envelopeId}/docGenFormFields" `
  -Method 'GET' `
  -Headers @{
  'Authorization' = "Bearer $accessToken";
  'Content-Type'  = "application/json";
} `
-OutFile $response

Write-Output "Response:"
Get-Content $response

# pull out the document id value
$documentId = $(Get-Content $response | ConvertFrom-Json).docGenFormFields[0].documentId
```

**`Python`**

```python title="Python"
(doc_gen_form_fields_response, status, headers) = envelopes_api.get_envelope_doc_gen_form_fields_with_http_info(account_id, envelope_id)

remaining = headers.get("X-RateLimit-Remaining")
reset = headers.get("X-RateLimit-Reset")

if remaining is not None and reset is not None:
    reset_date = dt.fromtimestamp(int(reset), tz=timezone.utc)
    print(f"API calls remaining: {remaining}")
    print(f"Next Reset: {reset_date}")

document_id_guid = doc_gen_form_fields_response.doc_gen_form_fields[0].document_id
```

**`Ruby`**

```ruby title="Ruby"
doc_gen_form_fields_response, _status, headers = envelope_api.get_envelope_doc_gen_form_fields_with_http_info(account_id, envelope_id)

remaining = headers['X-RateLimit-Remaining']
reset = headers['X-RateLimit-Reset']

if remaining && reset
  reset_date = Time.at(reset.to_i).utc
  puts "API calls remaining: #{remaining}"
  puts "Next Reset: #{reset_date}"
end

document_id_guid = doc_gen_form_fields_response.doc_gen_form_fields[0].document_id
```

## Step 7. Merge sender fields with the eSignature REST API

Update the `value` of the `docGenFormFields` specified in the response of the previous step with the appropriate sender data. Then, use the [DocumentGeneration:updateEnvelopeDocGenFormFields](/docs/esign-rest-api/reference/envelopes/documentgeneration/updateenvelopedocgenformfields) method to dynamically generate a document with the data included in the request.

**`Bash`**

```bash title="Bash"
printf \
'{
  "docGenFormFields": [
    {
      "documentId": "'"${document_id}"'",
      "docGenFormFieldList": [
        {
          "name": "Candidate_Name",
          "value": "'"${CANDIDATE_NAME}"'"
        },
        {
          "name": "Job_Title",
          "value": "'"${JOB_TITLE}"'"
        },
        {
          "name": "Manager_Name",
          "value": "'"${MANAGER_NAME}"'"
        },
        {
          "name": "Start_Date",
          "value": "'"${START_DATE}"'"
        },
        {
          "name": "Compensation_Package",
          "type": "TableRow",
          "rowValues": [
            {
              "docGenFormFieldList": [
                {
                  "name": "Compensation_Component",
                  "value": "Salary"
                },
                {
                  "name": "Details",
                  "value": "$'"${SALARY}"'"
                }
              ]
            },
            {
              "docGenFormFieldList": [
                {
                  "name": "Compensation_Component",
                  "value": "Bonus"
                },
                {
                  "name": "Details",
                  "value": "20%%"
                }
              ]
            },
            {
              "docGenFormFieldList": [
                {
                  "name": "Compensation_Component",
                  "value": "RSUs"
                },
                {
                  "name": "Details",
                  "value": '${RSUS}'
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}' >> $request_data

Status=$(curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
      --header "Content-Type: application/json" \
      --data-binary @${request_data} \
      --request PUT ${base_path}/v2.1/accounts/${account_id}/envelopes/${envelope_id}/docgenformfields \
      --output ${response})
```

**`C#`**

```csharp title="C#"
DocGenFormFieldRequest preparedFormFields = FormFields(
    formFieldsResponse.Data.DocGenFormFields.FirstOrDefault()?.DocumentId,
    candidateName,
    managerName,
    jobTitle,
    salary,
    rsus.ToString(),
    startDate.ToString("MM/dd/yyyy", CultureInfo.InvariantCulture));

var updateEnvelopeDocGenFormFields = envelopesApi.UpdateEnvelopeDocGenFormFieldsWithHttpInfo(
    accountId,
    envelopeId,
    preparedFormFields);
updateEnvelopeDocGenFormFields.Headers.TryGetValue("X-RateLimit-Remaining", out remaining);
updateEnvelopeDocGenFormFields.Headers.TryGetValue("X-RateLimit-Reset", out reset);

if (reset != null && remaining != null)
{
    DateTime resetDate = DateTimeOffset.FromUnixTimeSeconds(long.Parse(reset)).UtcDateTime;
    Console.WriteLine("API calls remaining: " + remaining);
    Console.WriteLine("Next Reset: " + resetDate);
}

        public static DocGenFormFieldRequest FormFields(
string documentId,
string candidateName,
string managerName,
string jobTitle,
string salary,
string rsus,
string startDate)
        {
return new DocGenFormFieldRequest
{
    DocGenFormFields = new List<DocGenFormFields>
    {
        new DocGenFormFields
        {
            DocumentId = documentId,
            DocGenFormFieldList = new List<DocGenFormField>
            {
                new DocGenFormField
                {
                    Name = "Candidate_Name",
                    Value = candidateName,
                },
                new DocGenFormField
                {
                    Name = "Manager_Name",
                    Value = managerName,
                },
                new DocGenFormField
                {
                    Name = "Job_Title",
                    Value = jobTitle,
                },
                new DocGenFormField
                {
                    Name = "Start_Date",
                    Value = startDate,
                },
                new DocGenFormField
                {
                    Name = "Compensation_Package",
                    Type = "TableRow",
                    RowValues = new List<DocGenFormFieldRowValue>
                    {
                        new DocGenFormFieldRowValue
                        {
                            DocGenFormFieldList = new List<DocGenFormField>
                            {
                                new DocGenFormField
                                {
                                    Name = "Compensation_Component",
                                    Value = "Salary",
                                },
                                new DocGenFormField
                                {
                                    Name = "Details",
                                    Value = "$" + salary,
                                },
                            },
                        },
                        new DocGenFormFieldRowValue
                        {
                            DocGenFormFieldList = new List<DocGenFormField>
                            {
                                new DocGenFormField
                                {
                                    Name = "Compensation_Component",
                                    Value = "Bonus",
                                },
                                new DocGenFormField
                                {
                                    Name = "Details",
                                    Value = "20%",
                                },
                            },
                        },
                        new DocGenFormFieldRowValue
                        {
                            DocGenFormFieldList = new List<DocGenFormField>
                            {
                                new DocGenFormField
                                {
                                    Name = "Compensation_Component",
                                    Value = "RSUs",
                                },
                                new DocGenFormField
                                {
                                    Name = "Details",
                                    Value = rsus,
                                },
                            },
                        },
                    },
                },
            },
        },
    },
};
        }
```

**`Java`**

```java title="Java"
DocGenFormFieldRequest formFields = getFormFields(
        documentId,
        candidateName,
        managerName,
        jobTitle,
        salary,
        rsus,
        startDate);

var envelopeDocGenResponse = envelopesApi.updateEnvelopeDocGenFormFieldsWithHttpInfo(accountId, envelopeId,
        formFields, envelopesApi.new UpdateEnvelopeDocGenFormFieldsOptions());
headers = envelopeDocGenResponse.getHeaders();
remaining = headers.get("X-RateLimit-Remaining");
reset = headers.get("X-RateLimit-Reset");

if (remaining != null & reset != null) {
    Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0)));
    System.out.println("API calls remaining: " + remaining);
    System.out.println("Next Reset: " + resetInstant);
}
;
    private DocGenFormFieldRequest getFormFields(
    String documentId,
    String candidateName,
    String managerName,
    String jobTitle,
    String salary,
    String rsus,
    String startDate) {
DocGenFormField candidateNameField = new DocGenFormField();
candidateNameField.setName(CANDIDATE_NAME);
candidateNameField.setValue(candidateName);

DocGenFormField managerNameField = new DocGenFormField();
managerNameField.setName(MANAGER_NAME);
managerNameField.setValue(managerName);

DocGenFormField jobTitleField = new DocGenFormField();
jobTitleField.setName(JOB_TITLE);
jobTitleField.setValue(jobTitle);

DocGenFormField startDateField = new DocGenFormField();
startDateField.setName(START_DATE);
startDateField.setValue(startDate);

DocGenFormField compensationPackageField = new DocGenFormField();
compensationPackageField.setName(COMPENSATION_PACKAGE);
compensationPackageField.setType("TableRow");
compensationPackageField.setRowValues(Arrays.asList(
        new DocGenFormFieldRowValue()
                .docGenFormFieldList(Arrays.asList(
                        new DocGenFormField()
                                .name(COMPENSATION_COMPONENT)
                                .value(SALARY),
                        new DocGenFormField()
                                .name(DETAILS)
                                .value("$" + salary))),
        new DocGenFormFieldRowValue()
                .docGenFormFieldList(Arrays.asList(
                        new DocGenFormField()
                                .name(COMPENSATION_COMPONENT)
                                .value(BONUS),
                        new DocGenFormField()
                                .name(DETAILS)
                                .value("20%"))),
        new DocGenFormFieldRowValue()
                .docGenFormFieldList(Arrays.asList(
                        new DocGenFormField()
                                .name(COMPENSATION_COMPONENT)
                                .value(RSUS),
                        new DocGenFormField()
                                .name(DETAILS)
                                .value(rsus)))));

DocGenFormFields formFields = new DocGenFormFields();
formFields.setDocGenFormFieldList(Arrays.asList(
        candidateNameField,
        managerNameField,
        jobTitleField,
        startDateField,
        compensationPackageField));
formFields.setDocumentId(documentId);

DocGenFormFieldRequest docGenFormFieldRequest = new DocGenFormFieldRequest();
docGenFormFieldRequest.setDocGenFormFields(Collections.singletonList(formFields));

return docGenFormFieldRequest;
    }
```

**`Node.js`**

```javascript title="Node.js"
const formFieldsData = formFields(documentIdGuid, envelopeArgs);
await envelopesApi.updateEnvelopeDocGenFormFields(accountId, envelopeId, { docGenFormFieldRequest: formFieldsData }, (error, data, response) => {
    const headers = response?.headers;

    const remaining = headers?.['x-ratelimit-remaining'];
    const reset = headers?.['x-ratelimit-reset'];

    if (remaining && reset) {
      const resetInstant = new Date(Number(reset) * 1000);

      console.log(`API calls remaining: ${remaining}`);
      console.log(`Next Reset: ${resetInstant.toISOString()}`);
    }
});
const formFields = (documentId, args) => {
const bonusValue = '20%';
const docGenFormFieldRequest = {
  docGenFormFields: [
    {
      documentId: documentId,
      docGenFormFieldList: [
        docusign.DocGenFormField.constructFromObject({
          name: 'Candidate_Name',
          value: args.candidateName
        }),
        docusign.DocGenFormField.constructFromObject({
          name: 'Manager_Name',
          value: args.managerName
        }),
        docusign.DocGenFormField.constructFromObject({
          name: 'Job_Title',
          value: args.jobTitle
        }),
        docusign.DocGenFormField.constructFromObject({
          name: 'Start_Date',
          value: args.startDate
        }),
        docusign.DocGenFormField.constructFromObject({
          name: 'Compensation_Package',
          type: 'TableRow',
          rowValues: [
            docusign.DocGenFormFieldRowValue.constructFromObject({
              docGenFormFieldList: [
                docusign.DocGenFormField.constructFromObject({
                  name: 'Compensation_Component',
                  value: 'Salary'
                }),
                docusign.DocGenFormField.constructFromObject({
                  name: 'Details',
                  value: `$${args.salary}`
                })
              ]
            }),
            docusign.DocGenFormFieldRowValue.constructFromObject({
              docGenFormFieldList: [
                docusign.DocGenFormField.constructFromObject({
                  name: 'Compensation_Component',
                  value: 'Bonus'
                }),
                docusign.DocGenFormField.constructFromObject({
                  name: 'Details',
                  value: bonusValue
                })
              ]
            }),
            docusign.DocGenFormFieldRowValue.constructFromObject({
              docGenFormFieldList: [
                docusign.DocGenFormField.constructFromObject({
                  name: 'Compensation_Component',
                  value: 'RSUs'
                }),
                docusign.DocGenFormField.constructFromObject({
                  name: 'Details',
                  value: args.rsus
                })
              ]
            })
          ]
        })
      ]
    }
  ]
};

return docGenFormFieldRequest;
};
```

**`PHP`**

```php title="PHP"
$formFields = DocumentGenerationService::formFields($args["form_data"], $documentId);
$response = $envelopeApi->updateEnvelopeDocGenFormFieldsWithHttpInfo(
    $args['account_id'],
    $envelopeId,
    $formFields
);

$remaining = $response[2]['X-RateLimit-Remaining'] ?? null;
$reset = $response[2]['X-RateLimit-Reset'] ?? null;

if ($remaining !== null && $reset !== null) {
    $resetInstant = (new DateTime())->setTimestamp((int)$reset);
    error_log("API calls remaining: $remaining");
    error_log("Next Reset: " . $resetInstant->format(\DateTime::ATOM));
}
    public static function formFields(array $args, $documentId): DocGenFormFieldRequest
    {
return new DocGenFormFieldRequest(
    [
        'doc_gen_form_fields' => [
            new DocGenFormFields([
                'document_id' => $documentId,
                'doc_gen_form_field_list' => [
                    new DocGenFormField([
                        'name' => 'Candidate_Name',
                        'value' => $args['candidate_name']
                    ]),
                    new DocGenFormField([
                        'name' => 'Manager_Name',
                        'value' => $args['manager_name']
                    ]),
                    new DocGenFormField([
                        'name' => 'Job_Title',
                        'value' => $args['job_title']
                    ]),
                    new DocGenFormField([
                        'name' => 'Start_Date',
                        'value' => $args['start_date']
                    ]),
                    new DocGenFormField([
                        'name' => 'Compensation_Package',
                        'type' => 'TableRow',
                        'row_values' => [
                            new DocGenFormFieldRowValue([
                                'doc_gen_form_field_list' => [
                                    new DocGenFormField([
                                        'name' => 'Compensation_Component',
                                        'value' => 'Salary'
                                    ]),
                                    new DocGenFormField([
                                        'name' => 'Details',
                                        'value' => '$' . $args['salary']
                                    ])
                                ]
                            ]),
                            new DocGenFormFieldRowValue([
                                'doc_gen_form_field_list' => [
                                    new DocGenFormField([
                                        'name' => 'Compensation_Component',
                                        'value' => 'Bonus'
                                    ]),
                                    new DocGenFormField([
                                        'name' => 'Details',
                                        'value' => '20%'
                                    ])
                                ]
                            ]),
                            new DocGenFormFieldRowValue([
                                'doc_gen_form_field_list' => [
                                    new DocGenFormField([
                                        'name' => 'Compensation_Component',
                                        'value' => 'RSUs'
                                    ]),
                                    new DocGenFormField([
                                        'name' => 'Details',
                                        'value' => $args['rsus']
                                    ])
                                ]
                            ])
                        ]
                    ])
                ]
            ])
        ]
    ]
);
    }
```

**`PowerShell`**

```text title="PowerShell"
@{
    docGenFormFields = @(
      @{
        documentId = "${documentId}";
        docGenFormFieldList = @(
          @{
            name = "Candidate_Name";
            value = "${CandidateName}";
          };
          @{
            name = "Job_Title";
            value = "${JobTitle}";
          };
          @{
            name = "Manager_Name";
            value = "${ManagerName}";
          };
          @{
            name = "Start_Date";
            value = "${StartDate}";
          };
          @{
            name = "Compensation_Package";
            type = "TableRow";
            rowValues = @(
              @{
                docGenFormFieldList = @(
                  @{
                    name = "Compensation_Component";
                    value = "Salary";
                  };
                  @{
                    name = "Details";
                    value = "$" + "${Salary}";
                  }
                )
              };
              @{
                docGenFormFieldList = @(
                  @{
                    name = "Compensation_Component";
                    value = "Bonus";
                  };
                  @{
                    name = "Details";
                    value = "20%";
                  }
                )
              };
              @{
                docGenFormFieldList = @(
                  @{
                    name = "Compensation_Component";
                    value = "RSUs";
                  };
                  @{
                    name = "Details";
                    value = $rsus;
                  }
                )
              }
            )
          }
        )
      }
    )
} | ConvertTo-Json -Depth 32 > $requestData

Invoke-RestMethod `
    -Uri "${apiUri}/v2.1/accounts/${accountId}/envelopes/${envelopeId}/docgenformfields" `
    -Method 'PUT' `
    -Headers @{
    'Authorization' = "Bearer $accessToken";
    'Content-Type'  = "application/json";
} `
    -InFile (Resolve-Path $requestData).Path  `
    -OutFile $response
```

**`Python`**

```python title="Python"
form_fields = cls.form_fields(envelope_args, document_id_guid)
(response, status, headers) = envelopes_api.update_envelope_doc_gen_form_fields_with_http_info(
    account_id,
    envelope_id,
    doc_gen_form_field_request=form_fields
)

remaining = headers.get("X-RateLimit-Remaining")
reset = headers.get("X-RateLimit-Reset")

if remaining is not None and reset is not None:
    reset_date = dt.fromtimestamp(int(reset), tz=timezone.utc)
    print(f"API calls remaining: {remaining}")
    print(f"Next Reset: {reset_date}")
    @classmethod
    def form_fields(cls, args, document_id_guid):
bonus_value = "20%"
doc_gen_form_field_request = DocGenFormFieldRequest(
    doc_gen_form_fields=[
        DocGenFormFields(
            document_id=document_id_guid,
            doc_gen_form_field_list=[
                DocGenFormField(
                    name="Candidate_Name",
                    value=args["candidate_name"]
                ),
                DocGenFormField(
                    name="Manager_Name",
                    value=args["manager_name"]
                ),
                DocGenFormField(
                    name="Job_Title",
                    value=args["job_title"]
                ),
                DocGenFormField(
                    name="Start_Date",
                    value=args["start_date"]
                ),
                DocGenFormField(
                    name="Compensation_Package",
                    type="TableRow",
                    row_values=[
                        DocGenFormFieldRowValue(
                            doc_gen_form_field_list=[
                                DocGenFormField(
                                    name="Compensation_Component",
                                    value="Salary"
                                ),
                                DocGenFormField(
                                    name="Details",
                                    value=f"${args['salary']}"
                                )
                            ]
                        ),
                        DocGenFormFieldRowValue(
                            doc_gen_form_field_list=[
                                DocGenFormField(
                                    name="Compensation_Component",
                                    value="Bonus"
                                ),
                                DocGenFormField(
                                    name="Details",
                                    value=bonus_value
                                )
                            ]
                        ),
                        DocGenFormFieldRowValue(
                            doc_gen_form_field_list=[
                                DocGenFormField(
                                    name="Compensation_Component",
                                    value="RSUs"
                                ),
                                DocGenFormField(
                                    name="Details",
                                    value=args["rsus"]
                                )
                            ]
                        )
                    ]
                )
            ]
        )
    ]
)
return doc_gen_form_field_request
```

**`Ruby`**

```ruby title="Ruby"
form_fields_request = form_fields(envelope_args, document_id_guid)
_results, _status, headers = envelope_api.update_envelope_doc_gen_form_fields_with_http_info(
  account_id,
  envelope_id,
  form_fields_request
)

remaining = headers['X-RateLimit-Remaining']
reset = headers['X-RateLimit-Reset']

if remaining && reset
  reset_date = Time.at(reset.to_i).utc
  puts "API calls remaining: #{remaining}"
  puts "Next Reset: #{reset_date}"
end
  def form_fields(args, document_id_guid)
bonus_value = '20%'

candidate_name_field = DocuSign_eSign::DocGenFormField.new(
  name: 'Candidate_Name',
  value: args[:candidate_name]
)
manager_name_field = DocuSign_eSign::DocGenFormField.new(
  name: 'Manager_Name',
  value: args[:manager_name]
)
job_title_field = DocuSign_eSign::DocGenFormField.new(
  name: 'Job_Title',
  value: args[:job_title]
)
start_date_field = DocuSign_eSign::DocGenFormField.new(
  name: 'Start_Date',
  value: args[:start_date]
)

salary_row = DocuSign_eSign::DocGenFormFieldRowValue.new(
  docGenFormFieldList: [
    DocuSign_eSign::DocGenFormField.new(
      name: 'Compensation_Component',
      value: 'Salary'
    ),
    DocuSign_eSign::DocGenFormField.new(
      name: 'Details',
      value: "$#{args[:salary]}"
    )
  ]
)
bonus_row = DocuSign_eSign::DocGenFormFieldRowValue.new(
  docGenFormFieldList: [
    DocuSign_eSign::DocGenFormField.new(
      name: 'Compensation_Component',
      value: 'Bonus'
    ),
    DocuSign_eSign::DocGenFormField.new(
      name: 'Details',
      value: bonus_value
    )
  ]
)
rsus_row = DocuSign_eSign::DocGenFormFieldRowValue.new(
  docGenFormFieldList: [
    DocuSign_eSign::DocGenFormField.new(
      name: 'Compensation_Component',
      value: 'RSUs'
    ),
    DocuSign_eSign::DocGenFormField.new(
      name: 'Details',
      value: args[:rsus]
    )
  ]
)
compensation_package = DocuSign_eSign::DocGenFormField.new(
  name: 'Compensation_Package',
  type: 'TableRow',
  rowValues: [salary_row, bonus_row, rsus_row]
)
doc_gen_form_fields_list = [
  candidate_name_field, manager_name_field, job_title_field, start_date_field, compensation_package
]

doc_gen_form_fields = DocuSign_eSign::DocGenFormFields.new(
  documentId: document_id_guid,
  docGenFormFieldList: doc_gen_form_fields_list
)

DocuSign_eSign::DocGenFormFieldRequest.new(
  docGenFormFields: [doc_gen_form_fields]
)
  end
```

## Step 8. Send the envelope with the eSignature REST API

Send the envelope by setting the status to `sent` using the [Envelopes:update](/docs/esign-rest-api/reference/envelopes/envelopes/update) method.

> **Note**
>
> View the source code for this how-to on GitHub: [Bash](https://github.com/docusign/code-examples-bash/blob/master/examples/eSignature/eg042DocumentGeneration.sh/), [C#](https://github.com/docusign/code-examples-csharp/blob/master/launcher-csharp/eSignature/Examples/DocumentGeneration.cs/), [Java](https://github.com/docusign/code-examples-java/tree/master/src/main/java/com/docusign/controller/eSignature/services/DocumentGenerationService.java/), [Node.js](https://github.com/docusign/code-examples-node/blob/master/lib/eSignature/examples/documentGeneration.js/), [PHP](https://github.com/docusign/code-examples-php/blob/master/src/Services/Examples/eSignature/DocumentGenerationService.php/), [Powershell](https://github.com/docusign/code-examples-powershell/blob/master/examples/eSignature/eg042DocumentGeneration.ps1/), [Python](https://github.com/docusign/code-examples-python/blob/master/app/eSignature/examples/eg042_document_generation.py/), or [Ruby](https://github.com/docusign/code-examples-ruby/blob/master/app/services/e_sign/eg042_document_generation_service.rb/).

**`Bash`**

```bash title="Bash"
printf \
'{
    "status": "sent"
}' >> $request_data

Status=$(curl --header "Authorization: Bearer ${ACCESS_TOKEN}" \
  --header "Content-Type: application/json" \
  --data-binary @${request_data} \
  --request PUT ${base_path}/v2.1/accounts/${account_id}/envelopes/${envelope_id} \
  --output ${response})
```

**`C#`**

```csharp title="C#"
var envelopeWithDocGen = envelopesApi.UpdateWithHttpInfo(
    accountId,
    envelopeId,
    new Envelope
    {
        Status = "sent",
    });
envelopeWithDocGen.Headers.TryGetValue("X-RateLimit-Remaining", out remaining);
envelopeWithDocGen.Headers.TryGetValue("X-RateLimit-Reset", out reset);

if (reset != null && remaining != null)
{
    DateTime resetDate = DateTimeOffset.FromUnixTimeSeconds(long.Parse(reset)).UtcDateTime;
    Console.WriteLine("API calls remaining: " + remaining);
    Console.WriteLine("Next Reset: " + resetDate);
}
```

**`Java`**

```java title="Java"
Envelope envelope = new Envelope();
envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT);

var envelopeUpdateSummary = envelopesApi.updateWithHttpInfo(accountId, envelopeId, envelope,
        envelopesApi.new UpdateOptions());
headers = envelopeUpdateSummary.getHeaders();
remaining = headers.get("X-RateLimit-Remaining");
reset = headers.get("X-RateLimit-Reset");

if (remaining != null & reset != null) {
    Instant resetInstant = Instant.ofEpochSecond(Long.parseLong(reset.get(0)));
    System.out.println("API calls remaining: " + remaining);
    System.out.println("Next Reset: " + resetInstant);
}
;
```

**`Node.js`**

```javascript title="Node.js"
const sendEnvelopeReq = docusign.Envelope.constructFromObject({
  status: 'sent',
});
response = await envelopesApi.update(accountId, envelopeId, { envelope: sendEnvelopeReq }, (error, data, response) => {
    const headers = response?.headers;

    const remaining = headers?.['x-ratelimit-remaining'];
    const reset = headers?.['x-ratelimit-reset'];

    if (remaining && reset) {
      const resetInstant = new Date(Number(reset) * 1000);

      console.log(`API calls remaining: ${remaining}`);
      console.log(`Next Reset: ${resetInstant.toISOString()}`);
    }
});
return response.data;
```

**`PHP`**

```php title="PHP"
$envelopeResponse = $envelopeApi->updateWithHttpInfo(
    $args['account_id'],
    $envelopeId,
    new Envelope([
        'status' => 'sent'
    ])
);

$remaining = $envelopeResponse[2]['X-RateLimit-Remaining'] ?? null;
$reset = $envelopeResponse[2]['X-RateLimit-Reset'] ?? null;

if ($remaining !== null && $reset !== null) {
    $resetInstant = (new DateTime())->setTimestamp((int)$reset);
    error_log("API calls remaining: $remaining");
    error_log("Next Reset: " . $resetInstant->format(\DateTime::ATOM));
}
```

**`PowerShell`**

```text title="PowerShell"
@{
    status = "sent";
} | ConvertTo-Json -Depth 32 > $requestData

Invoke-RestMethod `
    -Uri "${apiUri}/v2.1/accounts/${accountId}/envelopes/${envelopeId}/" `
    -Method 'PUT' `
    -Headers @{
    'Authorization' = "Bearer $accessToken";
    'Content-Type'  = "application/json";
} `
    -InFile (Resolve-Path $requestData).Path  `
    -OutFile $response
```

**`Python`**

```python title="Python"
send_envelope_req = Envelope(status="sent")
(envelope, status, headers) = envelopes_api.update_with_http_info(account_id, envelope_id, envelope=send_envelope_req)

remaining = headers.get("X-RateLimit-Remaining")
reset = headers.get("X-RateLimit-Reset")

if remaining is not None and reset is not None:
    reset_date = dt.fromtimestamp(int(reset), tz=timezone.utc)
    print(f"API calls remaining: {remaining}")
    print(f"Next Reset: {reset_date}")
```

**`Ruby`**

```ruby title="Ruby"
send_envelope_req = DocuSign_eSign::Envelope.new(status: 'sent')
envelope, _status, headers = envelope_api.update_with_http_info(account_id, envelope_id, send_envelope_req)

remaining = headers['X-RateLimit-Remaining']
reset = headers['X-RateLimit-Reset']

if remaining && reset
  reset_date = Time.at(reset.to_i).utc
  puts "API calls remaining: #{remaining}"
  puts "Next Reset: #{reset_date}"
end
```

## Expected response

If you run this code example from our Quickstart or launcher projects, you should see a JSON response similar to the code shown.

In addition, the signer receives an email containing a signing link that they can use to open and electronically sign a document using the Docusign mobile app or the Docusign website. After signing is complete, the recipient receives a carbon copy (CC) of the email that includes all of the completed and signed documents.

**`Sample response`**

```json title="Sample response"
{"envelopeId":"6d6fc561-xxxx-xxxx-xxxx-901a1b4b92a4"}
```

## Next steps

* Run this code example from our [Quickstart](/docs/esign-rest-api/quickstart) or launcher projects:    [Bash](https://github.com/docusign/code-examples-bash), [C#](https://github.com/docusign/code-examples-csharp), [Java](https://github.com/docusign/code-examples-java), [Node.js](https://github.com/docusign/code-examples-node), [PHP](https://github.com/docusign/code-examples-php), [PowerShell](https://github.com/docusign/code-examples-powershell), [Python](https://github.com/docusign/code-examples-python), or [Ruby](https://github.com/docusign/code-examples-ruby).
* Learn more about [Document generation](/docs/esign-rest-api/esign101/concepts/documents/document-generation).
* Find out more about [Document Generation Syntax](https://support.docusign.com/s/document-item?bundleId=als1679428547895\&topicId=ftc1679700030026.html).
* See [Document Generation for Docusign eSignature](https://support.docusign.com/s/document-item?bundleId=als1679428547895\&topicId=ldx1679428689631.html) in the eSignature User Guide for general information about the feature, including use cases.
* See how to [Go-Live](/docs/esign-rest-api/go-live) with a completed app and find the base path for API calls in the production environment.