Skip to main content
New Voice
August 3, 2026
Solved

How to create an envelope with a Payment Item field using the C# .NET SDK

  • August 3, 2026
  • 1 reply
  • 33 views

Hi Team,

I am implementing the DocuSign Payments feature using the C# .NET SDK and would appreciate some guidance.

My requirement is to:

  • Upload a PDF document through my ASP.NET Core Web API.
  • Create a new envelope programmatically (without using an existing envelope ID).
  • Add a signer.
  • Add a Payment Item field to the envelope.
  • Configure a payment amount.
  • Send the envelope so that the signer is prompted to make the payment during the signing process.

I have reviewed the Payments documentation and several community posts, but I could not find a complete REST API or C# SDK example that demonstrates how to create the Payment Item field programmatically.

Could someone please clarify the following?

  1. Which REST API endpoint or .NET SDK classes should be used to add a Payment Item field while creating an envelope?
  2. Is the Payment Item field represented as a Formula Tab with a paymentDetails object, or is there another recommended approach?
  3. Is there a complete C# (.NET) example that uploads a PDF, creates an envelope, configures the Payment Item field, and sends the envelope?
  4. Is there any official documentation that explains how to implement this feature using the eSignature REST API and .NET SDK?

Any guidance, sample code, or documentation links would be greatly appreciated.

Thank you!

Best answer by Koll.Klienstuber

@bharathshyam Sending a payment using C# is possible. 
The resources I’d suggest is:
“How to send a request for payment”
https://developers.docusign.com/docs/esign-rest-api/how-to/request-a-payment/

This article walks through the steps required with sample C# code. 

 

The full C# code sample from that article is pasted below if it helps. It’s found under “Step 3. Create the envelope definition“

EnvelopeDefinition envelope = MakeEnvelope(signerEmail, signerName, ccEmail, ccName, envStatus, gatawayAccountId, gatewayName, gatewayDisplayName);
private static EnvelopeDefinition MakeEnvelope(
string signerEmail,
string signerName,
string ccEmail,
string ccName,
string envStatus,
string gatewayAccountId,
string gatewayName,
string gatewayDisplayName)
{
// Data for this method
// signerEmail
// signerName
// ccEmail
// ccName
// envStatus

// document 1 (html) has multiple tags:
// /l1q/ and /l2q/ -- quantities: drop down
// /l1e/ and /l2e/ -- extended: payment lines
// /l3t/ -- total -- formula
//
// The envelope has two recipients.
// recipient 1 - signer
// recipient 2 - cc
// The envelope will be sent first to the signer.
// After it is signed, a copy is sent to the cc person.

///////////////////////////////////////////////////////////////////
// //
// NOTA BENA: This method programmatically constructs the //
// order form. For many use cases, it would be //
// better to create the order form as a template //
// using the DocuSign web tool as a WYSIWYG //
// form designer. //
// //
///////////////////////////////////////////////////////////////////

// Order form constants
int l1Price = 5;
int l2Price = 150;
int currencyMultiplier = 100;
string l1Name = "Harmonica";
string l1Description = $"${l1Price} each",
l2Name = "Xylophone";
string l2Description = $"${l2Price} each";

// Payment line items
PaymentLineItem paymentLineIteml1 = new PaymentLineItem
{
Name = l1Name,
Description = l1Description,
AmountReference = "l1e",
},
paymentLineIteml2 = new PaymentLineItem
{
Name = l2Name,
Description = l2Description,
AmountReference = "l2e",
};
PaymentDetails paymentDetails = new PaymentDetails
{
GatewayAccountId = gatewayAccountId,
CurrencyCode = "USD",
GatewayName = gatewayName,
GatewayDisplayName = gatewayDisplayName,
LineItems = new List<PaymentLineItem> { paymentLineIteml1, paymentLineIteml2 },
};

// read file from a local directory
// The read could raise an exception if the file is not available!
string doc1Html1 = System.IO.File.ReadAllText("order_form.html");

// Substitute values into the HTML
// Substitute for: {signerName}, {signerEmail}, {ccName}, {ccEmail}
var doc1Html2 = doc1Html1.Replace("{signerName}", signerName)
.Replace("{signerEmail}", signerEmail)
.Replace("{ccName}", ccName)
.Replace("{ccEmail}", ccEmail);

// create the envelope definition
EnvelopeDefinition env = new EnvelopeDefinition
{
EmailSubject = "Please complete your order",
};

// add the documents
string doc1B64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(doc1Html2));
Document doc1 = new Document
{
DocumentBase64 = doc1B64,
Name = "Order form", // can be different from actual file name
FileExtension = "html", // Source data format. Signed docs are always pdf.
DocumentId = "1", // a label used to reference the doc
};
env.Documents = new List<Document> { doc1 };

