Sign a PDF with C# and .NET
Send a document for signature from C# using HttpClient the way .NET actually wants you to.
Drop your document here and sign it now. PDF, Word and Excel all work: a .docx or .xlsx is laid out in your browser exactly as it was written, so there is nothing to convert first. Add a signature, a date, a company stamp or a watermark, then download it sealed. Free to start, no account, and the file is never uploaded to open it.
Create a document and get a signing link
One POST creates the document, places the fields and returns a signing URL for each signer. The key stays in the environment.
// Registered once: builder.Services.AddHttpClient("pdfverified", c => {
// c.BaseAddress = new Uri("https://api.pdfverified.com/v1/");
// c.DefaultRequestHeaders.Authorization =
// new AuthenticationHeaderValue("Bearer", config["PdfVerified:ApiKey"]);
// });
var client = factory.CreateClient("pdfverified");
var res = await client.PostAsJsonAsync("documents", new {
name = "Services agreement",
file_url = "https://example.com/agreement.pdf",
signers = new[] { new { name = "Jane Doe", email = "jane@example.com", role = "client" } },
webhook_url = "https://example.com/hooks/pdfverified",
});
res.EnsureSuccessStatusCode();
var doc = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(doc.GetProperty("id").GetString());What this ecosystem gets wrong first
- Use IHttpClientFactory rather than newing up an HttpClient. A new HttpClient per call exhausts sockets, and a single static one misses DNS changes: the factory is the fix for both, and it is the mistake most .NET integrations make first.
- PostAsJsonAsync uses System.Text.Json, which is camelCase by default. The snake_case field names above are set explicitly, so either name your anonymous type members to match or configure a naming policy.
- EnsureSuccessStatusCode throws without including the response body, which makes a 422 hard to debug. Read the content first if you want the reason in your logs.
Handling the webhook
When a signer completes, we POST the document id, the completion time, the signer record and the SHA-256 fingerprint of the sealed file to your webhook_url. Verify the signature header against the raw request body before you trust any of it, and respond 2xx quickly: do the slow work afterwards, because a webhook that takes ten seconds to answer is a webhook that gets retried.
The fingerprint in that payload is the same value the public verification page checks against, so you can store it and let anybody confirm a document you hold is the one that was signed.
What you get back
- A sealed PDF, with the signature part of the page rather than an annotation some viewers skip
- An audit certificate naming each signer, the time, the address and which checks they passed
- A SHA-256 fingerprint, and a public verification URL that needs no account to open
- Optional company stamps with serial numbers, applied in the same call
The REST API is included on the Business plan at $15 a month rather than sold as an add-on, which is the part worth comparing: several of the platforms a developer evaluates price the API separately and considerably higher.