SIGN PDF API · C#
Sign a PDF in C#.
This sign PDF API in C# example sends a template to one person, who signs on any device. Make a test key and a template, then run it. A test key sends nothing real and bills nothing.
SIGNED
Signed
C#
using Docustay.Api.Api;
using Docustay.Api.Client;
using Docustay.Api.Model;
var config = new Configuration { BasePath = Environment.GetEnvironmentVariable("DOCUSTAY_URL") ?? "https://app.docustay.app" };
config.AccessToken = Environment.GetEnvironmentVariable("DOCUSTAY_API_KEY");
var api = new DocumentsApi(config);
var request = new SendRequest(
templateId: Guid.Parse(Environment.GetEnvironmentVariable("DOCUSTAY_TEMPLATE_ID")!),
parties: new List<SendRequestPartiesInner> { new SendRequestPartiesInner(seat: "signer_1", name: "Rosa Alvarez", email: "rosa@example.com") });Send, listen, download
Three steps, one program.
1 · Install
Add the client.
dotnet add package Docustay.Api
The package targets .NET 8. Every call that creates something takes an idempotency key as its first argument: build one per attempt and reuse it when you retry. Set BasePath only when you point at a self-hosted install.
2 · Send
send.cs
using Docustay.Api.Api;
using Docustay.Api.Client;
using Docustay.Api.Model;
var config = new Configuration { BasePath = Environment.GetEnvironmentVariable("DOCUSTAY_URL") ?? "https://app.docustay.app" };
config.AccessToken = Environment.GetEnvironmentVariable("DOCUSTAY_API_KEY");
var api = new DocumentsApi(config);
var request = new SendRequest(
templateId: Guid.Parse(Environment.GetEnvironmentVariable("DOCUSTAY_TEMPLATE_ID")!),
parties: new List<SendRequestPartiesInner> { new SendRequestPartiesInner(seat: "signer_1", name: "Rosa Alvarez", email: "rosa@example.com") });
var doc = api.SendDocument(Guid.NewGuid().ToString(), request);
Console.WriteLine($"{doc.Id} {doc.State}"); This sends the template to one person. It reads the key and the template id from the environment.
3 · Then
Read the answer.
The C# program's answer holds the document's id and its state. Ask for it later with the same key, or get a signed webhook when it is signed. The quickstart shows the rest.
What happens next
A .NET client from NuGet: send from a service, a job or a console app.
When everyone has signed, the sealed PDF and its certificate go to everyone.
Certificate of completion
Document Services Agreement
Signed by Dana Whitfield · 14:02 UTC
Signed by Ada Lovelace · 14:09 UTC
File hash sha-256 9f2c…41ab
SIGNEDThe request, by hand
What the C# program sends.
| Part | Value |
|---|---|
| Method and path | POST /api/v1/documents/send |
| Authorization | Bearer, then your API key |
| Content-Type | application/json |
| Idempotency-Key | A fresh UUID for each document; keep it if you retry |
| Body | templateId and parties: a seat, a name and an email for each person |
The same request works from any language that can make an HTTPS call.
Line by line
What the C# program does.
Read it once and you can change it with confidence.
Base libraries only
The example uses System.Net.Http with top-level statements, so a one-file project on .NET 8 or newer is enough.
Build the JSON body
The body is a short JSON string with the templateId and one party for seat signer_1. A real program would build it with System.Text.Json.
Set the headers
Authorization carries the bearer key, the content is sent as application/json, and Idempotency-Key is a fresh Guid. Keep that value if you retry.
Check the status
A response that is not a success throws with the status and the body; otherwise the program prints the answer, which holds the document's id and its state.
When it goes wrong
Errors and retries in C#.
Every error from the API has the same shape: kind, a plain message, a requestId and a retryable flag.
Parse the error body
A failure comes back as a JSON object with a kind, a message, a requestId and a retryable flag. Deserialize it with the JSON library you already use and log the requestId.
Write the retry around the request
Retry a 429 after its Retry-After seconds and a 5xx after a pause, with the same Idempotency-Key each time. A generated C# client is available if you would rather not write that loop.
What is safe to retry
In C#, as anywhere, a 429 and a 5xx are safe to retry with the same Idempotency-Key: sending the same request again never sends a second document. A 400, 401, 403, 404 or 409 will give the same answer every time, so fix the cause before you try again.
Before you run it
What you need on hand.
Three things, none of them hard to get.
The .NET 8 SDK
Nothing to install from a package feed. The .NET SDK builds and runs the file, and HttpClient is part of the base libraries.
A test key
Make a key in the app under Developers, then API keys, and tick documents:read and documents:write. Give it to the C# program through DOCUSTAY_API_KEY. A key that starts dsk_test_ only does practice runs: the email goes to you and nothing counts.
A template id
Use your own copy of a built-in template, or one you made from HTML or a tagged PDF, and put its id in DOCUSTAY_TEMPLATE_ID before you run the C# file. Its seat names, such as signer_1, are what the parties in the request refer to.
Run it
Save the program as send.cs. It prints the document's id and its state, and the test email arrives in your own inbox within a minute or so.
Questions
Quick answers.
Does a test key send anything real?
No. A document sent with a dsk_test_ key is emailed only to you, carries a TEST watermark and is never counted.
Where do the key and template id come from?
From the environment: DOCUSTAY_API_KEY and DOCUSTAY_TEMPLATE_ID. The key never sits in the file.
How do I know it was signed?
Subscribe to documents.document.executed, or fetch the document by id.