> 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 require phone authentication for a recipient

> Demonstrates requesting a signature via email while also utilizing phone authentication.

eSignature REST API 2.1 only

This topic demonstrates how to request a signature via email while also using [phone authentication](/docs/esign-rest-api/esign101/concepts/recipients/auth#phone).

> **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. |
| \{COUNTRY_CODE}       | The country code corresponding to the PHONE_NUMBER.                                                                                                                                                                                                                                                                    |
| \{DOCUMENT_ID}        | A document identifier such as a name or ID. You can get a [list of envelope documents](/docs/esign-rest-api/how-to/list-envelope-documents) to obtain this information.                                                                                                                                                |
| Document to be signed | You must provide at least one document to be signed. Document used in this how-to:- [PDF file](https://github.com/docusign/code-examples-java/blob/master/src/main/resources/World_Wide_Corp_lorem.pdf)                                                                                                                |
| \{PHONE_NUMBER}       | The phone number of the signer where the authentication message will be sent.                                                                                                                                                                                                                                          |
| \{RECIPIENT_ID}       | A unique string value that you assign to identify each recipient. This value assigns tabs on a per-[recipient](/docs/esign-rest-api/esign101/concepts/recipients) basis.                                                                                                                                               |
| \{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.                                                                                                                                                                                                                                                                        |
| \{WORKFLOW_ID}        | A [GUID](http://guid.one/) value that identifies the identity verification workflow assigned to your account when phone authentication is enabled.                                                                                                                                                                     |

## Step 1. Obtain your OAuth token

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

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

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

## Step 2: 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);
```

**`Java`**

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

**`Node.js`**

```javascript title="Node.js"
let 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 $oAuthAccessToken")
$headers.add("Accept", "application/json")
$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. Obtain your workflow ID

Make a request to the [IdentityVerifications:list](/docs/esign-rest-api/reference/accounts/identityverifications/list) endpoint on the Accounts resource of the eSignature REST API using your \{API_ACCOUNT_ID} to retrieve the workflow ID. The response will include an array of workflow IDs. Different workflow IDs can be specified per recipient. To require phone authentication for a given recipient, use the workflow ID with the name “Phone Authentication.” If you do not have phone authentication configured for your account, the `identity_verification` call will return an empty array. Omitting a workflow ID or providing an invalid workflow ID will cause your request to fail.

**`Bash`**

```bash title="Bash"
Status=$(curl -w '%{http_code}' -i --request GET "https://demo.docusign.net/restapi/v2.1/accounts/${account_id}/identity_verification" \
     "${Headers[@]}" \
     --output ${response})

#If the Status code returned is greater than 201 (OK / Accepted), display an error message along with the API response.
if [[ "$Status" -gt "201" ]] ; then
    echo ""
	echo "Unable to retrieve your account's workflow ID."
	echo ""
	cat $response
	exit 0
fi

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

# Retrieve the workflow IDs from the API response and put them in an array.
workflowIds=`cat $response | grep -o -P '(?<=workflowId\":\").*?(?=\")'`
arrWorkflowIds=($workflowIds)

# Get the index of the Phone auth workflow based on name and use that index for workflowId.
# Workflow name of phone auth is 'Phone Authentication'
workflowNames=`cat $response | grep -o -P '(?<=defaultName\":).*?(?=,)'`
element="Phone Authentication"

workflowId=$(GetWorkflowId "$workflowNames" "$element" "$workflowIds")
```

**`C#`**

```csharp title="C#"
var accountsApi = new AccountsApi(docuSignClient);
var response = accountsApi.GetAccountIdentityVerificationWithHttpInfo(accountId);
response.Headers.TryGetValue("X-RateLimit-Remaining", out string remaining);
response.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);
}

var phoneAuthWorkflow = response.Data.IdentityVerification.FirstOrDefault(x => x.DefaultName == "Phone Authentication");
```

**`Java`**

```java title="Java"
AccountsApi workflowDetails = new AccountsApi(apiClient);
var workflowRes = workflowDetails.getAccountIdentityVerificationWithHttpInfo(session.getAccountId(), workflowDetails.new GetAccountIdentityVerificationOptions());
Map<String, List<String>> headers = workflowRes.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);
}
List<AccountIdentityVerificationWorkflow> identityVerification = workflowRes.getData().getIdentityVerification();
String workflowId = "";
for (int i = 0; i < identityVerification.size(); i++) {
    if (identityVerification.get(i).getDefaultName().equals("Phone Authentication")) {
        workflowId = identityVerification.get(i).getWorkflowId();
    }
}
```

**`Node.js`**

```javascript title="Node.js"
let accountsApi = new docusign.AccountsApi(dsApiClient);
let workflowId = null;

let results = await accountsApi.getAccountIdentityVerification(
  args.accountId, (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()}`);
    }
});

