Sign a PDF with Go
Send a document for signature from Go with net/http and a context deadline.
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.
payload, _ := json.Marshal(map[string]any{
"name": "Services agreement",
"file_url": "https://example.com/agreement.pdf",
"signers": []map[string]string{{"name": "Jane Doe", "email": "jane@example.com", "role": "client"}},
"webhook_url": "https://example.com/hooks/pdfverified",
})
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "POST", "https://api.pdfverified.com/v1/documents", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PDFVERIFIED_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil { log.Fatal(err) }
defer res.Body.Close()
io.Copy(os.Stdout, res.Body)What this ecosystem gets wrong first
- Always defer res.Body.Close(). A response body left open holds the connection out of the pool, and under load that becomes a slow leak rather than a crash, which is the hardest kind to find.
- http.DefaultClient has no timeout at all. The context deadline above is what saves you; a bare http.Post can hang for as long as the other end keeps the socket open.
- Use hmac.Equal to compare webhook signatures rather than ==. Constant-time comparison is the whole point, and Go gives it to you for free.
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.