// create a signer recipient to sign the document, identified by name and email
// We're setting the parameters via the object creation
Signer signer1 = new Signer
{
Email = signerEmail,
Name = signerName,
RecipientId = "1",
RoutingOrder = "1",
};

// routingOrder (lower means earlier) determines the order of deliveries
// to the recipients. Parallel routing order is supported by using the
// same integer as the order for two or more recipients.

// create a cc recipient to receive a copy of the documents, identified by name and email
// We're setting the parameters via setters
CarbonCopy cc1 = new CarbonCopy
{
Email = ccEmail,
Name = ccName,
RoutingOrder = "2",
RecipientId = "2",
};

// Create signHere fields (also known as tabs) on the documents,
// We're using anchor (autoPlace) positioning
SignHere signHere1 = new SignHere
{
AnchorString = "/sn1/",
AnchorYOffset = "10",
AnchorUnits = "pixels",
AnchorXOffset = "20",
};
ListItem listItem0 = new ListItem { Text = "none", Value = "0" },
listItem1 = new ListItem { Text = "1", Value = "1" },
listItem2 = new ListItem { Text = "2", Value = "2" },
listItem3 = new ListItem { Text = "3", Value = "3" },
listItem4 = new ListItem { Text = "4", Value = "4" },
listItem5 = new ListItem { Text = "5", Value = "5" },
listItem6 = new ListItem { Text = "6", Value = "6" },
listItem7 = new ListItem { Text = "7", Value = "7" },
listItem8 = new ListItem { Text = "8", Value = "8" },
listItem9 = new ListItem { Text = "9", Value = "9" },
listItem10 = new ListItem { Text = "10", Value = "10" }
;
List listl1Q = new List
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l1q/",
AnchorYOffset = "-10",
AnchorUnits = "pixels",
AnchorXOffset = "0",
ListItems = new List<ListItem>
{
listItem0, listItem1, listItem2,
listItem3, listItem4, listItem5, listItem6,
listItem7, listItem8, listItem9, listItem10,
},
Required = "true",
TabLabel = "l1q",
},
listl2Q = new List
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l2q/",
AnchorYOffset = "-10",
AnchorUnits = "pixels",
AnchorXOffset = "0",
ListItems = new List<ListItem>
{
listItem0,
listItem1,
listItem2,
listItem3,
listItem4,
listItem5,
listItem6,
listItem7,
listItem8,
listItem9,
listItem10,
},
Required = "true",
TabLabel = "l2q",
};

// create two formula tabs for the extended price on the line items
FormulaTab formulal1E = new FormulaTab
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l1e/",
AnchorYOffset = "-8",
AnchorUnits = "pixels",
AnchorXOffset = "105",
TabLabel = "l1e",
Formula = $"[l1q] * {l1Price}",
RoundDecimalPlaces = "0",
Required = "true",
Locked = "true",
DisableAutoSize = "false",
},
formulal2E = new FormulaTab
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l2e/",
AnchorYOffset = "-8",
AnchorUnits = "pixels",
AnchorXOffset = "105",
TabLabel = "l2e",
Formula = $"[l2q] * {l2Price}",
RoundDecimalPlaces = "0",
Required = "true",
Locked = "true",
DisableAutoSize = "false",
},

// Formula for the total
formulal3T = new FormulaTab
{
Font = "helvetica",
Bold = "true",
FontSize = "size12",
AnchorString = "/l3t/",
AnchorYOffset = "-8",
AnchorUnits = "pixels",
AnchorXOffset = "50",
TabLabel = "l3t",
Formula = $"[l1e] + [l2e]",
RoundDecimalPlaces = "0",
Required = "true",
Locked = "true",
DisableAutoSize = "false",
};

// Hidden formula for the payment itself
FormulaTab formulaPayment = new FormulaTab
{
TabLabel = "payment",
Formula = $"([l1e] + [l2e]) * {currencyMultiplier}",
RoundDecimalPlaces = "0",
PaymentDetails = paymentDetails,
Hidden = "true",
Required = "true",
Locked = "true",
DocumentId = "1",
PageNumber = "1",
XPosition = "0",
YPosition = "0",
};

// Tabs are set per recipient / signer
Tabs signer1Tabs = new Tabs
{
SignHereTabs = new List<SignHere> { signHere1 },
ListTabs = new List<List> { listl1Q, listl2Q },
FormulaTabs = new List<FormulaTab> { formulal1E, formulal2E, formulal3T, formulaPayment },
};
signer1.Tabs = signer1Tabs;

// Add the recipients to the envelope object
Recipients recipients = new Recipients
{
Signers = new List<Signer> { signer1 },
CarbonCopies = new List<CarbonCopy> { cc1 },
};
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 = envStatus;

return env;
}

 

