> 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 send an envelope with extension app data verification fields

> This topic demonstrates how to set connected fields in a document and send an envelope with a data verification field.

This topic demonstrates how to set connected fields in a document and send an envelope with a data verification field. A connected field is a field that can be verified by a connected field or [data verification](/extension-apps/extension-apps-101/supported-extensions) extension in your account.

Connected fields validate data entered in a document against an external system of record before submission. This enables users to verify different data types, such as email addresses, phone numbers, social security numbers, and other supported data verification types. This example will walk you through configuring connected fields using the `ConnectedFields:TabGroups` endpoint response, constructing an envelope request body containing the information needed to include a connected field, and sending that envelope via email (remote sending).

## Prerequisites

* Running this example requires that you have an extension app that includes a connected fields extension or a data verification extension installed in the [Developer Console](https://devconsole.docusign.com).
* Before running this example, download a connected field or data verification app from the [Docusign App Center](https://apps-d.docusign.com/app-center) or build your own using the connected fields reference implementation [Connected Fields Reference Implementation](https://github.com/docusign/extension-app-connected-fields-reference-implementation) or [Data Verification Reference Implementation](https://github.com/docusign/extension-app-data-verification-reference-implementation).
* When calling the Connected Fields API, you must include an additional scope, `adm_store_unified_repo_read`, in addition to your eSignature scopes.

> **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_PATH1}          | A string value that forms the root of the URL required to make calls to the Connected Fields API. The base path value in the example code is set to target the developer environment at https\://\<domain>/v1 Where \<domain> is api-d.docusign.com for the developer environment and api.docusign.com for production.                                                                                                                                        |
| \{BASE_PATH2}          | A string value that forms the root of the URL required to make calls to the eSignature REST API. 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.                                                                                                               |
| 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) |
| \{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**
>
> Wondering which grant type suits your integration? See [Authentication](/docs/connected-fields-api/auth) for guidance on your options to get an 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 Connected Fields 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#"
private static IamClient CreateAuthenticatedClient(string basePath, string accessToken) =>
    IamClient.Builder().WithServerUrl(basePath).WithAccessToken(accessToken).Build();
```

**`Java`**

```java title="Java"
ApiClient apiClient = new ApiClient(basePath);
apiClient.addDefaultHeader(
        HttpHeaders.AUTHORIZATION,
        BEARER_AUTHENTICATION + accessToken);
```

**`Node.js`**

```javascript title="Node.js"
const getTabGroups = async (args) => {
  const client = new iam.IamClient({ accessToken: args.accessToken });
  return await client.connectedFields.tabInfo.getConnectedFieldsTabGroups({ accountId: args.accountId });
};
```

**`PHP`**

```php title="PHP"
$config = new Configuration();
$config->setHost($basePath);
$config->addDefaultHeader('Authorization', 'Bearer ' . $accessToken);
```

**`PowerShell`**

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

**`Python`**

```python title="Python"
headers = {
    "Authorization": "Bearer " + args['access_token'],
    "Accept": "application/json",
    "Content-Type": "application/json"
}
```

**`Ruby`**

```ruby title="Ruby"
headers = {
  'Authorization' => "Bearer #{args[:access_token]}",
  'Accept' => 'application/json',
  'Content-Type' => 'application/json'
}
```

## Step 3. Call the Connected Fields API

Make a GET request to the ConnectedFields:TabGroups endpoint to retrieve a list of the extension apps in your account that support data verification, including the definitions of their required verifiable fields, that you will need to create an envelope with connected fields. The GET request will return a JSON response that includes all extension app data in the user’s account. Here’s how you make the call, but make sure to substitute your API account ID for \{ACCOUNT_ID}.

**`Bash`**

```bash title="Bash"
response=$(mktemp ./response-cf.XXXXXX)
Status=$(curl -w '%{http_code}' -i --ssl-no-revoke --request GET https://api-d.docusign.com/v1/accounts/${account_id}/connected-fields/tab-groups \
    "${Headers[@]}" \
    --output ${response})
```

**`C#`**

```csharp title="C#"
var client = CreateAuthenticatedClient(basePath, accessToken);
return await client.ConnectedFields.TabInfo.GetConnectedFieldsTabGroupsAsync(accountId);
```

**`Java`**

```java title="Java"
	public static ConnectedFieldsApiGetTabGroupsResponse getConnectedFieldsTabGroups(String accountId,
			String accessToken) throws Exception {
		return IamClient.builder()
				.accessToken(accessToken)
				.build()
				.connectedFields()
				.tabInfo()
				.getConnectedFieldsTabGroups()
				.accountId(accountId)
				.call();
	}
```

**`Node.js`**

```javascript title="Node.js"
const filterData = (connectedFields) => {
  return connectedFields.filter(app =>
    app.tabs?.some(tab =>
      (tab.extensionData?.actionContract?.includes('Verify')) ||
      (tab.tabLabel?.includes('connecteddata'))
    )
  );
};
```

**`PHP`**

```php title="PHP"
$response = $client->request('GET', $url, [
    'headers' => [
        'Authorization' => "Bearer $accessToken",
        'Accept' => 'application/json',
        'Content-Type' => 'application/json'
    ]
]);
```

**`PowerShell`**

```text title="PowerShell"
Invoke-RestMethod `
    -Uri "${apiUri1}/v1/accounts/${accountId}/connected-fields/tab-groups" `
    -Method 'GET' `
    -Headers $headers `
    -OutFile $response
```

**`Python`**

```python title="Python"
url = f"{args['base_path']}/v1/accounts/{args['account_id']}/connected-fields/tab-groups"

response = requests.get(url, headers=headers)
response_data = response.json()

filtered_apps = list(
    app for app in response_data
    if any(
        ("extensionData" in tab and "actionContract" in tab["extensionData"] and "Verify" in tab["extensionData"]["actionContract"]) or
        ("tabLabel" in tab and "connecteddata" in tab["tabLabel"])
        for tab in app.get("tabs", [])
    )
)

unique_apps = list({app['appId']: app for app in filtered_apps}.values())
```

**`Ruby`**

```ruby title="Ruby"
url = URI("#{args[:extensions_base_path]}/v1/accounts/#{args[:account_id]}/connected-fields/tab-groups")
response = Net::HTTP.get_response(url, headers)
response_data = JSON.parse(response.body)

filtered_apps = response_data.select do |app|
  app['tabs']&.any? do |tab|
    (tab['extensionData']&.dig('actionContract')&.include? 'Verify') ||
      (tab['tabLabel']&.include? 'connecteddata')
  end
end

# return unique apps
filtered_apps.uniq { |app| app['appId'] }
```

## Step 4. Extract the tab data from the response

Next, retrieve the required tab information from the response. Begin by creating a filter to identify apps capable of verifying a connected field: data verification extension apps and connected fields extension apps. Then prompt the user to choose an extension app. Finally, extract the tab values from the `extensionData` object of the selected app for use in Step 5, where they will be used to construct a connected field in the envelope definition. The tab values needed to construct the connected field are:

* `app_id`: The unique ID of the extension app used to verify the field data.
* `extension_group_id`: The ID of the group of extensions within the extension app.
* `publisher_name`: The publisher of the extension app.
* `application_name`: The name of the extension app.
* `action_name`: The name of the verification action in the extension app.
* `action_contract`: The template defining the verification action.
* `action_input_key`: The key representing the input data required for verification. The value for this property determines the actual data type to be verified.
* `extension_name`: The name of the extension.
* `extension_contract`: The template defining the extension.
* `required_for_extension`: A boolean value that indicates whether the field must pass verification before the signer can sign the document.
* `tab_label`: The label assigned to the verification field in the document.
* `connection_key`: The key used to identify the connection instance.
* `connection_value`: The value of the connection instance.

**`Bash`**

```bash title="Bash"
extract_verify_info() {
    invoke_python "filter_by_verify_action('''$response''')"
}

prompt_user_choice() {
    local json_data="'''$1'''"
    unique_apps=()
    while IFS= read -r line; do
        unique_apps+=("$line")
    done < <(invoke_python "extract_unique_apps($json_data)")

    if [[ -z "$json_data" || "$json_data" == "[]" ]]; then
        echo "No data verification were found in the account. Please install a data verification app."
        echo ""
        echo "You can install a phone number verification extension app by copying the following link to your browser: "
        echo "https://apps.docusign.com/app-center/app/d16f398f-8b9a-4f94-b37c-af6f9c910c04"
        exit 1
    fi

    echo "Please select an app by entering a number:"
    for i in "${!unique_apps[@]}"; do
        echo "$((i+1)). ${unique_apps[$i]#* }"
    done

    read -p "Enter choice (1-${#unique_apps[@]}): " choice
    if [[ "$choice" =~ ^[1-${#unique_apps[@]}]$ ]]; then
        chosen_app_id="'${unique_apps[$((choice-1))]%% *}'"
        selected_data=$(invoke_python "filter_by_app_id('''$response''', $chosen_app_id)")
    else
        echo "Invalid choice. Exiting."
        exit 1
    fi
}

if [[ -z "$response" ]]; then
    echo "Error: response file variable not set."
    exit 1
fi

filtered_data=$(extract_verify_info)

if [[ -z "$filtered_data" || "$filtered_data" == "[]" ]]; then
    echo "No data verification were found in the account. Please install a data verification app."
    echo ""
    echo "You can install a phone number verification extension app by copying the following link to your browser: "
    echo "https://apps.docusign.com/app-center/app/d16f398f-8b9a-4f94-b37c-af6f9c910c04"
    exit 1
fi

prompt_user_choice "$filtered_data"
```

**`C#`**

```csharp title="C#"
public static List<TabInfo> FilterData(List<TabInfo> connectedFields)
{
    return connectedFields
        .Where(group => group.Tabs.Any(tab =>
            tab.ExtensionData?.ActionContract?.Contains("Verify") == true ||
            tab.TabLabel.Contains("connecteddata")))
        .ToList();
}
```

**`Java`**

```java title="Java"
	public static List<TabInfo> filterData(ConnectedFieldsApiGetTabGroupsResponse connectedFields) {
		List<TabInfo> filteredList = new ArrayList<>();

		for (var tabInfoGroup : connectedFields.tabInfos().orElse(List.of())) {
			for (var tab : tabInfoGroup.tabs()) {
				var extensionData = tab.extensionData();
				String tabLabel = tab.tabLabel();

				boolean hasVerify = extensionData != null &&
						extensionData.actionContract().isPresent() &&
						extensionData.actionContract().get().contains("Verify");

				boolean hasConnectedData = tabLabel != null && tabLabel.contains("connecteddata");

				if (hasVerify || hasConnectedData) {
					filteredList.add(tabInfoGroup);
					break;
				}
			}
		}

		return filteredList;
	}

	public static TabInfo findAppById(List<TabInfo> extensionApps, String appId) {
		return extensionApps.stream()
				.filter(app -> appId.equals(app.appId()))
				.findFirst()
				.orElse(null);
	}
```

**`Node.js`**

```javascript title="Node.js"
const extractVerificationData = (selectedAppId, tab) => {
  const extensionData = tab.extensionData;

  return {
    appId: selectedAppId,
    extensionGroupId: extensionData.extensionGroupId,
    publisherName: extensionData.publisherName,
    applicationName: extensionData.applicationName,
    actionName: extensionData.actionName,
    actionInputKey: extensionData.actionInputKey,
    actionContract: extensionData.actionContract,
    extensionName: extensionData.extensionName,
    extensionContract: extensionData.extensionContract,
    requiredForExtension: extensionData.requiredForExtension,
    tabLabel: tab.tabLabel,
    connectionKey: extensionData.connectionInstances ? extensionData.connectionInstances[0].connectionKey : '',
    connectionValue: extensionData.connectionInstances ? extensionData.connectionInstances[0].connectionValue : '',
  };
};
```

**`PHP`**

```php title="PHP"
public static function filterData(array $data): string
{
    $filteredData = array_filter($data, function ($item) {
        if (!isset($item['tabs']) || !is_array($item['tabs'])) {
            return false;
        }

        foreach ($item['tabs'] as $tab) {
            if ((isset($tab['extensionData']['actionContract'])
                    && str_contains($tab['extensionData']['actionContract'], "Verify")) ||
                (isset($tab['tabLabel']) && str_contains($tab['tabLabel'], "connecteddata"))) {
                return true;
            }
        }

        return false;
    });

    return json_encode(array_values($filteredData));
}
```

**`PowerShell`**

```text title="PowerShell"
function Extract-VerifyInfo {
    param (
        [string]$responseFile
    )

    # Read the response file content
    $content = Get-Content $responseFile -Raw

    # Extract JSON
    $jsonStart = $content.IndexOf('[')
    if ($jsonStart -ge 0) {
        $json = $content.Substring($jsonStart) | ConvertFrom-Json
    } else {
        Write-Error "No JSON array found in the response."
        return
    }

    # Filter the JSON to keep only verification extension apps
    $filtered = $json | Where-Object {
        $_.tabs -and ($_.tabs | Where-Object {
            ($_.extensionData.actionContract -like "*Verify*") -or
            ($_.PSObject.Properties['tabLabel'] -and $_.tabLabel -like "*connecteddata*")
        })
    }

    return $filtered | ConvertTo-Json -Depth 10
}

function Prompt-UserChoice {
    param (
        [string]$jsonData
    )

    if (-not $jsonData -or $jsonData -eq "[]") {
        Write-Host "No data verification were found in the account. Please install a data verification app."
        Write-Host "You can install a phone number verification extension app by copying the following link to your browser: "
        Write-Host "https://apps.docusign.com/app-center/app/d16f398f-8b9a-4f94-b37c-af6f9c910c04"
        exit 1
    }

    $data = $jsonData | ConvertFrom-Json

    # Extract unique app IDs and application names
    $uniqueApps = @{}
    foreach ($item in $data) {
        if ($item.appId -and $item.tabs[0].extensionData.applicationName) {
            $uniqueApps[$item.appId] = $item.tabs[0].extensionData.applicationName
        }
    }

    # If no unique apps are found
    if ($uniqueApps.Count -eq 0) {
        Write-Host "No valid apps found in the JSON data."
        exit 1
    }

    # Display available apps
    Write-Host "Please select an app by entering a number:"
    $appList = $uniqueApps.Keys | Sort-Object
    for ($i = 0; $i -lt $appList.Count; $i++) {
        Write-Host "$($i + 1). $($uniqueApps[$appList[$i]])"
    }

    # Get user choice
    $choice = Read-Host "Enter choice (1-$($appList.Count))"
    if ($choice -match "^\d+$" -and [int]$choice -ge 1 -and [int]$choice -le $appList.Count) {
        $chosenAppId = $appList[[int]$choice - 1]

        # Filter JSON data for the selected app ID
        $selectedData = $data | Where-Object { $_.appId -eq $chosenAppId }
        return $selectedData
    } else {
        Write-Host "Invalid choice. Exiting."
        exit 1
    }
}

function Parse-VerificationData {
    param (
        $selectedAppId,
        $tab
    )

    $connectionKeyData   = ''
    $connectionValueData = ''
    if ($tab.extensionData.connectionInstances) {
        $connectionKeyData   = $tab.extensionData.connectionInstances[0].connectionKey
        $connectionValueData = $tab.extensionData.connectionInstances[0].connectionValue
    }

    # Extract required fields from the first element
    $extractedData = @{
        appId                = $selectedAppId
        extensionGroupId     = $tab.extensionData.extensionGroupId
        publisherName        = $tab.extensionData.publisherName
        applicationName      = $tab.extensionData.applicationName
        actionName           = $tab.extensionData.actionName
        actionInputKey       = $tab.extensionData.actionInputKey
        actionContract       = $tab.extensionData.actionContract
        extensionName        = $tab.extensionData.extensionName
        extensionContract    = $tab.extensionData.extensionContract
        requiredForExtension = $tab.extensionData.requiredForExtension
        tabLabel             = $tab.tabLabel
        connectionKey        = $connectionKeyData
        connectionValue      = $connectionValueData
    }

    return $extractedData
}

$filteredData = Extract-VerifyInfo -responseFile $response

$selectedApp = Prompt-UserChoice -jsonData $filteredData
```

**`Python`**

```python title="Python"
def extract_verification_data(selected_app_id, tab):
    extension_data = tab["extensionData"]

    return {
        "app_id": selected_app_id,
        "extension_group_id": extension_data["extensionGroupId"] if "extensionGroupId" in extension_data else "",
        "publisher_name": extension_data["publisherName"] if "publisherName" in extension_data else "",
        "application_name": extension_data["applicationName"] if "applicationName" in extension_data else "",
        "action_name": extension_data["actionName"] if "actionName" in extension_data else "",
        "action_input_key": extension_data["actionInputKey"] if "actionInputKey" in extension_data else "",
        "action_contract": extension_data["actionContract"] if "actionContract" in extension_data else "",
        "extension_name": extension_data["extensionName"] if "extensionName" in extension_data else "",
        "extension_contract": extension_data["extensionContract"] if "extensionContract" in extension_data else "",
        "required_for_extension": extension_data["requiredForExtension"] if "requiredForExtension" in extension_data else "",
        "tab_label": tab["tabLabel"],
        "connection_key": (
            extension_data["connectionInstances"][0]["connectionKey"]
            if "connectionInstances" in extension_data and extension_data["connectionInstances"]
            else ""
        ),
        "connection_value": (
            extension_data["connectionInstances"][0]["connectionValue"]
            if "connectionInstances" in extension_data and extension_data["connectionInstances"]
            else ""
        ),
    }
```

**`Ruby`**

```ruby title="Ruby"
def extract_verification_data(selected_app_id, tab)
  extension_data = tab['extensionData']

  {
    app_id: selected_app_id,
    extension_group_id: extension_data['extensionGroupId'],
    publisher_name: extension_data['publisherName'],
    application_name: extension_data['applicationName'],
    action_name: extension_data['actionName'],
    action_input_key: extension_data['actionInputKey'],
    action_contract: extension_data['actionContract'],
    extension_name: extension_data['extensionName'],
    extension_contract: extension_data['extensionContract'],
    required_for_extension: extension_data['requiredForExtension'],
    tab_label: tab['tabLabel'],
    connection_key: extension_data['connectionInstances']&.dig(0, 'connectionKey') || '',
    connection_value: extension_data['connectionInstances']&.dig(0, 'connectionValue') || ''
  }
end
```

## Step 5. Create the envelope definition

Next, create the envelope definition for the request body. If you're using a Docusign SDK, you can prepare a compatible request body by creating an envelope definition using the included makeEnvelope method.

* Set a `signHere` tab to collect signature information.
* As an example for this how-to, create a `text` tab containing the extension app tab data extracted from Step 4. For your own apps, you may choose any verifiable tabs based on the results of your Connected Fields API call.

**`Bash`**

```bash title="Bash"
text_tabs=$(invoke_python "make_text_tabs_list('''$selected_data''', $chosen_app_id)")

printf \
'{
    "emailSubject": "Please sign this document",
    "documents": [
        {
            "documentBase64": "' > "$request_data"
            cat $doc1_base64 >> $request_data
            printf '",
            "name": "Lorem Ipsum",
            "fileExtension": "pdf",
            "documentId": "1"
        }
    ],
    "status": "sent",
    "recipients": {
        "signers": [
            {
                "email": "'"${SIGNER_EMAIL}"'",
                "name": "'"${SIGNER_NAME}"'",
                "recipientId": "1",
                "routingOrder": "1",
                "tabs": {
                    "signHereTabs": [
                        {
                            "anchorString": "/sn1/",
                            "anchorUnits": "pixels",
                            "anchorXOffset": "20",
                            "anchorYOffset": "10"
                        }
                    ],
                    "textTabs": ' >> "$request_data"
                        printf '%s' "$text_tabs" >> "$request_data"  # Ensure all tabs are added
                        printf '
                }
            }
        ]
    }
}' >> $request_data
```

**`C#`**

```csharp title="C#"
public static EnvelopeDefinition MakeEnvelope(
    string signerEmail,
    string signerName,
    string docPdf,
    TabInfo selectedApp)
{
    EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition();
    envelopeDefinition.EmailSubject = "Please sign this document set";
    envelopeDefinition.Status = "sent";

    string docPdfBytes = Convert.ToBase64String(System.IO.File.ReadAllBytes(docPdf));
    Document document = new Document
    {
        DocumentBase64 = docPdfBytes,
        Name = "Lorem Ipsum",
        FileExtension = "pdf",
        DocumentId = "1",
    };

    envelopeDefinition.Documents = new List<Document> { document };

    Signer signer = new Signer
    {
        Email = signerEmail,
        Name = signerName,
        RecipientId = "1",
        RoutingOrder = "1",
        Tabs = new Tabs
        {
            SignHereTabs = new List<SignHere>
           {
                new SignHere
                {
                    AnchorString = "/sn1/",
                    AnchorUnits = "pixels",
                    AnchorYOffset = "10",
                    AnchorXOffset = "20",
                },
           },
            TextTabs = new List<Text>(),
        },
    };

    foreach (var tab in selectedApp.Tabs)
    {
        var extensionData = tab.ExtensionData;
        var connectionKey = extensionData.ConnectionInstances != null ?
            extensionData.ConnectionInstances[0]?.ConnectionKey : string.Empty;
        var connectionValue = extensionData.ConnectionInstances != null ?
            extensionData.ConnectionInstances[0]?.ConnectionValue : string.Empty;

        var text = new Text
        {
            RequireInitialOnSharedChange = "false",
            RequireAll = "false",
            Name = extensionData.ApplicationName,
            Required = "false",
            Locked = "false",
            DisableAutoSize = "false",
            MaxLength = "4000",
            TabLabel = tab.TabLabel,
            Font = "lucidaconsole",
            FontColor = "black",
            FontSize = "size9",
            DocumentId = "1",
            RecipientId = "1",
            PageNumber = "1",
            XPosition = "273",
            YPosition = "191",
            Width = "84",
            Height = "22",
            TemplateRequired = "false",
            TabType = "text",
            ExtensionData = new ExtensionData
            {
                ExtensionGroupId = extensionData.ExtensionGroupId,
                PublisherName = extensionData.PublisherName,
                ApplicationId = selectedApp.AppId,
                ApplicationName = extensionData.ApplicationName,
                ActionName = extensionData.ActionName,
                ActionContract = extensionData.ActionContract,
                ExtensionName = extensionData.ExtensionName,
                ExtensionContract = extensionData.ExtensionContract,
                RequiredForExtension = extensionData.RequiredForExtension.ToString(),
                ActionInputKey = extensionData.ActionInputKey,
                ExtensionPolicy = "MustVerifyToSign",
                ConnectionInstances = new List<ConnectionInstance>
                {
                    new ConnectionInstance
                    {
                        ConnectionKey = connectionKey,
                        ConnectionValue = connectionValue,
                    },
                },
            },
        };
        signer.Tabs.TextTabs.Add(text);
    }

    envelopeDefinition.Recipients = new Recipients
    {
        Signers = new List<Signer>
        {
            signer,
        },
    };
    return envelopeDefinition;
}
```

**`Java`**

```java title="Java"
	public static EnvelopeDefinition makeEnvelope(String signerEmail, String signerName, TabInfo selectedApp)
			throws Exception {
		String appId = selectedApp.appId();
		var tabLabels = selectedApp.tabs();

		EnvelopeDefinition envelopeDefinition = new EnvelopeDefinition();
		envelopeDefinition.setEmailSubject("Please sign this document set");
		envelopeDefinition.setStatus("sent");

		Document document = EnvelopeHelpers.createDocumentFromFile(
				PDF_DOCUMENT_FILE_NAME,
				PDF_DOCUMENT_NAME,
				"1");
		envelopeDefinition.setDocuments(Collections.singletonList(document));

		Signer signer = new Signer();
		signer.setEmail(signerEmail);
		signer.setName(signerName);
		signer.setRecipientId("1");
		signer.setRoutingOrder("1");

		SignHere signHere = new SignHere();
		signHere.setAnchorString("/sn1/");
		signHere.setAnchorUnits("pixels");
		signHere.setAnchorYOffset("10");
		signHere.setAnchorXOffset("20");

		List<Text> textTabs = new ArrayList<>();

		if (tabLabels != null) {
			for (var tab : tabLabels) {
				var extensionData = tab.extensionData();

				String connectionKey = "";
				String connectionValue = "";

				var connectionInstances = extensionData.connectionInstances();
				if (connectionInstances.isPresent() && !connectionInstances.get().isEmpty()) {
					var firstInstance = connectionInstances.get().get(0);
					connectionKey = firstInstance.connectionKey();
					connectionValue = firstInstance.connectionValue();
				}

				Text textTab = new Text();
				textTab.setRequireInitialOnSharedChange("false");
				textTab.setRequireAll("false");
				textTab.setName(extensionData.applicationName().orElse("App"));
				textTab.setRequired("false");
				textTab.setLocked("false");
				textTab.setDisableAutoSize("false");
				textTab.setMaxLength("4000");
				textTab.setTabLabel(tab.tabLabel());
				textTab.setFont("lucidaconsole");
				textTab.setFontColor("black");
				textTab.setFontSize("size9");
				textTab.setDocumentId("1");
				textTab.setRecipientId("1");
				textTab.setPageNumber("1");
				textTab.setXPosition("273");
				textTab.setYPosition("191");
				textTab.setWidth("84");
				textTab.setHeight("22");
				textTab.setTemplateRequired("false");
				textTab.setTabType("text");

				ExtensionData extension = new ExtensionData();
				extension.setExtensionGroupId(extensionData.extensionGroupId());
				extension.setPublisherName(extensionData.publisherName().orElse(null));
				extension.setApplicationId(appId);
				extension.setApplicationName(extensionData.applicationName().orElse(null));
				extension.setActionName(extensionData.actionName().orElse(null));
				extension.setActionContract(extensionData.actionContract().orElse(null));
				extension.setExtensionName(extensionData.applicationName().orElse(null));
				extension.setExtensionContract(extensionData.extensionContract().orElse(null));
				extension.setRequiredForExtension(String.valueOf(extensionData.requiredForExtension()));
				extension.setActionInputKey(extensionData.actionInputKey());
				extension.setExtensionPolicy("None");

				ConnectionInstance connectionInstance = new ConnectionInstance();
				connectionInstance.setConnectionKey(connectionKey);
				connectionInstance.setConnectionValue(connectionValue);
				extension.setConnectionInstances(Collections.singletonList(connectionInstance));

				textTab.setExtensionData(extension);
				textTabs.add(textTab);
			}
		}

		Tabs tabs = new Tabs();
		tabs.setSignHereTabs(Collections.singletonList(signHere));
		tabs.setTextTabs(textTabs);
		signer.setTabs(tabs);

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

		return envelopeDefinition;
	}
```

**`Node.js`**

```javascript title="Node.js"
function makeEnvelope(args) {
  // Data for this method
  // args.signerEmail
  // args.signerName
  // args.signerClientId
  // docFile

  // document 1 (pdf) has tag /sn1/
  //
  // The envelope has one recipients.
  // recipient 1 - signer

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

  // read file from a local directory
  // The read could raise an exception if the file is not available!
  const docPdfBytes = fs.readFileSync(args.docFile);

  // add the documents
  let doc = new docusign.Document();
  let docb64 = Buffer.from(docPdfBytes).toString('base64');
  doc.documentBase64 = docb64;
  doc.name = 'Lorem Ipsum'; // can be different from actual file name
  doc.fileExtension = 'pdf';
  doc.documentId = '1';

  // The order in the docs array determines the order in the envelope
  env.documents = [doc];

  // Create a signer recipient to sign the document, identified by name and email
  let signer = new docusign.Signer();
  signer.email = args.signerEmail;
  signer.name = args.signerName;
  signer.recipientId = '1';
  signer.routingOrder = '1';

  // Create signHere fields (also known as tabs) on the documents,
  // We're using anchor (autoPlace) positioning
  //
  // The DocuSign platform seaches throughout your envelope's
  // documents for matching anchor strings.
  let signHere = new docusign.SignHere();
  signHere.anchorString = '/sn1/';
  signHere.anchorYOffset = '10';
  signHere.anchorUnits = 'pixels';
  signHere.anchorXOffset = '20';

  let textTabs = [];
  for (const tab of args.app.tabs.filter(t => !t.tabLabel.includes('SuggestionInput'))) {
    const verificationData = extractVerificationData(args.appId, tab);
    const textTab = makeTextTab(verificationData, textTabs.length);

    textTabs.push(textTab);
  }

  // Tabs are set per recipient / signer
  let signerTabs = new docusign.Tabs();
  signerTabs.signHereTabs = [signHere];
  signerTabs.textTabs = textTabs;

  signer.tabs = signerTabs;

  // Add the recipient to the envelope object
  let recipients = new docusign.Recipients();
  recipients.signers = [signer];

  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 = 'sent';

  return env;
}

const getExtensionData = (verificationData) => ({
  extensionGroupId: verificationData.extensionGroupId,
  publisherName: verificationData.publisherName,
  applicationId: verificationData.appId,
  applicationName: verificationData.applicationName,
  actionName: verificationData.actionName,
  actionContract: verificationData.actionContract,
  extensionName: verificationData.extensionName,
  extensionContract: verificationData.extensionContract,
  requiredForExtension: verificationData.requiredForExtension,
  actionInputKey: verificationData.actionInputKey,
  extensionPolicy: 'MustVerifyToSign',
  connectionInstances: [
    {
      connectionKey: verificationData.connectionKey,
      connectionValue: verificationData.connectionValue,
    },
  ],
});

const makeTextTab = (verificationData, textTabsCount) => ({
  requireInitialOnSharedChange: false,
  requireAll: false,
  name: verificationData.applicationName,
  required: true,
  locked: false,
  disableAutoSize: false,
  maxLength: 4000,
  tabLabel: verificationData.tabLabel,
  font: 'lucidaconsole',
  fontColor: 'black',
  fontSize: 'size9',
  documentId: '1',
  recipientId: '1',
  pageNumber: '1',
  xPosition: `${70 + 100 * Math.floor(textTabsCount / 10)}`,
  yPosition: `${560 + 20 * (textTabsCount % 10)}`,
  width: '84',
  height: '22',
  templateRequired: false,
  tabType: 'text',
  tooltip: verificationData.actionInputKey,
  extensionData: getExtensionData(verificationData)
});
```

**`PHP`**

```php title="PHP"
public static function makeEnvelopes($app, $signerName, $signerEmail, $pdfDoc, $demoPath): EnvelopeDefinition
{
    $appId = $app['appId'] ?? "";
    $tabLabels = $app['tabs'];

    $contentBytes = file_get_contents($demoPath . $pdfDoc);
    $base64FileContent = base64_encode($contentBytes);

    $doc = new Document([
        'document_base64' => $base64FileContent,
        'name' => 'Lorem Ipsum',
        'file_extension' => 'pdf',
        'document_id' => '1'
    ]);

    $signer = new Signer([
        'email' => $signerEmail,
        'name' => $signerName,
        'recipient_id' => '1',
        "routing_order" => "1",
    ]);

    $signHere = new SignHere([
        'anchor_string' => '/sn1/',
        'anchor_y_offset' => '10',
        'anchor_units' => 'pixels',
        'anchor_x_offset' => '20'
    ]);

    $textTabs = [];

    foreach ($tabLabels as $tab) {
        $connectionKey = $tab['extensionData']['connectionInstances'][0]['connectionKey'] ?? "";
        $connectionValue = $tab['extensionData']['connectionInstances'][0]['connectionValue'] ?? "";
        $extensionGroupId = $tab['extensionData']['extensionGroupId'] ??  "";
        $publisherName = $tab['extensionData']['publisherName'] ?? "";
        $applicationName = $tab['extensionData']['applicationName'] ?? "";
        $actionName = $tab['extensionData']['actionName'] ?? "";
        $actionInputKey = $tab['extensionData']['actionInputKey'] ?? "";
        $actionContract = $tab['extensionData']['actionContract'] ?? "";
        $extensionName = $tab['extensionData']['extensionName'] ?? "";
        $extensionContract = $tab['extensionData']['extensionContract'] ?? "";
        $requiredForExtension = $tab['extensionData']['requiredForExtension'] ?? "";

        $textTab = [
            "requireInitialOnSharedChange"=> false,
            "requireAll"=> false,
            "name"=> $applicationName,
            "required"=> true,
            "locked"=> false,
            "disableAutoSize"=> false,
            "maxLength"=> 4000,
            "tabLabel"=> $tab["tabLabel"],
            "font"=> "lucidaconsole",
            "fontColor"=> "black",
            "fontSize"=> "size9",
            "documentId"=> "1",
            "recipientId"=> "1",
            "pageNumber"=> "1",
            "xPosition"=> "273",
            "yPosition"=>  150 + 20 * count($textTabs),
            "width"=> "84",
            "height"=> "22",
            "templateRequired"=> false,
            "tabType"=> "text",
            "extensionData" => [
                "extensionGroupId" => $extensionGroupId,
                "publisherName"=> $publisherName,
                "applicationId"=> $appId,
                "applicationName"=> $applicationName,
                "actionName"=> $actionName,
                "actionContract"=> $actionContract,
                "extensionName"=> $extensionName,
                "extensionContract"=> $extensionContract,
                "requiredForExtension"=> $requiredForExtension,
                "actionInputKey"=> $actionInputKey,
                "extensionPolicy"=> "MustVerifyToSign",
                "connectionInstances"=> [
                    [
                        "connectionKey"=> $connectionKey,
                        "connectionValue"=> $connectionValue
                    ]
                ]
            ]
        ];

        array_push($textTabs, $textTab);
    }

    $signerTabs = new Tabs([
        'sign_here_tabs' => [$signHere],
        'text_tabs' => $textTabs
    ]);
    $signer->setTabs($signerTabs);

    $recipients = new Recipients([
        'signers' => [$signer]
    ]);

    $envelope = new EnvelopeDefinition([
        'email_subject' => 'Please sign this document',
        'documents' => [$doc],
        'recipients' => $recipients,
        'status' => 'sent'
    ]);

    return $envelope;
}
```

**`PowerShell`**

```text title="PowerShell"
function Get-Extension-Data {
    param (
        $verificationData
    )

    return @{
        extensionGroupId     = $verificationData.extensionGroupId;
        publisherName        = $verificationData.publisherName;
        applicationId        = $verificationData.appId;
        applicationName      = $verificationData.applicationName;
        actionName           = $verificationData.actionName;
        actionContract       = $verificationData.actionContract;
        extensionName        = $verificationData.extensionName;
        extensionContract    = $verificationData.extensionContract;
        requiredForExtension = $verificationData.requiredForExtension;
        actionInputKey       = $verificationData.actionInputKey;
        extensionPolicy      = "MustVerifyToSign";
        connectionInstances  = @(
            @{
                connectionKey   = $verificationData.connectionKey;
                connectionValue = $verificationData.connectionValue;
            };
        );
    };
}

function Make-Text-Tab {
    param (
        $verificationData,
        $extensionData,
        $textTabCount
    )

    return @{
        requireInitialOnSharedChange = "false";
        requireAll                   = "false";
        name                         = $verificationData.applicationName;
        required                     = "true";
        locked                       = "false";
        disableAutoSize              = "false";
        maxLength                    = "4000";
        tabLabel                     = $verificationData.tabLabel;
        font                         = "lucidaconsole";
        fontColor                    = "black";
        fontSize                     = "size9";
        documentId                   = "1";
        recipientId                  = "1";
        pageNumber                   = "1";
        xPosition                    = [string](70 + 100 * [math]::Floor($textTabCount / 10));
        yPosition                    = [string](560 + 20 * ($textTabCount % 10));
        width                        = "84";
        height                       = "22";
        templateRequired             = "false";
        tabType                      = "text";
        tooltip                      = $verificationData.actionInputKey;
        extensionData                = $extensionData
    };
}

function Make-Text-Tab-List {
    param (
        $app
    )

    $text_tabs = @()
    foreach ($tab in $app.tabs | Where-Object { $_.tabLabel -notlike '*SuggestionInput*' }) {
        $verificationData = Parse-VerificationData -selectedAppId $app.appId -tab $tab
        $extensionData = Get-Extension-Data -verificationData $verificationData

        $text_tab = Make-Text-Tab -verificationData $verificationData -extensionData $extensionData -textTabCount $text_tabs.Count
        $text_tabs += $text_tab
    }

    return $text_tabs
}

$textTabs = Make-Text-Tab-List -app $selectedApp

@{
    emailSubject = "Please sign this document";
    documents    = @(
        @{
            documentBase64 = "$(Get-Content $docBase64)";
            name           = "Lorem Ipsum";
            fileExtension  = "pdf";
            documentId     = "1";
        };
    );
    status      = "sent";
    recipients  = @{
        signers = @(
            @{
                email        = $variables.SIGNER_EMAIL;
                name         = $variables.SIGNER_NAME;
                recipientId  = "1";
                routingOrder = "1";
                tabs = @{
                    signHereTabs = @(
                        @{
                            anchorString  = "/sn1/";
                            anchorUnits   = "pixels";
                            anchorXOffset = "20";
                            anchorYOffset = "10";
                        };
                    );
                    textTabs = @($textTabs);
                };
            };
        );
    };
} | ConvertTo-Json -Depth 32 > $requestData
```

**`Python`**

```python title="Python"
def make_envelope(cls, args, app):
    """
    Creates envelope
    args -- parameters for the envelope:
    signer_email, signer_name
    returns an envelope definition
    """

    # document 1 (pdf) has tag /sn1/
    #
    # The envelope has one recipient.
    # recipient 1 - signer
    with open(path.join(demo_docs_path, DS_CONFIG["doc_pdf"]), "rb") as file:
        content_bytes = file.read()
    base64_file_content = base64.b64encode(content_bytes).decode("ascii")

    # Create the document model
    document = Document(  # create the DocuSign document object
        document_base64=base64_file_content,
        name="Example document",  # can be different from actual file name
        file_extension="pdf",  # many different document types are accepted
        document_id=1  # a label used to reference the doc
    )

    # Create the signer recipient model
    signer = Signer(
        # The signer
        email=args["signer_email"],
        name=args["signer_name"],
        recipient_id="1",
        routing_order="1"
    )

    # Create a sign_here tab (field on the document)
    sign_here = SignHere(
        anchor_string="/sn1/",
        anchor_units="pixels",
        anchor_y_offset="10",
        anchor_x_offset="20"
    )

    # Create text tabs (field on the document)
    text_tabs = []
    for tab in (t for t in app["tabs"] if "SuggestionInput" not in t["tabLabel"]):
        verification_data = cls.extract_verification_data(app["appId"], tab)
        extension_data = cls.get_extension_data(verification_data)

        text_tab = {
            "requireInitialOnSharedChange": False,
            "requireAll": False,
            "name": verification_data["application_name"],
            "required": True,
            "locked": False,
            "disableAutoSize": False,
            "maxLength": 4000,
            "tabLabel": verification_data["tab_label"],
            "font": "lucidaconsole",
            "fontColor": "black",
            "fontSize": "size9",
            "documentId": "1",
            "recipientId": "1",
            "pageNumber": "1",
            "xPosition": f"{70 + 100 * int(len(text_tabs) / 10)}",
            "yPosition": f"{560 + 20 * (len(text_tabs) % 10)}",
            "width": "84",
            "height": "22",
            "templateRequired": False,
            "tabType": "text",
            "tooltip": verification_data["action_input_key"],
            "extensionData": extension_data
        }
        text_tabs.append(text_tab)

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

    # Next, create the top level envelope definition and populate it.
    envelope_definition = EnvelopeDefinition(
        email_subject="Please sign this document",
        documents=[document],
        # The Recipients object wants arrays for each recipient type
        recipients=Recipients(signers=[signer]),
        status="sent"  # requests that the envelope be created and sent.
    )

    return envelope_definition

def get_extension_data(verification_data):
    return {
        "extensionGroupId": verification_data["extension_group_id"],
        "publisherName": verification_data["publisher_name"],
        "applicationId": verification_data["app_id"],
        "applicationName": verification_data["application_name"],
        "actionName": verification_data["action_name"],
        "actionContract": verification_data["action_contract"],
        "extensionName": verification_data["extension_name"],
        "extensionContract": verification_data["extension_contract"],
        "requiredForExtension": verification_data["required_for_extension"],
        "actionInputKey": verification_data["action_input_key"],
        "extensionPolicy": 'MustVerifyToSign',
        "connectionInstances": [
            {
                "connectionKey": verification_data["connection_key"],
                "connectionValue": verification_data["connection_value"],
            }
        ]
    }
```

**`Ruby`**

```ruby title="Ruby"
def make_envelope(envelope_args, app)
  doc = DocuSign_eSign::Document.new
  doc.document_base64 = Base64.encode64(File.binread(envelope_args[:doc_pdf]))
  doc.name = 'Lorem Ipsum'
  doc.file_extension = 'pdf'
  doc.document_id = '1'

  # The order in the docs array determines the order in the envelope
  # Create a signer recipient to sign the document, identified by name and email
  # We're setting the parameters via the object creation
  signer = DocuSign_eSign::Signer.new
  signer.email = envelope_args[:signer_email]
  signer.name = envelope_args[:signer_name]
  signer.recipient_id = 1

  # 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_here = DocuSign_eSign::SignHere.new
  sign_here.anchor_string = '/sn1/'
  sign_here.anchor_units = 'pixels'
  sign_here.anchor_x_offset = '20'
  sign_here.anchor_y_offset = '10'

  text_tabs = []
  app['tabs'].each do |tab|
    next if tab['tabLabel'].include?('SuggestionInput')

    verification_data = extract_verification_data(app['appId'], tab)
    text_tabs.push(text_tab(verification_data, text_tabs.length))
  end

  tabs = DocuSign_eSign::Tabs.new
  tabs.sign_here_tabs = [sign_here]
  tabs.text_tabs = text_tabs
  signer.tabs = tabs

  recipients = DocuSign_eSign::Recipients.new
  recipients.signers = [signer]

  envelope_definition = DocuSign_eSign::EnvelopeDefinition.new
  envelope_definition.email_subject = 'Please sign this document'
  envelope_definition.documents = [doc]
  envelope_definition.recipients = recipients
  envelope_definition.status = 'sent'
  envelope_definition
end

def extension_data(verification_data)
  {
    extensionGroupId: verification_data[:extension_group_id],
    publisherName: verification_data[:publisher_name],
    applicationId: verification_data[:app_id],
    applicationName: verification_data[:application_name],
    actionName: verification_data[:action_name],
    actionContract: verification_data[:action_contract],
    extensionName: verification_data[:extension_name],
    extensionContract: verification_data[:extension_contract],
    requiredForExtension: verification_data[:required_for_extension],
    actionInputKey: verification_data[:action_input_key],
    extensionPolicy: 'MustVerifyToSign',
    connectionInstances: [
      {
        connectionKey: verification_data[:connection_key],
        connectionValue: verification_data[:connection_value]
      }
    ]
  }
end

def text_tab(verification_data, text_tabs_count)
  {
    requireInitialOnSharedChange: false,
    requireAll: false,
    name: verification_data[:application_name],
    required: true,
    locked: false,
    disableAutoSize: false,
    maxLength: 4000,
    tabLabel: verification_data[:tab_label],
    font: 'lucidaconsole',
    fontColor: 'black',
    fontSize: 'size9',
    documentId: '1',
    recipientId: '1',
    pageNumber: '1',
    xPosition: (70 + 100 * (text_tabs_count / 10)).to_s,
    yPosition: (560 + 20 * (text_tabs_count % 10)).to_s,
    width: '84',
    height: '22',
    templateRequired: false,
    tabType: 'text',
    tooltip: verification_data[:action_input_key],
    extensionData: extension_data(verification_data)
  }
end
```

## Step 6. Create and send the envelope

Now that you have constructed your request body, make a POST request to the eSignature REST API [Envelopes:create](/docs/esign-rest-api/reference/envelopes/envelopes/create) endpoint and include the request body to create the envelope.

> **Note**
>
> View the source code for this how-to on GitHub: [Bash](https://github.com/docusign/code-examples-bash/blob/master/examples/ConnectedFields/eg001SetConnectedFields.sh), [C#](https://github.com/docusign/code-examples-csharp/blob/master/launcher-csharp/ConnectedFields/Examples/SetConnectedFields.cs), [Java](https://github.com/docusign/code-examples-java/blob/master/src/main/java/com/docusign/controller/connectedFields/examples/CF001SetConnectedFields.java), [Node.js](https://github.com/docusign/code-examples-node/blob/master/lib/connectedFields/examples/setConnectedFields.js), [PHP](https://github.com/docusign/code-examples-php/blob/master/src/Services/Examples/ConnectedFields/SetConnectedFieldsService.php),  [PowerShell](https://github.com/docusign/code-examples-powershell/blob/master/examples/ConnectedFields/eg001SetConnectedFields.ps1), [Python](https://github.com/docusign/code-examples-python/blob/master/app/connected_fields/examples/eg001_set_connected_fields.py), or [Ruby](https://github.com/docusign/code-examples-ruby/blob/master/app/controllers/connected_fields/feg001_set_connected_fields_controller.rb).

**`Bash`**

```bash title="Bash"
response=$(mktemp /tmp/response-eg-001.XXXXXX)

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

base_path2="https://demo.docusign.net/restapi"

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

echo ""
echo "Response:"
cat $response
echo ""
```

**`C#`**

```csharp title="C#"
EnvelopeDefinition envelopeDefinition = MakeEnvelope(signerEmail, signerName, docPdf, selectedApp);
var docuSignClient = new DocuSignClient(basePath);
docuSignClient.Configuration.DefaultHeader.Add("Authorization", "Bearer " + accessToken);

EnvelopesApi envelopesApi = new EnvelopesApi(docuSignClient);
EnvelopeSummary results = envelopesApi.CreateEnvelope(accountId, envelopeDefinition);
```

**`Java`**

```java title="Java"
EnvelopesApi envelopesApi = createEnvelopesApi(session.getBasePath(), user.getAccessToken());

EnvelopeDefinition envelope = SetConnectedFieldsService.makeEnvelope(
        args.getSignerEmail(),
        args.getSignerName(),
        extensionApp);
EnvelopeSummary envelopeSummary = SetConnectedFieldsService.signingViaEmail(
        envelopesApi,
        session.getAccountId(),
        envelope);
```

**`Node.js`**

```javascript title="Node.js"
let dsApiClient = new docusign.ApiClient();
dsApiClient.setBasePath(args.basePath);
dsApiClient.addDefaultHeader('Authorization', 'Bearer ' + args.accessToken);
let envelopesApi = new docusign.EnvelopesApi(dsApiClient);

const envelope = makeEnvelope(args.envelopeArgs);

const results = await envelopesApi.createEnvelope(args.accountId, {
  envelopeDefinition: envelope,
});
```

**`PHP`**

```php title="PHP"
$apiClient = new ApiClient($config);
$envelopesApi = new EnvelopesApi($apiClient);

$envelope = SetConnectedFieldsService::makeEnvelopes(
    $app,
    $signerName,
    $signerEmail,
    $pdfDoc,
    $demoPath
);

$options = new \DocuSign\eSign\Api\EnvelopesApi\CreateEnvelopeOptions();
$results = $envelopesApi->createEnvelope($accountId, $envelope, $options);

return $results->getEnvelopeId();
```

**`PowerShell`**

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

**`Python`**

```python title="Python"
envelope_args = args["envelope_args"]
# Create the envelope request object
envelope_definition = cls.make_envelope(envelope_args, app)

# Call Envelopes::create API method
# Exceptions will be caught by the calling function
api_client = create_api_client(base_path=args["base_path"], access_token=args["access_token"])

envelope_api = EnvelopesApi(api_client)
results = envelope_api.create_envelope(account_id=args["account_id"], envelope_definition=envelope_definition)

envelope_id = results.envelope_id
```

**`Ruby`**

```ruby title="Ruby"
envelope = make_envelope args[:envelope_args], app

# Call Docusign to create the envelope
envelope_api = create_envelope_api(args)

results = envelope_api.create_envelope args[:account_id], envelope

{ 'envelope_id' => results.envelope_id }
```

## 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 the document containing the connected fields using the Docusign mobile app or the Docusign website. After signing is complete, the recipient will receive a carbon copy (CC) of the email that includes all of the completed and signed documents.

**`Sample response`**

```json title="Sample response"
Response:
{"envelopeId":"537cb132-xxxx-xxxx-xxxx-634ac1ea51fe","uri":"/envelopes/537cb132-xxxx-xxxx-xxxx-634ac1ea51fe","statusDateTime":"2025-03-04T23:01:27.9530000Z","status":"sent"}
EnvelopeId: 537cb132-xxxx-xxxx-xxxx-634ac1ea51fe

Done. When the signer inputs the data to be verified, ensure the connection to the sender’s data verification extension app or connected fields extension app is active.
```

## 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 [Extension apps](/extension-apps).
* See how to [Go-Live](/docs/connected-fields-api/go-live) with a completed app and find the base path for API calls in the production environment.