// Find the workflow ID corresponding to the name "Phone Authentication"
results.data.identityVerification.forEach(workflow => {
  if (workflow.defaultName === 'Phone Authentication') {
    workflowId = workflow.workflowId;
  }
});
```

**`PHP`**

```php title="PHP"
$accounts_api = $clientService->getAccountsApi();
$accounts_response = $accounts_api->getAccountIdentityVerificationWithHttpInfo($_SESSION['ds_account_id']);

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

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

$workflows_data = $accounts_response[0]->getIdentityVerification();
$workflow_id = '';
foreach ($workflows_data as $workflow) {
    if ($workflow['default_name'] == 'Phone Authentication') {
        $workflow_id = $workflow['workflow_id'];
    }
}
```

**`PowerShell`**

```text title="PowerShell"
$uri = "https://demo.docusign.net/restapi/v2.1/accounts/$APIAccountId/identity_verification"

Write-Output "Attempting to retrieve your account's workflow ID"

Write-Output "Response:"
$result = Invoke-RestMethod -uri $uri -headers $headers -method GET
$result.content
#Obtain the workflow ID from the API response
$workflowId = [System.Linq.Enumerable]::FirstOrDefault($result.identityVerification, [func[object, bool]] { param($x) $x.defaultName -eq "Phone Authentication"}).workflowId
```

**`Python`**

```python title="Python"
workflow_details = AccountsApi(api_client)
(workflow_response, status, headers) = workflow_details.get_account_identity_verification_with_http_info(account_id=args["account_id"])

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

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

# Check that idv authentication is enabled
# Find the workflow ID corresponding to the name "Phone Authentication"
if workflow_response.identity_verification:
    for workflow in workflow_response.identity_verification:
        if workflow.default_name == "Phone Authentication":
            session['workflow_id'] = workflow.workflow_id
```

**`Ruby`**

```ruby title="Ruby"
workflow_details = create_account_api(args)
workflow_response, _status, headers = workflow_details.get_account_identity_verification_with_http_info(args[:account_id])

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

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

# Check that idv authentication is enabled
if workflow_response.identity_verification
  phone_auth_workflow = workflow_response.identity_verification.find { |item| item.default_name == 'Phone Authentication' }
  if phone_auth_workflow
    phone_auth_workflow.workflow_id
  else
    ''
  end
else
  ''
end
```

## Step 4. 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 \{RECIPIENT_ID}, \{SIGNER_NAME}, \{SIGNER_EMAIL}, \{COUNTRY_CODE}, and \{PHONE_NUMBER} with your recipient's data in the JSON request body.

The accompanying code demonstrates how to use the `identityVerification` property in the request body to require phone authentication for a given recipient. In your developer account, use the workflow ID from the previous step to specify the phone authentication workflow.

**`Bash`**

```bash title="Bash"
printf \
'{
	"documents": [{
        "documentBase64": "' > $request_data
        cat $doc1_base64 >> $request_data
        printf '",
        "name": "Lorem Ipsum",
        "fileExtension": "pdf",
        "documentId": "1"
	}],
	"emailBlurb": "Sample text for email body",
	"emailSubject": "Please Sign",
	"envelopeIdStamping": "true",
	"recipients": {
		"signers": [{
			"name": "'"${RECIPIENT_NAME}"'",
			"email": "'"${RECIPIENT_EMAIL}"'",
			"note": "",
			"routingOrder": "1",
			"status": "created",
			"tabs": {
				"signHereTabs": [{
					"documentId": "1",
					"name": "SignHereTab",
					"pageNumber": "1",
					"recipientId": "1",
					"tabLabel": "SignHereTab",
					"xPosition": "200",
					"yPosition": "170"
				}]
			},
			"templateAccessCodeRequired": null,
			"deliveryMethod": "email",
			"recipientId": "1",
			"identityVerification":{
				"workflowId":"'"${workflowId}"'",
				"steps":null,"inputOptions":[
					{"name":"phone_number_list",
					"valueType":"PhoneNumberList",
					"phoneNumberList":[
						{
							"countryCode":"'"${SIGNER_PHONE_COUNTRY}"'",
							"number":"'"${SIGNER_PHONE_NUMBER}"'"
						}
						]
					}]
				}
			}]
		},
	"status": "Sent"
}
' >> $request_data
```

**`C#`**

