> 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 set document visibility for envelope recipients

> This topic demonstrates how to set document visibility for envelope recipients. Document visibility allows senders to control which documents each recipient can see in an envelope with multiple documents.

> **Note**
>
> The document visibility feature is available in all developer accounts, but only in certain production account plans. Contact [Docusign Support](https://support.docusign.com/s/contactSupport) or your account manager to find out whether document visibility is available for your production account plan.

This topic demonstrates how to set [document visibility](https://support.docusign.com/s/document-item?bundleId=gbo1643332197980\&topicId=eui1578456411411.html) for envelope recipients. Document visibility allows senders to control which documents each recipient can see in an envelope with multiple documents.

**Note:** A document cannot be hidden from a recipient if the recipient has tabs assigned to them on the document. Carbon Copy, Certified Delivery (Needs to Sign), Editor, and Agent recipients can always see all documents, unless they are specifically excluded using the `excludedDocuments` property when an envelope is sent.

**Important:** You must enable document visibility in your account to complete this how-to:

1. In production, enable the **Allow sender to specify document visibility** parameter in the Sending Settings. This parameter is not displayed in the developer environment Sending Settings, because the feature is enabled on that environment by default.
2. In both production and the developer environment, set the **Document Visibility** parameter in the [Sending Settings](https://admindemo.docusign.com/authenticate?goTo=sending) to any value except **Off**.

See the **Document Visibility** section in [Fields and Properties](https://support.docusign.com/s/document-item?rsc_301\&bundleId=pik1583277475390\&topicId=xgg1583277350154.html) for details about document visibility options.

![Access document visibility settings from Sending Settings in Docusign eSignature.](/_fern-files/_img/61bfb997cc7f73702e93aa129abf9ba1013d73114736b7f58a3c66137dc4b1c4.webp)

> **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.                                                                                                                                        |
| \{CC_RECIPIENT_EMAIL}  | A string value for the email address of the carbon copy recipient.                                                                                                                                                                                                                                                                                                                                                                                            |
| \{CC_RECIPIENT_NAME}   | A string value for the name of the carbon copy recipient.                                                                                                                                                                                                                                                                                                                                                                                                     |
| Documents to be signed | You must provide at least one document to be signed. Documents used in this how-to:- [DOCX file](https://github.com/docusign/code-examples-java/blob/master/src/main/resources/World_Wide_Corp_Battle_Plan_Trafalgar.docx)
- [PDF file](https://github.com/docusign/code-examples-java/blob/master/src/main/resources/World_Wide_Corp_lorem.pdf)
- [HTML file](https://github.com/docusign/code-examples-java/blob/master/src/main/resources/order_form.html) |
| \{SIGNER1_EMAIL}       | A string value for the email address where the first signer will receive a notification of the signing request.                                                                                                                                                                                                                                                                                                                                               |
| \{SIGNER2_EMAIL}       | A string value for the email address where the second signer will receive a notification of the signing request.                                                                                                                                                                                                                                                                                                                                              |
| \{SIGNER1_NAME}        | A string value for the full name of the first signer.                                                                                                                                                                                                                                                                                                                                                                                                         |
| \{SIGNER2_NAME}        | A string value for the full name of the second signer.                                                                                                                                                                                                                                                                                                                                                                                                        |

## Step 1. Obtain your OAuth token

To make the API call 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. Construct your API headers

After you have a valid OAuth access token, you are ready to construct the API headers that you will pass to the API call. Construct your headers like this, but make sure to substitute your valid OAuth access token for \{ACCESS_TOKEN}.

**`Bash`**

```bash title="Bash"
declare -a Headers=('--header' "Authorization: Bearer ${ACCESS_TOKEN}"
    '--header' "Accept: application/json"
    '--header' "Content-Type: application/json")
```

**`C#`**

```csharp title="C#"
var docuSignClient = new DocuSignClient(basePath);
docuSignClient.Configuration.DefaultHeader.Add("Authorization", "Bearer " + accessToken);

EnvelopesApi envelopesApi = new EnvelopesApi(docuSignClient);
```

**`Java`**

```java title="Java"
ApiClient apiClient = createApiClient(basePath, accessToken);
EnvelopesApi envelopesApi = new EnvelopesApi(apiClient);
```

**`Node.js`**

```javascript title="Node.js"
const dsApiClient = new docusign.ApiClient();

dsApiClient.setBasePath(args.basePath);
dsApiClient.addDefaultHeader('Authorization', 'Bearer ' + args.accessToken);
```

**`PHP`**

```php title="PHP"
$config = new Configuration();
$config->setHost($args['base_path']);
$config->addDefaultHeader('Authorization', 'Bearer ' . $args['ds_access_token']);
$this->apiClient = new ApiClient($config);
```

**`PowerShell`**

```text title="PowerShell"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.add("Authorization", "Bearer $accessToken")
$headers.add("Content-Type", "application/json")
```

**`Python`**

```python title="Python"
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])
```

**`Ruby`**

```ruby title="Ruby"
configuration = DocuSign_eSign::Configuration.new
configuration.host = args[:base_path]
api_client = DocuSign_eSign::ApiClient.new configuration

api_client.default_headers['Authorization'] = "Bearer #{args[:access_token]}"
```

## Step 3. Construct the request body

Next, create the request body. To create an envelope using the eSignature REST API, you need to construct an envelope body in JSON format. Replace \{CC_EMAIL}, \{CC_NAME}, \{SIGNER1_EMAIL}, \{SIGNER1_NAME}, \{SIGNER2_EMAIL}, and \{SIGNER2_NAME} with your recipients’ data in the JSON request body.

Include the `enforceSignerVisibility` property set to `true`. This enforces the option selected in the **Document Visibility** section in your account [Sending Settings](https://admindemo.docusign.com/authenticate?goTo=sending) for the envelope. When `enforceSignerVisibility` is set to `true`, you can also override the selected **Document Visibility** option for specific recipients by omitting documents from their envelopes. To omit documents for a recipient, set `excludedDocuments` to an array of the user-defined document IDs that should be hidden from the recipient when they receive the envelope.

**`Bash`**

```bash title="Bash"
printf \
'{
    "emailSubject": "Please sign this document set",
    "enforceSignerVisibility": "true",
    "documents": [
        {
            "documentBase64": "' > $request_data
            cat $doc1_base64 >> $request_data
            printf '",
            "name": "Order acknowledgement",
            "fileExtension": "html",
            "documentId": "1"
        },
        {
            "documentBase64": "' >> $request_data
            cat $doc2_base64 >> $request_data
            printf '",
            "name": "Battle Plan",
            "fileExtension": "docx",
            "documentId": "2"
        },
        {
            "documentBase64": "' >> $request_data
            cat $doc3_base64 >> $request_data
            printf '",
            "name": "Lorem Ipsum",
            "fileExtension": "pdf",
            "documentId": "3"
        }
    ],
    "recipients": {
        "carbonCopies": [
            {
                "email": "'"${CC_EMAIL}"'",
                "name": "'"${CC_NAME}"'",
                "recipientId": "3",
                "routingOrder": "2"
            }
        ],
        "signers": [
            {
                "email": "'"${SIGNER1_EMAIL}"'",
                "name": "'"${SIGNER1_NAME}"'",
                "recipientId": "1",
                "routingOrder": "1",
                "excludedDocuments": [2, 3],
                "tabs": {
                    "signHereTabs": [
                        {
                            "anchorString": "**signature_1**",
                            "anchorUnits": "pixels",
                            "anchorXOffset": "20",
                            "anchorYOffset": "10"
                        }
                    ]
                }
            },
            {
                "email": "'"${SIGNER2_EMAIL}"'",
                "name": "'"${SIGNER2_NAME}"'",
                "recipientId": "2",
                "routingOrder": "1",
                "excludedDocuments": [1],
                "tabs": {
                    "signHereTabs": [
                        {
                            "anchorString": "/sn1/",
                            "anchorUnits": "pixels",
                            "anchorXOffset": "20",
                            "anchorYOffset": "10"
                        }
                    ]
                }
            }
        ]
    },
    "status": "sent"
}' >> $request_data
```

**`C#`**

```csharp title="C#"
private static EnvelopeDefinition PrepareEnvelope(
    string signer1Email,
    string signer1Name,
    string signer2Email,
    string signer2Name,
    string ccEmail,
    string ccName,
    string docPdf,
    string docDocx,
    string docHtml)
{
    EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition
    {
        EmailSubject = "Please sign this document set",
        Documents = PrepareDocumentsForTemplate(
            signer1Email,
            signer1Name,
            ccEmail,
            ccName,
            docPdf,
            docDocx,
            docHtml),
        EnforceSignerVisibility = "true",
    };

    Signer signer1 = PrepareSigner(
        signer1Email,
        signer1Name,
        "1",
        "1",
        new List<string> { "2", "3" },
        "**signature_1**",
        "pixels",
        "20",
        "10");
    Signer signer2 = PrepareSigner(
        signer2Email,
        signer2Name,
        "2",
        "1",
        new List<string> { "1" },
        "/sn1/",
        "pixels",
        "20",
        "10");

    CarbonCopy carbonCopy = new CarbonCopy
    {
        Email = ccEmail,
        Name = ccName,
        RecipientId = "3",
        RoutingOrder = "2",
    };

    envelopeDefinition.Recipients = new Recipients
    {
        CarbonCopies = new List<CarbonCopy> { carbonCopy },
        Signers = new List<Signer> { signer1, signer2, },
    };

    envelopeDefinition.Status = "sent";

    return envelopeDefinition;
}

private static Signer PrepareSigner(
    string signerEmail,
    string signerName,
    string recipientId,
    string routingOrder,
    List<string> excludedDocuments,
    string tabsAnchorString,
    string tabsAnchorUnits,
    string tabsAnchorXOffset,
    string tabsAnchorYOffset)
{
    return new Signer
    {
        Email = signerEmail,
        Name = signerName,
        RecipientId = recipientId,
        RoutingOrder = routingOrder,
        ExcludedDocuments = excludedDocuments,
        Tabs = new Tabs
        {
            SignHereTabs = new List<SignHere>
            {
                new SignHere
                {
                    AnchorString = tabsAnchorString,
                    AnchorUnits = tabsAnchorUnits,
                    AnchorXOffset = tabsAnchorXOffset,
                    AnchorYOffset = tabsAnchorYOffset,
                },
            },
        },
    };
}

private static List<Document> PrepareDocumentsForTemplate(
    string signer1Email,
    string signer1Name,
    string ccEmail,
    string ccName,
    string docPdf,
    string docDocx,
    string docHtml)
{
    byte[] pdfFileContentInBytes = System.IO.File.ReadAllBytes(docPdf);
    byte[] docxFileContentInBytes = System.IO.File.ReadAllBytes(docDocx);

    string htmlFileContentsString = System.IO.File.ReadAllText(docHtml);
    htmlFileContentsString = htmlFileContentsString.Replace("{USER_EMAIL}", signer1Email);
    htmlFileContentsString = htmlFileContentsString.Replace("{USER_FULLNAME}", signer1Name);
    htmlFileContentsString = htmlFileContentsString.Replace("{CC_EMAIL}", ccEmail);
    htmlFileContentsString = htmlFileContentsString.Replace("{CC_NAME}", ccName);
    byte[] htlmFileContentInBytes = System.Text.Encoding.UTF8.GetBytes(htmlFileContentsString);

    return new List<Document>
    {
        new Document
        {
            DocumentBase64 = Convert.ToBase64String(htlmFileContentInBytes),
            Name = "Order acknowledgement",
            FileExtension = "html",
            DocumentId = "1",
        },
        new Document
        {
            DocumentBase64 = Convert.ToBase64String(docxFileContentInBytes),
            Name = "Battle Plan",
            FileExtension = "docx",
            DocumentId = "2",
        },
        new Document
        {
            DocumentBase64 = Convert.ToBase64String(pdfFileContentInBytes),
            Name = "Lorem Ipsum",
            FileExtension = "pdf",
            DocumentId = "3",
        },
    };
}
```

**`Java`**

```java title="Java"
public static EnvelopeDefinition makeEnvelope(
        String signerEmail,
        String signerName,
        String signerEmail2,
        String signerName2,
        String ccEmail,
        String ccName,
        String documentFileNamePDF,
        String documentFileNameDOCX,
        String documentFileNameHTML
) throws IOException {
    CarbonCopy carbonCopy = new CarbonCopy();

    carbonCopy.setEmail(ccEmail);
    carbonCopy.setName(ccName);
    carbonCopy.setRecipientId("3");
    carbonCopy.setRoutingOrder("2");

    Recipients recipients = new Recipients();
    recipients.setSigners(Arrays.asList(prepareSigners(signerEmail, signerName, signerEmail2, signerName2)));
    recipients.setCarbonCopies(Collections.singletonList(carbonCopy));

    EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition();
    envelopeDefinition.setEnforceSignerVisibility("true");
    envelopeDefinition.setEmailSubject("Please sign this document set");
    envelopeDefinition.setRecipients(recipients);

    envelopeDefinition.setDocuments(Arrays.asList(prepareDocumentsForSending(
            signerEmail,
            signerName,
            ccEmail,
            ccName,
            documentFileNamePDF,
            documentFileNameDOCX,
            documentFileNameHTML)));

    envelopeDefinition.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT);

    return envelopeDefinition;
}

private static Signer[] prepareSigners(
        String signerEmail,
        String signerName,
        String signerEmail2,
        String signerName2) {
    Signer signer1 = new Signer();

    signer1.setEmail(signerEmail);
    signer1.setName(signerName);
    signer1.setRecipientId("1");
    signer1.setRoutingOrder("1");
    signer1.setExcludedDocuments(Arrays.asList("2", "3"));
    signer1.setTabs(EnvelopeHelpers.createSingleSignerTab("**signature_1**", 10, 20));

    Signer signer2 = new Signer();

    signer2.setEmail(signerEmail2);
    signer2.setName(signerName2);
    signer2.setRecipientId("2");
    signer2.setRoutingOrder("1");
    signer2.setExcludedDocuments(Arrays.asList("1"));
    signer2.setTabs(EnvelopeHelpers.createSingleSignerTab("/sn1/", 10, 20));

    return new Signer[]{signer1, signer2};
}

private static Document[] prepareDocumentsForSending(
        String signerEmail,
        String signerName,
        String ccEmail,
        String ccName,
        String documentFileNamePDF,
        String documentFileNameDOCX,
        String documentFileNameHTML) throws IOException {
    ClassPathResource resource = new ClassPathResource(documentFileNameHTML);
    String documentHTMLContentsString = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
    documentHTMLContentsString = documentHTMLContentsString.replace("{USER_EMAIL}", signerEmail);
    documentHTMLContentsString = documentHTMLContentsString.replace("{USER_FULLNAME}", signerName);
    documentHTMLContentsString = documentHTMLContentsString.replace("{CC_EMAIL}", ccEmail);
    documentHTMLContentsString = documentHTMLContentsString.replace("{CC_NAME}", ccName);
    byte[] documentHTMLContentsBytes = documentHTMLContentsString.getBytes(StandardCharsets.UTF_8);
    String extension = FilenameUtils.getExtension(documentFileNameHTML);

    Document documentHTML = EnvelopeHelpers.createDocument(
            documentHTMLContentsBytes,
            "Order acknowledgement",
            extension,
            "1");

    Document documentDOCX = EnvelopeHelpers.createDocumentFromFile(
            documentFileNameDOCX,
            "Battle Plan",
            "2");

    Document documentPDF = EnvelopeHelpers.createDocumentFromFile(
            documentFileNamePDF,
            "Lorem Ipsum",
            "3");

    return new Document[]{documentHTML, documentDOCX, documentPDF};
}
```

**`Node.js`**

```javascript title="Node.js"
function makeEnvelope(args) {
  /**
   * document 1 (html) has tag **signature_1**
   * document 2 (docx) has tag /sn1/
   * document 3 (pdf) has tag /sn1/
   *
   * The envelope has two recipients.
   * recipient 1 - signer 1
   * recipient 2 - signer 2
   * recipient 3 - cc
   * The envelope will be sent first to the signer 1 and then to signer 2.
   * After it is signed, a copy is sent to the cc person.
   */

  let doc2DocxBytes, doc3PdfBytes;
  // read files from a local directory
  // The reads could raise an exception if the file is not available!
  doc2DocxBytes = fs.readFileSync(args.doc2File);
  doc3PdfBytes = fs.readFileSync(args.doc3File);

  // create the envelope definition
  let env = new docusign.EnvelopeDefinition();
  env.emailSubject = 'Please sign this document set';
  env.enforceSignerVisibility = 'true';

  // add the documents
  const doc1b64 = Buffer.from(document1(args)).toString('base64');
    const doc2b64 = Buffer.from(doc2DocxBytes).toString('base64');
    const doc3b64 = Buffer.from(doc3PdfBytes).toString('base64');

  const doc1 = new docusign.Document.constructFromObject({
    documentBase64: doc1b64,
    name: 'Order acknowledgement', // can be different from actual file name
    fileExtension: 'html', // Source data format. Signed docs are always pdf.
    documentId: '1', // a label used to reference the doc
  });

  // Alternate pattern: using constructors for docs 2 and 3...
  const doc2 = new docusign.Document.constructFromObject({
    documentBase64: doc2b64,
    name: 'Battle Plan', // can be different from actual file name
    fileExtension: 'docx',
    documentId: '2',
  });

  const doc3 = new docusign.Document.constructFromObject({
    documentBase64: doc3b64,
    name: 'Lorem Ipsum', // can be different from actual file name
    fileExtension: 'pdf',
    documentId: '3',
  });

  // The order in the docs array determines the order in the envelope
  env.documents = [doc1, doc2, doc3];

  /**
   * Create signHere fields (also known as tabs) on the documents,
   * We're using anchor (autoPlace) positioning
   *
   * The DocuSign platform searches throughout your envelope's
   * documents for matching anchor strings. So the
   * signHere2 tab will be used in both document 2 and 3 since they
   * use the same anchor string for their "signer 1" tabs.
   */
  const signHere1 = docusign.SignHere.constructFromObject({
    anchorString: '**signature_1**',
    anchorYOffset: '10',
    anchorUnits: 'pixels',
    anchorXOffset: '20',
  });
  const signHere2 = docusign.SignHere.constructFromObject({
    anchorString: '/sn1/',
    anchorYOffset: '10',
    anchorUnits: 'pixels',
    anchorXOffset: '20',
  });

  // Tabs are set per recipient / signer
  const signer1Tabs = docusign.Tabs.constructFromObject({
    signHereTabs: [signHere1],
  });

  const signer2Tabs = docusign.Tabs.constructFromObject({
    signHereTabs: [signHere2],
  });

  // create a signer recipient to sign the document, identified by name and email
  // We're setting the parameters via the object constructor
  const signer1 = docusign.Signer.constructFromObject({
    email: args.signer1Email,
    name: args.signer1Name,
    recipientId: '1',
    routingOrder: '1',
    excludedDocuments: [2, 3],
    tabs: signer1Tabs,
  });

  const signer2 = docusign.Signer.constructFromObject({
    email: args.signer2Email,
    name: args.signer2Name,
    recipientId: '2',
    routingOrder: '2',
    excludedDocuments: [1],
    tabs: signer2Tabs,
  });

  /**
   * routingOrder (lower means earlier) determines the order of deliveries
   * to the recipients. Parallel routing order is supported by using the
   * same integer as the order for two or more recipients.
   * create a cc recipient to receive a copy of the documents, identified by name and email
   * We're setting the parameters via setters
   */
  const cc = new docusign.CarbonCopy.constructFromObject({
    email: args.ccEmail,
    name: args.ccName,
    routingOrder: '3',
    recipientId: '3',
  });

  // Add the recipients to the envelope object
  const recipients = docusign.Recipients.constructFromObject({
    signers: [signer1, signer2],
    carbonCopies: [cc],
  });
  env.recipients = recipients;

  // Request that the envelope be sent by setting |status| to "sent".
  // To request that the envelope be created as a draft, set to "created"
  env.status = args.status;

  return env;
}

/**
 * Creates document 1
 * @function
 * @private
 * @param {object} args parameters for the envelope
 * @param {string} args.signer1Email The email of first signer
 * @param {string} args.signer1Name The name of first signer
 * @param {string} args.ccEmail The email of cc recipient
 * @param {string} args.ccName The name of cc recipient
 * @returns {string} A document in HTML format
 */

function document1(args) {
  return `
    <!DOCTYPE html>
    <html>
        <head>
          <meta charset="UTF-8">
        </head>
        <body style="font-family:sans-serif;margin-left:2em;">
        <h1 style="font-family: 'Trebuchet MS', Helvetica, sans-serif;
            color: darkblue;margin-bottom: 0;">World Wide Corp</h1>
        <h2 style="font-family: 'Trebuchet MS', Helvetica, sans-serif;
          margin-top: 0px;margin-bottom: 3.5em;font-size: 1em;
          color: darkblue;">Order Processing Division</h2>
        <h4>Ordered by ${args.signer1Name}</h4>
        <p style="margin-top:0em; margin-bottom:0em;">Email: ${args.signer1Email}</p>
        <p style="margin-top:0em; margin-bottom:0em;">Copy to: ${args.ccName}, ${args.ccEmail}</p>
        <p style="margin-top:3em;">
  Candy bonbon pastry jujubes lollipop wafer biscuit biscuit. Topping brownie sesame snaps sweet roll pie. Croissant danish biscuit soufflé caramels jujubes jelly. Dragée danish caramels lemon drops dragée. Gummi bears cupcake biscuit tiramisu sugar plum pastry. Dragée gummies applicake pudding liquorice. Donut jujubes oat cake jelly-o. Dessert bear claw chocolate cake gummies lollipop sugar plum ice cream gummies cheesecake.
        </p>
        <!-- Note the anchor tag for the signature field is in white. -->
        <h3 style="margin-top:3em;">Agreed: <span style="color:white;">**signature_1**/</span></h3>
        </body>
    </html>
  `;
}
```

**`PHP`**

```php title="PHP"
private static function makeEnvelope(
    string $signer1Email,
    string $signer1Name,
    string $signer2Email,
    string $signer2Name,
    string $ccEmail,
    string $ccName,
    string $docPdf,
    string $docDocx,
    string $docHTML,
    string $demoPath
): EnvelopeDefinition {
    $carbonCopy = new CarbonCopy(
        [
            'email' => $ccEmail,
            'name' => $ccName,
            'recipient_id' => "3",
            'routing_order' => "2",
        ]
    );

    $envelope_definition = new EnvelopeDefinition(
        [
            'enforce_signer_visibility' => 'true',
            'email_subject' => "Please sign this document set",
            'documents' => SetDocumentsVisibilityService::_prepareDocuments(
                $signer1Email,
                $signer1Name,
                $ccEmail,
                $ccName,
                $docPdf,
                $docDocx,
                $docHTML,
                $demoPath
            ),
            'recipients' => new Recipients(
                [
                    'signers' => SetDocumentsVisibilityService::_prepareSigners(
                        $signer1Email,
                        $signer1Name,
                        $signer2Email,
                        $signer2Name
                    ),
                    'carbon_copies' => [$carbonCopy]
                ]
            ),
            'status' => "sent"
        ]
    );

    return $envelope_definition;
}

private static function _prepareSigners(
    string $signer1Email,
    string $signer1Name,
    string $signer2Email,
    string $signer2Name
): array {
    $signer1 = new Signer(
        [
            'email' => $signer1Email,
            'name' => $signer1Name,
            'recipient_id' => "1",
            'routing_order' => "1",
            'excluded_documents' => ["2", "3"],
            'tabs' => new Tabs(
                [
                    'sign_here_tabs' =>  [
                        new SignHere(
                            [
                                'anchor_string' => '**signature_1**',
                                'anchor_units' => 'pixels',
                                'anchor_y_offset' => '10',
                                'anchor_x_offset' => '20'
                            ]
                        )
                    ]
                ]
            )
        ]
    );

    $signer2 = new Signer(
        [
            'email' => $signer2Email,
            'name' => $signer2Name,
            'recipient_id' => "2",
            'routing_order' => "1",
            'excluded_documents' => ["1"],
            'tabs' => new Tabs(
                [
                    'sign_here_tabs' =>  [
                        new SignHere(
                            [
                                'anchor_string' => '/sn1/',
                                'anchor_units' => 'pixels',
                                'anchor_y_offset' => '10',
                                'anchor_x_offset' => '20'
                            ]
                        )
                    ]
                ]
            )
        ]
    );

    return [$signer1, $signer2];
}

private static function _prepareDocuments(
    string $signer1Email,
    string $signer1Name,
    string $ccEmail,
    string $ccName,
    string $docPdf,
    string $docDocx,
    string $docHTML,
    string $demoPath
): array {
    $contentBytesPdf = file_get_contents($demoPath . $docPdf);
    $contentBytesDocx = file_get_contents($demoPath . $docDocx);
    $contentBytesHtml = file_get_contents($demoPath . $docHTML);
    $contentBytesHtml = str_replace("{USER_EMAIL}", $signer1Email, $contentBytesHtml);
    $contentBytesHtml = str_replace("{USER_FULLNAME}", $signer1Name, $contentBytesHtml);
    $contentBytesHtml = str_replace("{CC_EMAIL}", $ccEmail, $contentBytesHtml);
    $contentBytesHtml = str_replace("{CC_NAME}", $ccName, $contentBytesHtml);

    $documentHTML = new Document(
        [
            'document_base64' => base64_encode($contentBytesHtml),
            'name' => 'Order acknowledgement',
            'file_extension' => 'html',
            'document_id' => "1"
        ]
    );

    $documentDOCX = new Document(
        [
            'document_base64' => base64_encode($contentBytesDocx),
            'name' => 'Battle Plan',
            'file_extension' => 'docx',
            'document_id' => "2"
        ]
    );

    $documentPDF = new Document(
        [
            'document_base64' => base64_encode($contentBytesPdf),
            'name' => 'Lorem Ipsum',
            'file_extension' => 'pdf',
            'document_id' => "3"
        ]
    );

    return [$documentHTML, $documentDOCX, $documentPDF];
}
```

**`PowerShell`**

```text title="PowerShell"
@{
    emailSubject = "Please sign this document set";
    enforceSignerVisibility = "true";
    documents    = @(
        @{
            documentBase64 = "$(Get-Content $doc1Base64)";
            name           = "Order acknowledgement";
            fileExtension  = "html";
            documentId     = "1";
        };
        @{
            documentBase64 = "$(Get-Content $doc2Base64)";
            name           = "Battle Plan";
            fileExtension  = "docx";
            documentId     = "2";
        };
        @{
            documentBase64 = "$(Get-Content $doc3Base64)";
            name           = "Lorem Ipsum";
            fileExtension  = "pdf";
            documentId     = "3";
        }; );
    recipients   = @{
        carbonCopies = @(
            @{
                email        = $CC_EMAIL;
                name         = $CC_NAME;
                recipientId  = "3";
                routingOrder = "3";
            };
        );
        signers      = @(
            @{
                email        = $SIGNER1_EMAIL;
                name         = $SIGNER1_NAME;
                recipientId  = "1";
                routingOrder = "1";
                excludedDocuments = @(2, 3)
                tabs         = @{
                    signHereTabs = @(
                        @{
                            anchorString  = "**signature_1**";
                            anchorUnits   = "pixels";
                            anchorXOffset = "20";
                            anchorYOffset = "10";
                        };
                    );
                };
            };
            @{
                email        = $SIGNER2_EMAIL;
                name         = $SIGNER2_NAME;
                recipientId  = "2";
                routingOrder = "2";
                excludedDocuments = @(1)
                tabs         = @{
                    signHereTabs = @(
                        @{
                            anchorString  = "/sn1/";
                            anchorUnits   = "pixels";
                            anchorXOffset = "20";
                            anchorYOffset = "10";
                        };
                    );
                };
            };
        );
    };
    status       = "sent";
} | ConvertTo-Json -Depth 32 > $requestData
```

**`Python`**

```python title="Python"
def make_envelope(cls, args, doc_docx_path, doc_pdf_path):
    """
    Creates envelope
    args -- parameters for the envelope:
    signer_email, signer_name, signer_client_id
    returns an envelope definition
    """
    env = EnvelopeDefinition(
        email_subject = "Please sign this document set",
        enforce_signer_visibility = "true",
    )

    doc1_b64 = base64.b64encode(bytes(cls.create_document1(args), "utf-8")).decode("ascii")
    # read files 2 and 3 from a local directory
    # The reads could raise an exception if the file is not available!
    with open(path.join(demo_docs_path, doc_docx_path), "rb") as file:
        doc2_docx_bytes = file.read()
    doc2_b64 = base64.b64encode(doc2_docx_bytes).decode("ascii")
    with open(path.join(demo_docs_path, doc_pdf_path), "rb") as file:
        doc3_pdf_bytes = file.read()
    doc3_b64 = base64.b64encode(doc3_pdf_bytes).decode("ascii")

    # Create the document models
    document1 = Document(  # create the DocuSign document object
        document_base64=doc1_b64,
        name="Order acknowledgement",  # can be different from actual file name
        file_extension="html",  # many different document types are accepted
        document_id="1",  # a label used to reference the doc
    )
    document2 = Document(
        document_base64=doc2_b64,
        name="Battle Plan",
        file_extension="docx",
        document_id="2"
    )
    document3 = Document(
        document_base64=doc3_b64,
        name="Lorem Ipsum",
        file_extension="pdf",
        document_id="3"
    )

    # The order in the docs array determines the order in the envelope
    env.documents = [document1, document2, document3]

    # Create the signer recipient model
    signer1 = Signer(
        # The signer1
        email=args["signer1_email"],
        name=args["signer1_name"],
        excluded_documents = ["2","3"], # Sets which documents are excluded for this signer
        recipient_id="1",
        routing_order="1",
        role_name="Signer1"
    )

    signer2 = Signer(
        # The signer2
        email=args["signer2_email"],
        name=args["signer2_name"],
        excluded_documents = ["1"],
        recipient_id="2",
        routing_order="1",
        role_name="Signer2"
    )

    cc = CarbonCopy(
        email=args["cc_email"],
        name=args["cc_name"],
        recipient_id="3",
        routing_order="2"
    )

    # Create signHere fields (also known as tabs) on the documents.
    sign_here1 = SignHere(
        document_id="1",
        page_number="1",
        name="Signer1",
        anchor_string="**signature_1**",
        anchor_units="pixels",
        anchor_y_offset="10",
        anchor_x_offset="20"
    )
    sign_here2 = SignHere(
        document_id="2",
        anchor_string="/sn1/",
        anchor_units="pixels",
        anchor_y_offset="10",
        anchor_x_offset="20"
    )

    # Add the tabs model (including the sign_here tabs) to the signer
    # The Tabs object wants arrays of the different field/tab types
    signer1.tabs = Tabs(
        sign_here_tabs=[sign_here1, ],
    )

    signer2.tabs = Tabs(sign_here_tabs=[sign_here2, ])

    # Add the recipients to the envelope object
    recipients = Recipients(signers=[signer1, signer2], carbon_copies=[cc])
    env.recipients = recipients

    # Request that the envelope be sent by setting |status| to "sent".
    # To request that the envelope be created as a draft, set to "created"
    env.status = args["status"]

    return env

@classmethod
def create_document1(cls, args):
    """ Creates document 1 -- an html document"""

    return f"""
    <!DOCTYPE html>
    <html>
        <head>
          <meta charset="UTF-8">
        </head>
        <body style="font-family:sans-serif;margin-left:2em;">
        <h1 style="font-family: "Trebuchet MS", Helvetica, sans-serif;
            color: darkblue;margin-bottom: 0;">World Wide Corp</h1>
        <h2 style="font-family: "Trebuchet MS", Helvetica, sans-serif;
          margin-top: 0px;margin-bottom: 3.5em;font-size: 1em;
          color: darkblue;">Order Processing Division</h2>
        <h4>Ordered by {args["signer1_name"]}</h4>
        <p style="margin-top:0em; margin-bottom:0em;">Email: {args["signer1_email"]}</p>
        <p style="margin-top:0em; margin-bottom:0em;">Copy to: {args["cc_name"]}, {args["cc_email"]}</p>
        <p style="margin-top:3em;">
            Candy bonbon pastry jujubes lollipop wafer biscuit biscuit. Topping brownie sesame snaps sweet roll pie.
            Croissant danish biscuit soufflé caramels jujubes jelly. Dragée danish caramels lemon drops dragée.
            Gummi bears cupcake biscuit tiramisu sugar plum pastry. Dragée gummies applicake pudding liquorice.
            Donut jujubes oat cake jelly-o.
            Dessert bear claw chocolate cake gummies lollipop sugar plum ice cream gummies cheesecake.
        </p>
        <!-- Note the anchor tag for the signature field is in white. -->
        <h3 style="margin-top:3em;">Agreed: <span style="color:white;">**signature_1**/</span></h3>
        </body>
    </html>
    """
```

**`Ruby`**

```ruby title="Ruby"
envelope_definition = make_envelope args[:envelope_args]
  def make_envelope(envelope_args)
# document 1 (HTML) has tag **signature_1**
# document 2 (DOCX) has tag /sn1/
# document 3 (PDF) has tag /sn1/
#
# The envelope has two recipients:
# recipient 1 - signer 1
# recipient 2 - signer 2
# recipient 3 - cc
# The envelope will be sent first to the signer.
# After it is signed, a copy is sent to the cc person

# Create the envelope definition
envelope_definition = DocuSign_eSign::EnvelopeDefinition.new

envelope_definition.email_subject = 'Please sign this document set'
envelope_definition.enforce_signer_visibility = 'true'

# Add the documents
doc1_b64 = Base64.encode64(create_document1(envelope_args))
# Read files 2 and 3 from a local directory
# The reads could raise an exception if the file is not available!
doc2_b64 = Base64.encode64(File.binread(envelope_args[:doc_docx]))
doc3_b64 = Base64.encode64(File.binread(envelope_args[:doc_pdf]))

# Create the document models
document1 = DocuSign_eSign::Document.new(
  # Create the Docusign document object
  documentBase64: doc1_b64,
  name: 'Order acknowledgement', # Can be different from actual file name
  fileExtension: 'html', # Many different document types are accepted
  documentId: '1' # A label used to reference the doc
)
document2 = DocuSign_eSign::Document.new(
  # Create the Docusign document object
  documentBase64: doc2_b64,
  name: 'Battle Plan', # Can be different from actual file name
  fileExtension: 'docx', # Many different document types are accepted
  documentId: '2' # A label used to reference the do
)
document3 = DocuSign_eSign::Document.new(
  # Create the Docusign document object
  documentBase64: doc3_b64,
  name: 'Lorem Ipsum', # Can be different from actual file name
  fileExtension: 'pdf', # Many different document types are accepted
  documentId: '3' # A label used to reference the doc
)

# The order in the docs array determines the order in the envelope
envelope_definition.documents = [document1, document2, document3]

# Create the signer recipient model
signer1 = DocuSign_eSign::Signer.new
signer1.email = envelope_args[:signer1_email]
signer1.name = envelope_args[:signer1_name]
signer1.recipient_id = '1'
signer1.routing_order = '1'
signer1.excluded_documents = [2, 3]

signer2 = DocuSign_eSign::Signer.new
signer2.email = envelope_args[:signer2_email]
signer2.name = envelope_args[:signer2_name]
signer2.recipient_id = '2'
signer2.routing_order = '2'
signer2.excluded_documents = [1]
## routingOrder (lower means earlier) determines the order of deliveries
# to the recipients. Parallel routing order is supported by using the
# same integer as the order for two or more recipients

# Create a cc recipient to receive a copy of the documents
cc = DocuSign_eSign::CarbonCopy.new(
  email: envelope_args[:cc_email],
  name: envelope_args[:cc_name],
  routingOrder: '3',
  recipientId: '3'
)
# Create signHere fields (also known as tabs) on the documents
# We're using anchor (autoPlace) positioning
#
# The Docusign platform searches throughout your envelope's documents for matching
# anchor strings. So the sign_here_2 tab will be used in both document 2 and 3
# since they use the same anchor string for their "signer 1" tabs.
sign_here1 = DocuSign_eSign::SignHere.new(
  anchorString: '**signature_1**',
  anchorYOffset: '10',
  anchorUnits: 'pixels',
  anchorXOffset: '20'
)

sign_here2 = DocuSign_eSign::SignHere.new(
  anchorString: '/sn1/',
  anchorYOffset: '10',
  anchorUnits: 'pixels',
  anchorXOffset: '20'
)
# Add the tabs model (including the sign_here tabs) to the signer
# The Tabs object takes arrays of the different field/tab types
signer1_tabs = DocuSign_eSign::Tabs.new({
                                          signHereTabs: [sign_here1]
                                        })

signer1.tabs = signer1_tabs

signer2_tabs = DocuSign_eSign::Tabs.new({
                                          signHereTabs: [sign_here2]
                                        })

signer2.tabs = signer2_tabs

# Add the recipients to the envelope object
recipients = DocuSign_eSign::Recipients.new(
  signers: [signer1, signer2],
  carbonCopies: [cc]
)
# Request that the envelope be sent by setting status to "sent".
# To request that the envelope be created as a draft, set status to "created"
envelope_definition.recipients = recipients
envelope_definition.status = envelope_args[:status]
envelope_definition
  end
```

## Step 4. Call the eSignature REST API

Now that you have constructed your API headers and request body, make a POST request to the eSignature REST API and include the request body to send an envelope with the specified document visibility. Here’s how you make the call, but make sure to substitute your API account ID for \{ACCOUNT_ID}.

> **Note**
>
> View the source code for this how-to on GitHub: [Bash](https://github.com/docusign/code-examples-bash/blob/master/examples/eSignature/eg040SetDocumentVisibility.sh), [C#](https://github.com/docusign/code-examples-csharp/blob/master/launcher-csharp/eSignature/Examples/SetDocumentVisibility.cs), [Java](https://github.com/docusign/code-examples-java/blob/master/src/main/java/com/docusign/controller/eSignature/services/SetDocumentVisibilityService.java), [Node.js](https://github.com/docusign/code-examples-node/blob/master/lib/eSignature/examples/setDocumentVisibility.js), [PHP](https://github.com/docusign/code-examples-php/blob/master/src/Services/Examples/eSignature/SetDocumentsVisibilityService.php), [PowerShell](https://github.com/docusign/code-examples-powershell/blob/master/examples/eSignature/eg040SetDocumentVisibility.ps1), [Python](https://github.com/docusign/code-examples-python/blob/master/app/eSignature/examples/eg040_document_visibility.py). or [Ruby](https://github.com/docusign/code-examples-ruby/blob/master/app/services/e_sign/eg040_set_document_visibility_service.rb).

**`Bash`**

```bash title="Bash"
response=$(mktemp /tmp/response-oa.XXXXXX)
Status=$(curl --request POST ${base_path}/v2.1/accounts/${account_id}/envelopes \
"${Headers[@]}" \
--data-binary @${request_data} \
--output ${response})
```

**`C#`**

```csharp title="C#"
var envelopeSummary = envelopesApi.CreateEnvelopeWithHttpInfo(accountId, envelopeDefinition);
envelopeSummary.Headers.TryGetValue("X-RateLimit-Remaining", out string remaining);
envelopeSummary.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);
}
```

**`Java`**

```java title="Java"
var envelopeSummary = envelopesApi.createEnvelopeWithHttpInfo(
        accountId,
        envelope,
        envelopesApi.new CreateEnvelopeOptions());
Map<String, List<String>> headers = envelopeSummary.getHeaders();
java.util.List<String> remaining = headers.get("X-RateLimit-Remaining");
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);
}
```

**`Node.js`**

```javascript title="Node.js"
const envelopesApi = new docusign.EnvelopesApi(dsApiClient);

// Make the envelope request body
const envelope = makeEnvelope(args.envelopeArgs);

// Call Envelopes::create API method
// Exceptions will be caught by the calling function
const results = await envelopesApi.createEnvelope(args.accountId, {
  envelopeDefinition: envelope,
}, (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 = results.data.envelopeId;
```

**`PHP`**

```php title="PHP"
$envelopeSummary = $envelope_api->createEnvelopeWithHttpInfo(
    $accountId,
    $envelope_definition
);

$remaining = $envelopeSummary[2]['X-RateLimit-Remaining'] ?? null;
$reset =  $envelopeSummary[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"
try {
    Invoke-RestMethod `
        -Uri "${apiUri}/v2.1/accounts/${accountId}/envelopes" `
        -Method 'POST' `
        -Headers $headers `
        -InFile (Resolve-Path $requestData).Path `
        -OutFile $response
```

**`Python`**

```python title="Python"
envelope_api = EnvelopesApi(api_client)
(results, status, headers) = envelope_api.create_envelope_with_http_info(account_id=args["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 = results.envelope_id
```

**`Ruby`**

```ruby title="Ruby"
envelope_api = create_envelope_api(args)
results, _status, headers = envelope_api.create_envelope_with_http_info args[: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 = results.envelope_id
```

## Expected response

* Signer 1 should be able to view and sign “Order acknowledgement”
* Signer 2 should be able to view and sign “Battle Plan Trafalgar” and “Lorem Ipsum”
* Carbon copy recipient should be able to see all three completed documents

## 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).
* See [requirements and limitations with document visibility](https://support.docusign.com/s/document-item?bundleId=gbo1643332197980\&topicId=fhx1578456268488.html).
* Learn how to [Send Using Advanced Workflow Features](https://dsucustomers.docusign.com/send-using-advanced-workflow-features).
* Learn [How to request a signature by email](/docs/esign-rest-api/how-to/request-signature-email-remote).
* 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.