The endpoint would be the standard create envelope endpoint and inside the body of the request is where you define details of the envelope like the documents, fields (payment tab), and recipients. 

https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopes/create/

 

Our quick start also has an example and the link to it is here: 

https://developers.docusign.com/docs/esign-rest-api/quickstart/overview/

It states: 

Additional configuration: Docusign payments
To use the payments code example in the Multiple code examples, Authorization Code Grant, and JWT Grant project Quickstart, first create a test payment gateway on the Payments page in your developer account. See Configure a payment gateway for details.

Once you've created a payment gateway, save the Gateway Account ID GUID to launcher-csharp/appsettings.json.

1 reply

Docusign Employee
August 4, 2026

@bharathshyam Sending a payment using C# is possible. 
The resources I’d suggest is:
“How to send a request for payment”
https://developers.docusign.com/docs/esign-rest-api/how-to/request-a-payment/

This article walks through the steps required with sample C# code. 

 

The full C# code sample from that article is pasted below if it helps. It’s found under “Step 3. Create the envelope definition“

EnvelopeDefinition envelope = MakeEnvelope(signerEmail, signerName, ccEmail, ccName, envStatus, gatawayAccountId, gatewayName, gatewayDisplayName);
private static EnvelopeDefinition MakeEnvelope(
string signerEmail,
string signerName,
string ccEmail,
string ccName,
string envStatus,
string gatewayAccountId,
string gatewayName,
string gatewayDisplayName)
{
// Data for this method
// signerEmail
// signerName
// ccEmail
// ccName
// envStatus

// document 1 (html) has multiple tags:
// /l1q/ and /l2q/ -- quantities: drop down
// /l1e/ and /l2e/ -- extended: payment lines
// /l3t/ -- total -- formula
//
// The envelope has two recipients.
// recipient 1 - signer
// recipient 2 - cc
// The envelope will be sent first to the signer.
// After it is signed, a copy is sent to the cc person.

///////////////////////////////////////////////////////////////////
// //
// NOTA BENA: This method programmatically constructs the //
// order form. For many use cases, it would be //
// better to create the order form as a template //
// using the DocuSign web tool as a WYSIWYG //
// form designer. //
// //
///////////////////////////////////////////////////////////////////

// Order form constants
int l1Price = 5;
int l2Price = 150;
int currencyMultiplier = 100;
string l1Name = "Harmonica";
string l1Description = $"${l1Price} each",
l2Name = "Xylophone";
string l2Description = $"${l2Price} each";

// Payment line items
PaymentLineItem paymentLineIteml1 = new PaymentLineItem
{
Name = l1Name,
Description = l1Description,
AmountReference = "l1e",
},
paymentLineIteml2 = new PaymentLineItem
{
Name = l2Name,
Description = l2Description,
AmountReference = "l2e",
};
PaymentDetails paymentDetails = new PaymentDetails
{
GatewayAccountId = gatewayAccountId,
CurrencyCode = "USD",
GatewayName = gatewayName,
GatewayDisplayName = gatewayDisplayName,
LineItems = new List<PaymentLineItem> { paymentLineIteml1, paymentLineIteml2 },
};

// read file from a local directory
// The read could raise an exception if the file is not available!
string doc1Html1 = System.IO.File.ReadAllText("order_form.html");

// Substitute values into the HTML
// Substitute for: {signerName}, {signerEmail}, {ccName}, {ccEmail}
var doc1Html2 = doc1Html1.Replace("{signerName}", signerName)
.Replace("{signerEmail}", signerEmail)
.Replace("{ccName}", ccName)
.Replace("{ccEmail}", ccEmail);

// create the envelope definition
EnvelopeDefinition env = new EnvelopeDefinition
{
EmailSubject = "Please complete your order",
};

// add the documents
string doc1B64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(doc1Html2));
Document doc1 = new Document
{
DocumentBase64 = doc1B64,
Name = "Order form", // can be different from actual file name
FileExtension = "html", // Source data format. Signed docs are always pdf.
DocumentId = "1", // a label used to reference the doc
};
env.Documents = new List<Document> { doc1 };

// create a signer recipient to sign the document, identified by name and email
// We're setting the parameters via the object creation
Signer signer1 = new Signer
{
Email = signerEmail,
Name = signerName,
RecipientId = "1",
RoutingOrder = "1",
};

// routingOrder (lower means earlier) determines the order of deliveries
// to the recipients. Parallel routing order is supported by using the
// same integer as the order for two or more recipients.

// create a cc recipient to receive a copy of the documents, identified by name and email
// We're setting the parameters via setters
CarbonCopy cc1 = new CarbonCopy
{
Email = ccEmail,
Name = ccName,
RoutingOrder = "2",
RecipientId = "2",
};