```csharp title="C#"
EnvelopeDefinition env = new EnvelopeDefinition()
{
    EnvelopeIdStamping = "true",
    EmailSubject = "Please Sign",
    EmailBlurb = "Sample text for email body",
    Status = "Sent",
};

byte[] buffer = System.IO.File.ReadAllBytes(docPdf);

// Add a document
Document doc1 = new Document()
{
    DocumentId = "1",
    FileExtension = "pdf",
    Name = "Lorem",
    DocumentBase64 = Convert.ToBase64String(buffer),
};

// Create your signature tab
env.Documents = new List<Document> { doc1 };
SignHere signHere1 = new SignHere
{
    AnchorString = "/sn1/",
    AnchorUnits = "pixels",
    AnchorXOffset = "10",
    AnchorYOffset = "20",
};

// Tabs are set per recipient/signer
Tabs signer1Tabs = new Tabs
{
    SignHereTabs = new List<SignHere> { signHere1 },
};

RecipientIdentityVerification workflow = new RecipientIdentityVerification()
{
    WorkflowId = workflowId,
    InputOptions = new List<RecipientIdentityInputOption>
    {
        new RecipientIdentityInputOption
        {
            Name = "phone_number_list",
            ValueType = "PhoneNumberList",
            PhoneNumberList = new List<RecipientIdentityPhoneNumber>
            {
                new RecipientIdentityPhoneNumber
                {
                    Number = phoneNumber,
                    CountryCode = countryAreaCode,
                },
            },
        },
    },
};

Signer signer1 = new Signer()
{
    Name = signerName,
    Email = signerEmail,
    RoutingOrder = "1",
    Status = "Created",
    DeliveryMethod = "Email",
    RecipientId = "1", // represents your {RECIPIENT_ID},
    Tabs = signer1Tabs,
    IdentityVerification = workflow,
};

Recipients recipients = new Recipients();
recipients.Signers = new List<Signer> { signer1 };
env.Recipients = recipients;
```

**`Java`**

```java title="Java"
EnvelopeSummary results = PhoneAuthenticationService.phoneAuthentication(envelopesApi, accountId, envelope);
    public static EnvelopeDefinition createEnvelope(String signerName, String signerEmail, String countryCode,
    String phone, String workFlowId) throws IOException {
Document doc = EnvelopeHelpers.createDocumentFromFile(DOCUMENT_FILE_NAME, DOCUMENT_NAME, "1");

SignHere signHere = new SignHere();
signHere.setName("SignHereTab");
signHere.setXPosition("200");
signHere.setYPosition("160");
signHere.setTabLabel("SignHereTab");
signHere.setPageNumber("1");
signHere.setDocumentId(doc.getDocumentId());
// A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your
// own systems.
// This value is referenced in the Tabs element below to assign tabs on a
// per-recipient basis.
signHere.setRecipientId("1");

RecipientIdentityPhoneNumber phoneNumber = new RecipientIdentityPhoneNumber();
phoneNumber.setCountryCode(countryCode);
phoneNumber.setNumber(phone);

RecipientIdentityInputOption inputOption = new RecipientIdentityInputOption();
inputOption.setName("phone_number_list");
inputOption.setValueType("PhoneNumberList");
inputOption.setPhoneNumberList(List.of(phoneNumber));

RecipientIdentityVerification identityVerification = new RecipientIdentityVerification();

identityVerification.setWorkflowId(workFlowId);
identityVerification.setInputOptions(List.of(inputOption));

Signer signer = new Signer();
signer.setName(signerName);
signer.setEmail(signerEmail);
signer.setRoutingOrder("1");
signer.setStatus(EnvelopeHelpers.SIGNER_STATUS_CREATED);
signer.setDeliveryMethod(EnvelopeHelpers.DELIVERY_METHOD_EMAIL);
signer.setRecipientId(signHere.getRecipientId());
signer.setTabs(EnvelopeHelpers.createSignerTabs(signHere));
signer.setIdentityVerification(identityVerification);

Recipients recipients = new Recipients();
recipients.setSigners(List.of(signer));

EnvelopeDefinition envelope = new EnvelopeDefinition();
envelope.setEmailSubject("Please Sign");
envelope.setDocuments(List.of(doc));
envelope.setEnvelopeIdStamping("true");
envelope.setEmailBlurb("Sample text for email body");
envelope.setStatus(EnvelopeHelpers.ENVELOPE_STATUS_SENT);
envelope.setRecipients(recipients);

return envelope;
    }
```

