Hanzo AI

DocuSign

DocuSign collects legally binding signatures on a document. Here that is /v1/esign — 13 operations, a signing link that carries its own token, and an audit trail you can read.

DocuSign sends a document to people and collects their signatures. /v1/esign (13 operations) is the same sequence: create a document, add recipients and fields, send it, and read the audit trail when it is done.

The shape that differs: the signer's link is the credential. A recipient does not have an account here. GET /v1/esign/o/{org}/sign/{token} is the whole session — the token names the org, the document and the recipient, and the signing routes carry no other authentication.

Start here

Three calls: mint a key, upload the PDF, add the person who signs it.

# 1. mint a key — sk- belongs on a server, pk- is safe in a browser
curl -sS -X POST https://api.hanzo.ai/v1/account/keys \
  -H "Authorization: Bearer $HANZO_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{"type":"secret"}'

# 2. upload the PDF — 201, and the document is in DRAFT
ID=$(curl -sS -X POST https://api.hanzo.ai/v1/esign/documents \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"title\":\"Mutual NDA\",\"pdfBase64\":\"$(base64 < nda.pdf | tr -d '\n')\"}" \
  | jq -r .id)

# 3. add the signer — the response carries their token
curl -sS -X POST "https://api.hanzo.ai/v1/esign/documents/$ID/recipients" \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"email":"[email protected]","name":"Dana Lee","role":"SIGNER"}'

You have a DRAFT document and one recipient, and step 3 answered a token — minted before anything is sent, and the entire credential the signing endpoint accepts. That is the shape difference from DocuSign in one call: the signer has no account, only the link built from that token.

Core capabilities

CapabilityWhat it doesOperations
/v1/esignUpload a PDF, add recipients and fields, send, read the audit trail13
/v1/dataroomHolds the documents and the links that share them — where a DocuSign template's reusable shape lives26
/v1/complianceSubjects, verifications and accreditation decisions — the identity check you run before handing over a link17

Nouns

DocuSignHanzo
AccountYour org, taken from the validated key
EnvelopeDocument — POST /v1/esign/documents
Document (inside an envelope)The document itself. One per envelope
Recipient / SignerPOST /v1/esign/documents/{id}/recipients
Tab (SignHere, DateSigned, Text)Field — POST /v1/esign/documents/{id}/fields
Routing ordersigningOrder on the recipient
Send envelopePOST /v1/esign/documents/{id}/send
Signing ceremony URLGET /v1/esign/o/{org}/sign/{token}
Certificate of completionGET /v1/esign/documents/{id}/audit
Completed PDFGET /v1/esign/documents/{id}/download
Decline to signPOST /v1/esign/o/{org}/sign/{token}/reject
Template libraryHanzo Dataroom — /v1/dataroom (26), documents and the links that share them

The call

DocuSign, creating and sending:

curl -sS -X POST \
  "https://demo.docusign.net/restapi/v2.1/accounts/$ACCT/envelopes" \
  -H "Authorization: Bearer $DS_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"emailSubject":"Please sign","status":"sent","documents":[…],"recipients":{…}}'

Hanzo — the same thing, as four calls that each do one thing:

# 1. the document — title and the base64 PDF, both required
ID=$(curl -sS -X POST https://api.hanzo.ai/v1/esign/documents \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"title\":\"Services Agreement\",\"pdfBase64\":\"$(base64 < contract.pdf | tr -d '\n')\"}" \
  | jq -r .id)

# 2. who signs it — the response carries the recipient id and their token
RCPT=$(curl -sS -X POST "https://api.hanzo.ai/v1/esign/documents/$ID/recipients" \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"email":"[email protected]","name":"A Signer","signingOrder":1}' \
  | jq -r .id)

# 3. where they sign — a field is placed against that recipient
curl -sS -X POST "https://api.hanzo.ai/v1/esign/documents/$ID/fields" \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d "{\"recipientId\":\"$RCPT\",\"type\":\"SIGNATURE\",\"page\":1,\"positionX\":120,\"positionY\":640}"

# 4. send
curl -sS -X POST "https://api.hanzo.ai/v1/esign/documents/$ID/send" \
  -H "Authorization: Bearer $HANZO_API_KEY"

A field's page and coordinates are the caller's numbers, kept as given — the route does not round them, so a template that positions fields fractionally ports without drift.

What does not carry

Templates live in the Dataroom, not on this API. DocuSign templates hold recipients, tabs and routing so an envelope can be created from one. Hanzo Dataroom (dataroom.hanzo.ai) is where documents and their reusable shapes are kept — /v1/dataroom (26) carries the datarooms, the documents and the links that share them. What /v1/esign publishes is the signing sequence itself, and it has no template noun: driving it from the API means posting the field list per document, which is what a template is once it stops going stale.

No bulk send. One document, one set of recipients. A hundred contracts is a hundred sequences, which is a loop rather than a feature.

No embedded signing ceremony. DocuSign's JS embeds the ceremony in your page with a recipient view URL. The signing link here is a page we serve.

Identity is verified somewhere else, not in the ceremony. DocuSign gates a signer with SMS, an access code or an ID check inside the envelope. The token in the link is the whole authentication here. Proving who someone is has its own capability — /v1/compliance carries subjects, records and accreditation decisions — so the check is a step you run before you hand the link over, rather than a setting on the document.

No connect webhooks yet. DocuSign pushes envelope events to a listener. Poll GET /v1/esign/documents/{id} for status, or subscribe on /v1/webhook if the event you need is already published there.

How is this guide?