All posts
· 5 min read

Holosign API Quickstart: From No Key to a Signed PDF

Holosign API Quickstart

Beta. The Holosign API is in beta — endpoints and behavior may still change.

Six calls take you from no API key to a signed, downloaded PDF: mint a key, upload a document, send it, learn when it’s done, watch the signer act, then download the result. Every request and response below was captured from a real run of this exact sequence against the test environment — nothing here is invented.

1. Get a key

Click Settings in the left sidebar, then scroll down to the API Key section (below Plan & Billing and the HubSpot integration). Click Generate — the plaintext key is shown to you exactly once, in a panel with a copy button. Save it now: Holosign cannot show it to you again once you navigate away.

Before you click: generating a key revokes your previous one immediately. An owner has exactly one active key at a time, and the change takes effect on your very next request — if anything else is currently using your old key, it stops working the moment you generate a new one.

Every call below authenticates with this key as a bearer token:

Authorization: Bearer hsk_live_YOUR_API_KEY

2. Upload and create a draft

Creating a document never sends it — this call only uploads the PDF and persists a draft. It’s a multipart/form-data request with two parts: a file part (the PDF itself) and a metadata part (a JSON string naming the document, its signers, and where each field goes on the page). Like every mutating call in this API, it requires a fresh Idempotency-Key header — any non-empty string you generate yourself, typically a UUID.

curl -i https://app.holosign.co/api/v1/documents \
  -X POST \
  -H "Authorization: Bearer hsk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: 98a88c46-557c-4804-8271-c31a2434469f" \
  -F "file=@walkthrough.pdf;type=application/pdf" \
  -F 'metadata={"name":"Holosign API Walkthrough Fixture","signers":[{"key":"s1","name":"Jordan Rivera","email":"jordan@example.com","order":0}],"fields":[{"signer_key":"s1","type":"signature","page":1,"x":12,"y":25,"width":30,"height":6,"required":true}]}'

# HTTP/1.1 201 Created
# {"id":"8285cab8-9895-41de-ae84-a0cf08a0de46","name":"Holosign API Walkthrough Fixture","status":"draft","created_at":"2026-08-20T09:46:03.778088+00:00","sent_at":null,"completed_at":null,"expires_at":null,"signers":[{"id":"d9eae1db-471d-4d85-a015-d819ef5ed079","name":"Jordan Rivera","email":"jordan@example.com","order":0,"signed_at":null}]}

Field coordinates are percentages, not points or pixels: x/y/width/height are each 0-100, a percentage of the page’s own width or height. x/y place the field’s top-left corner, and y is measured from the top of the page. A field at x: 12, y: 25, width: 30, height: 6 sits near the upper-left of the page, about a third of the page wide and a twentieth of it tall — not 12 or 650 points from anywhere. The API does not currently reject out-of-range values, so a value in points or pixels will not error; it will just place the field somewhere you didn’t intend, possibly off the visible page entirely.

A successful call returns 201 with the document’s full representation. Its status reads draft — nobody has been emailed anything yet.

3. Send it

A second call, its own fresh Idempotency-Key, starts the send:

curl -X POST https://app.holosign.co/api/v1/documents/8285cab8-9895-41de-ae84-a0cf08a0de46/send \
  -H "Authorization: Bearer hsk_live_YOUR_API_KEY" \
  -H "Idempotency-Key: d722c4ca-855f-4884-9743-770887e3ff13" \
  -H "Content-Type: application/json" \
  -d '{}'

# HTTP/1.1 202 Accepted
# {"id":"8285cab8-9895-41de-ae84-a0cf08a0de46","name":"Holosign API Walkthrough Fixture","status":"sending","created_at":"2026-08-20T09:46:03.778088+00:00","sent_at":null,"completed_at":null,"expires_at":null,"signers":[{"id":"d9eae1db-471d-4d85-a015-d819ef5ed079","name":"Jordan Rivera","email":"jordan@example.com","order":0,"signed_at":null}]}

Read this response carefully — it is not a completion. Sending is asynchronous: the call returns 202 immediately, and the document’s status in that same response is sending — a non-terminal status. The actual work (preparing the PDF, emailing every signer) happens after this response has already gone back to you. A 202 from this endpoint never carries a finished, terminal status in its body — if you ever see one that does, something has changed and you should not build against it.

4. Learn the outcome

There are two ways to find out that the send actually finished, and the webhook is the primary one: once the PDF is prepared and every signer’s email is out, Holosign delivers a sent event to your configured receiver. For the full delivery shape, the signature you need to verify, and how to configure a receiver in the first place, see the API reference — it’s not repeated here.

If you can’t receive a webhook, polling the same canonical read every other step in this walkthrough uses is the documented fallback. Keep polling until status leaves sending:

curl https://app.holosign.co/api/v1/documents/8285cab8-9895-41de-ae84-a0cf08a0de46 \
  -H "Authorization: Bearer hsk_live_YOUR_API_KEY"

# HTTP/1.1 200 OK
# {"id":"8285cab8-9895-41de-ae84-a0cf08a0de46","name":"Holosign API Walkthrough Fixture","status":"sent","created_at":"2026-08-20T09:46:03.778088+00:00","sent_at":"2026-08-20T09:46:05.45+00:00","completed_at":null,"expires_at":"2026-09-03T09:46:05.373+00:00","signers":[{"id":"d9eae1db-471d-4d85-a015-d819ef5ed079","name":"Jordan Rivera","email":"jordan@example.com","order":0,"signed_at":null}]}

In this real run, the document left sending on the second poll, about two seconds after the send call — that’s how fast the async work actually was here, not a promise about every run.

5. The signer signs

Each signer named at creation time receives a unique signing link by email once the send completes. The first time a signer opens that link, Holosign fires a viewed event — exactly once per signer, no matter how many times they reload the page. When the signer finishes their signing steps, a signed event follows. Once every signer on the document has signed, Holosign bakes the final, certificate-stamped PDF and fires completed. None of this requires another call from you — it’s driven entirely by what the signer does in their browser, and every event lands wherever your webhook receiver (or your poll loop) is already watching.

If you’re polling GET /v1/documents/{id} to detect completed rather than waiting on the webhook, expect this to take as long as the signer takes — anywhere from seconds to several minutes, entirely outside your control. In the run this guide is captured from, the signer took about six minutes; a poll loop on a fixed interval (the walkthrough that produced this guide polls every 5 seconds) rather than a tight loop is the right shape here, exactly like the send-side fallback poll above.

6. Download the completed PDF

The finished PDF is only available once the document has actually reached completed. Asking for it any earlier is a conflict, not a missing-file error — the document exists, it just isn’t ready yet:

curl -i https://app.holosign.co/api/v1/documents/8285cab8-9895-41de-ae84-a0cf08a0de46/download \
  -H "Authorization: Bearer hsk_live_YOUR_API_KEY"

# HTTP/1.1 200 OK
# Content-Type: application/pdf
# Content-Disposition: attachment; filename="Holosign API Walkthrough Fixture.pdf"; filename*=UTF-8''Holosign%20API%20Walkthrough%20Fixture.pdf
# Content-Length: 730738
# (730738 bytes of PDF data, not shown)

A successful download returns 200 with Content-Type: application/pdf and a Content-Disposition header carrying both an ASCII-folded filename and a UTF-8 filename*, so the document’s real name survives even if it contains characters plain ASCII can’t represent.

See also

For the full request and response schema of every endpoint — including every error code, the rate limits, idempotency behavior, and how to receive and verify webhooks — see the API reference.