**`Node.js`**

```javascript title="Node.js"
let envelope = makeEnvelope(args.envelopeArgs);
function makeEnvelope(args) {
// Data for this method
// args.signerEmail
// args.signerName
// args.phoneNumber
// arge.countryCode
// docFile

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

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

// Create the envelope definition
let env = new docusign.EnvelopeDefinition();
env.emailSubject = 'Please sign';
env.emailBlurb = 'Sample text for email body';
env.status = 'Sent';

// Add a document
let doc1 = new docusign.Document();
  let doc1b64 = Buffer.from(docPdfBytes).toString('base64');
doc1.documentBase64 = doc1b64;
doc1.name = 'Lorem'; // can be different from actual file name
doc1.fileExtension = 'pdf';
doc1.documentId = '1';

env.documents = [doc1];

// Create signHere fields (also known as tabs) on the documents,
// We're using anchor (autoPlace) positioning
let signHere1 = docusign.SignHere.constructFromObject({
  anchorString: '/sn1/',
  anchorYOffset: '10',
  anchorUnits: 'pixels',
  anchorXOffset: '20',
});
// Tabs are set per recipient / signer
let signer1Tabs = docusign.Tabs.constructFromObject({
  signHereTabs: [signHere1],
});

// A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your own systems.
// This value is referenced in the Tabs element below to assign tabs on a per-recipient basis.
RecipientId = '1'; // represents your {RECIPIENT_ID}

let signer1 = docusign.Signer.constructFromObject({
  email: args.signerEmail,
  name: args.signerName,
  recipientId: RecipientId,
  routingOrder: '1',
  deliveryMethod: 'Email',
  tabs: signer1Tabs,
  identityVerification: { workflowId: args.workflowId, steps: null, inputOptions: [{name: 'phone_number_list', valueType: 'PhoneNumberList', phoneNumberList: [{countryCode: args.countryCode, code: '1', number: args.phoneNumber}]}], idCheckConfigurationName: ''}
});

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

return env;
}
```

**`PHP`**

```php title="PHP"
$envelope_definition = $envelopeAndSigner['envelopeDefinition'];
$signer1Tabs = $envelopeAndSigner['signerTabs'];

$phoneNumber = new RecipientIdentityPhoneNumber;
$phoneNumber->setCountryCode($args['signer_country_code']);
$phoneNumber->setNumber($args['signer_phone_number']);

$inputOption = new RecipientIdentityInputOption;
$inputOption->setName('phone_number_list');
$inputOption->setValueType('PhoneNumberList');
$inputOption->setPhoneNumberList(array($phoneNumber));

$identityVerification = new RecipientIdentityVerification;
$identityVerification->setWorkflowId($workflow_id);
$identityVerification->setInputOptions(array($inputOption));

$signer1 = new Signer([
    'name' => $args['signer_name'],
    'email' => $args['signer_email'],
    'routing_order' => '1',
    'status' => 'created',
    'delivery_method' => 'Email',
    'recipient_id' => '1', # represents your {RECIPIENT_ID}
    'tabs' => $signer1Tabs,
    'identity_verification' => $identityVerification
]);

$recipients = new Recipients();
$recipients->setSigners(array($signer1));

$envelope_definition->setRecipients($recipients);
```

**`PowerShell`**

```text title="PowerShell"
$body = @"
{
	"documents": [{
		"documentBase64": "$(Get-Content $docBase64)",
		"documentId": "1",
		"fileExtension": "pdf",
		"name": "Lorem"
	}],
	"emailBlurb": "Sample text for email body",
	"emailSubject": "Please Sign",
	"envelopeIdStamping": "true",
	"recipients": {
		"signers": [{
			"name": "$SIGNER_NAME",
			"email": "$SIGNER_EMAIL",
			"roleName": "",
			"note": "",
			"routingOrder": 2,
			"status": "created",
			"tabs": {
				"signHereTabs": [{
					"documentId": "1",
					"name": "SignHereTab",
					"pageNumber": "1",
					"recipientId": "1",
					"tabLabel": "SignHereTab",
					"xPosition": "200",
					"yPosition": "160"
				}]
			},
			"templateAccessCodeRequired": null,
			"deliveryMethod": "email",
			"recipientId": "1",
			"identityVerification":{
				"workflowId":"$workflowId",
				"steps":null,"inputOptions":[
					{"name":"phone_number_list",
					"valueType":"PhoneNumberList",
					"phoneNumberList":[
						{
							"countryCode":"$SIGNER_COUNTRY_CODE",
							"number":"$SIGNER_PHONE_NUMBER"
						}
						]
					}]
				}
			}]
		},
	"status": "Sent"
}
"@
```