// Create signHere fields (also known as tabs) on the documents,
// We're using anchor (autoPlace) positioning
SignHere signHere1 = new SignHere
{
AnchorString = "/sn1/",
AnchorYOffset = "10",
AnchorUnits = "pixels",
AnchorXOffset = "20",
};
ListItem listItem0 = new ListItem { Text = "none", Value = "0" },
listItem1 = new ListItem { Text = "1", Value = "1" },
listItem2 = new ListItem { Text = "2", Value = "2" },
listItem3 = new ListItem { Text = "3", Value = "3" },
listItem4 = new ListItem { Text = "4", Value = "4" },
listItem5 = new ListItem { Text = "5", Value = "5" },
listItem6 = new ListItem { Text = "6", Value = "6" },
listItem7 = new ListItem { Text = "7", Value = "7" },
listItem8 = new ListItem { Text = "8", Value = "8" },
listItem9 = new ListItem { Text = "9", Value = "9" },
listItem10 = new ListItem { Text = "10", Value = "10" }
;
List listl1Q = new List
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l1q/",
AnchorYOffset = "-10",
AnchorUnits = "pixels",
AnchorXOffset = "0",
ListItems = new List<ListItem>
{
listItem0, listItem1, listItem2,
listItem3, listItem4, listItem5, listItem6,
listItem7, listItem8, listItem9, listItem10,
},
Required = "true",
TabLabel = "l1q",
},
listl2Q = new List
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l2q/",
AnchorYOffset = "-10",
AnchorUnits = "pixels",
AnchorXOffset = "0",
ListItems = new List<ListItem>
{
listItem0,
listItem1,
listItem2,
listItem3,
listItem4,
listItem5,
listItem6,
listItem7,
listItem8,
listItem9,
listItem10,
},
Required = "true",
TabLabel = "l2q",
};

// create two formula tabs for the extended price on the line items
FormulaTab formulal1E = new FormulaTab
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l1e/",
AnchorYOffset = "-8",
AnchorUnits = "pixels",
AnchorXOffset = "105",
TabLabel = "l1e",
Formula = $"[l1q] * {l1Price}",
RoundDecimalPlaces = "0",
Required = "true",
Locked = "true",
DisableAutoSize = "false",
},
formulal2E = new FormulaTab
{
Font = "helvetica",
FontSize = "size11",
AnchorString = "/l2e/",
AnchorYOffset = "-8",
AnchorUnits = "pixels",
AnchorXOffset = "105",
TabLabel = "l2e",
Formula = $"[l2q] * {l2Price}",
RoundDecimalPlaces = "0",
Required = "true",
Locked = "true",
DisableAutoSize = "false",
},

// Formula for the total
formulal3T = new FormulaTab
{
Font = "helvetica",
Bold = "true",
FontSize = "size12",
AnchorString = "/l3t/",
AnchorYOffset = "-8",
AnchorUnits = "pixels",
AnchorXOffset = "50",
TabLabel = "l3t",
Formula = $"[l1e] + [l2e]",
RoundDecimalPlaces = "0",
Required = "true",
Locked = "true",
DisableAutoSize = "false",
};

// Hidden formula for the payment itself
FormulaTab formulaPayment = new FormulaTab
{
TabLabel = "payment",
Formula = $"([l1e] + [l2e]) * {currencyMultiplier}",
RoundDecimalPlaces = "0",
PaymentDetails = paymentDetails,
Hidden = "true",
Required = "true",
Locked = "true",
DocumentId = "1",
PageNumber = "1",
XPosition = "0",
YPosition = "0",
};

// Tabs are set per recipient / signer
Tabs signer1Tabs = new Tabs
{
SignHereTabs = new List<SignHere> { signHere1 },
ListTabs = new List<List> { listl1Q, listl2Q },
FormulaTabs = new List<FormulaTab> { formulal1E, formulal2E, formulal3T, formulaPayment },
};
signer1.Tabs = signer1Tabs;

// Add the recipients to the envelope object
Recipients recipients = new Recipients
{
Signers = new List<Signer> { signer1 },
CarbonCopies = new List<CarbonCopy> { cc1 },
};
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 = envStatus;

return env;
}

 

The endpoint would be the standard create envelope endpoint and inside the body of the request is where you define details of the envelope like the documents, fields (payment tab), and recipients. 

https://developers.docusign.com/docs/esign-rest-api/reference/envelopes/envelopes/create/

 

Our quick start also has an example and the link to it is here: 

https://developers.docusign.com/docs/esign-rest-api/quickstart/overview/

It states: 

Additional configuration: Docusign payments
To use the payments code example in the Multiple code examples, Authorization Code Grant, and JWT Grant project Quickstart, first create a test payment gateway on the Payments page in your developer account. See Configure a payment gateway for details.

Once you've created a payment gateway, save the Gateway Account ID GUID to launcher-csharp/appsettings.json.