**`Python`**

```python title="Python"
envelope_definition = EnvelopeDefinition(
    email_subject="Please sign this document set"
)

# Open the example file
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")

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

envelope_definition.documents = [document1]
envelope_definition.status = args["envelope_args"]["status"]

# Create your signature tab
sign_here1 = SignHere(
    name="SignHereTab",
    anchor_string="/sn1/",
    anchor_units="pixels",
    anchor_y_offset="10",
    anchor_x_offset="20",
    tab_label="SignHereTab",
    page_number="1",
    document_id="1",
    # A 1- to 8-digit integer or 32-character GUID to match recipient IDs on your own systems.
    # This value is referenced in the Tabs element below to assign tabs on a per-recipient basis.
    recipient_id="1"  # represents your {RECIPIENT_ID}
)

signer1 = Signer(
    email=args["envelope_args"]["signer_email"],  # Represents your {signer_email}
    name=args["envelope_args"]["signer_name"],  # Represents your {signer_name}
    role_name="",
    note="",
    status="created",
    delivery_method="email",
    recipient_id="1",  # Represents your {RECIPIENT_ID}
    routing_order="1",
    identity_verification={ "workflowId": session['workflow_id'], "steps": "null", "inputOptions":[{"name":"phone_number_list","valueType":"PhoneNumberList","phoneNumberList":[{"countryCode":args["envelope_args"]["country_code"],"code":"1","number":args["envelope_args"]["phone_number"]}]}], "idCheckConfigurationName":""},
    tabs=Tabs(sign_here_tabs=[sign_here1])
)

# Tabs are set per recipient
envelope_definition.recipients = Recipients(signers=[signer1])
```

**`Ruby`**

```ruby title="Ruby"
envelope_definition = DocuSign_eSign::EnvelopeDefinition.new
envelope_definition.email_subject = 'Please sign this document set'

# Add the documents and create the document models
pdf_filename = 'World_Wide_Corp_lorem.pdf'
document1 = DocuSign_eSign::Document.new(
  # Create the Docusign Document object
  documentBase64: Base64.encode64(File.binread(File.join('data', pdf_filename))),
  name: 'Lorem', # Can be different from actual file name
  fileExtension: 'pdf', # Many different document types are accepted
  documentId: '1' # A label used to reference the doc
)

envelope_definition.documents = [document1]

# Create the signer recipient model
signer1 = DocuSign_eSign::Signer.new
signer1.email = envelope_args[:signer_email]
signer1.name = envelope_args[:signer_name]
signer1.role_name = ''
signer1.note = ''
signer1.status = 'created'
signer1.delivery_method = 'email'
signer1.recipient_id = '1'
signer1.routing_order = '1'

phone_number = DocuSign_eSign::RecipientIdentityPhoneNumber.new
phone_number.country_code = envelope_args[:country_code]
phone_number.number = envelope_args[:phone_number]

input_option = DocuSign_eSign::RecipientIdentityInputOption.new
input_option.name = 'phone_number_list'
input_option.value_type = 'PhoneNumberList'
input_option.phone_number_list = [phone_number]

identity_verification = DocuSign_eSign::RecipientIdentityVerification.new

identity_verification.workflow_id = workflow_id
identity_verification.input_options = [input_option]

signer1.identity_verification = identity_verification

sign_here1 = DocuSign_eSign::SignHere.new
sign_here1.name = 'SignHereTab'
sign_here1.anchor_string = '/sn1/'
sign_here1.anchor_units = 'pixels'
sign_here1.anchor_x_offset = '20'
sign_here1.anchor_y_offset = '10'

# 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 = DocuSign_eSign::Tabs.new({
                                          signHereTabs: [sign_here1]
                                        })
signer1.tabs = signer1_tabs

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

## Step 5. Call the eSignature REST API

Now that you have constructed your API headers and request body, you can send the envelope with the [Envelopes:create](/docs/esign-rest-api/reference/envelopes/envelopes/create) method. 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/eg020SigningViaEmailWithPhoneAuthentication.sh), [C#](https://github.com/docusign/code-examples-csharp/blob/master/launcher-csharp/eSignature/Examples/RecipientAuthPhone.cs), [Java](https://github.com/docusign/code-examples-java/blob/master/src/main/java/com/docusign/controller/eSignature/examples/EG020ControllerPhoneAuthentication.java), [Node.js](https://github.com/docusign/code-examples-node/blob/master/lib/eSignature/examples/phoneAuthentication.js), [PHP](https://github.com/docusign/code-examples-php/blob/master/src/Services/Examples/eSignature/PhoneAuthenticationService.php),  [PowerShell](https://github.com/docusign/code-examples-powershell/blob/master/examples/eSignature/eg020SigningViaEmailWithPhoneAuthentication.ps1), [Python](https://github.com/docusign/code-examples-python/blob/master/app/eSignature/examples/eg020_phone_authentication.py), or [Ruby](https://github.com/docusign/code-examples-ruby/blob/master/app/services/e_sign/eg020_phone_authentication_service.rb).

**`Bash`**

```bash title="Bash"
curl --request POST "https://demo.docusign.net/restapi/v2.1/accounts/${account_id}/envelopes" \
     "${Headers[@]}" \
     --data-binary @${request_data} \
     --output ${response}
```

**`C#`**

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

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

**`Java`**

```java title="Java"
EnvelopeDefinition envelope = PhoneAuthenticationService.createEnvelope(args.getSignerName(), args.getSignerEmail(), args.getCountryCode(),
        args.getPhoneNumber(), workflowId);
```

**`Node.js`**

```javascript title="Node.js"
let envelopesApi = new docusign.EnvelopesApi(dsApiClient);
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()}`);
    }
});
```

**`PHP`**

```php title="PHP"
$envelope_api = $clientService->getEnvelopeApi();
$envelopeResponse = $envelope_api->createEnvelopeWithHttpInfo($args['account_id'], $envelope_definition);

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

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

**`PowerShell`**

```text title="PowerShell"
$uri = "https://demo.docusign.net/restapi/v2.1/accounts/$APIAccountId/envelopes"
try {
	Write-Output "Response:"
	$result = Invoke-WebRequest -uri $uri -headers $headers -body $body -method POST
	$result.content
}
catch {
	$int = 0
	foreach ($header in $_.Exception.Response.Headers) {
		if ($header -eq "X-DocuSign-TraceToken") { Write-Output "TraceToken : " $_.Exception.Response.Headers[$int] }
		$int++
	}
	Write-Output "Error : "$_.ErrorDetails.Message
	Write-Output "Command : "$_.InvocationInfo.Line
}
```

**`Python`**

```python title="Python"
envelopes_api = EnvelopesApi(api_client)
(results, status, headers) = envelopes_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}")
```

**`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
```

## 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.

**`Sample response`**

```json title="Sample response"
{
  "documents": [
    {
      "documentBase64": "JVBERi...VPRgo=",
      "name": "Lorem Ipsum",
      "fileExtension": "pdf",
      "documentId": "1"
    }
  ],
  "emailBlurb": "Sample text for email body",
  "emailSubject": "Please Sign",
  "envelopeIdStamping": "true",
  "recipients": {
    "signers": [
      {
        "name": "Susan Signer",
        "email": "test@example.com",
        "roleName": "",
        "note": "",
        "routingOrder": 3,
        "status": "created",
        "tabs": {
          "signHereTabs": [
            {
              "documentId": "1",
              "name": "SignHereTab",
              "pageNumber": "1",
              "recipientId": "1",
              "tabLabel": "SignHereTab",
              "xPosition": "75",
              "yPosition": "572"
            }
          ]
        },
        "templateAccessCodeRequired": null,
        "deliveryMethod": "email",
        "recipientId": "1",
        "identityVerification": {
          "workflowId": "c368e411-xxxx-xxxx-xxxx-dca94ac539ae",
          "steps": null,
          "inputOptions": [
            {
              "name": "phone_number_list",
              "valueType": "PhoneNumberList",
              "phoneNumberList": [
                {
                  "countryCode": "1",
                  "number": "4155551212"
                }
              ]
            }
          ]
        }
      }
    ]
  },
  "status": "Sent"
}
```

## 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 [Recipient authentication](/docs/esign-rest-api/esign101/concepts/recipients/auth).
* 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.