Sign inStart free trial

HydraSign API

Send documents for signature from your own software, get notified the moment they're signed, and download the signed PDF. Available on the Pro and Business plans.

AuthenticationSend an envelopeText tagsTemplatesStatus & PDFIn-person signingWebhooksClaude connectorErrors & limits

Authentication

Create an API key in HydraSign under Account → Integrations & API. Send it as a bearer token on every request. The base URL is https://your-domain/api/v1.

curl https://your-domain/api/v1/me -H "Authorization: Bearer hs_live_..."

Requests act on behalf of the company that owns the key. Keep keys on your server — never put them in a website or mobile app.

Send an envelope

POST/envelopes creates the envelope and, unless you pass "send": false, emails/texts the first signer right away.

{
  "title": "Work Authorization — Job T-1001",
  "message": "Please sign so we can start.",
  "routing": "sequential",                     // or "parallel"
  "metadata": { "job_id": "T-1001" },          // your IDs; returned in every webhook
  "documents": [ { "name": "authorization.pdf", "file_base64": "JVBERi0xLjcK..." } ],
  "recipients": [
    { "ref": "customer", "name": "Jane Customer", "email": "jane@example.com" },
    { "ref": "tech", "name": "Tom Tech", "phone": "206-555-0100", "delivery": "sms" },
    { "name": "Office", "email": "office@example.com", "role": "cc" }
  ],
  "text_tags": [
    { "text": "Customer signature:",   "recipient": "customer", "type": "signature" },
    { "text": "Technician signature:", "recipient": "tech",     "type": "signature" }
  ],
  "fields": [
    { "recipient": "customer", "type": "date_signed", "page": 1, "x": 190, "y": 372 }
  ]
}
Recipient fieldNotes
refYour label, used by fields and text_tags (you can also use the recipient's index, 0-based).
rolesigner (default) or cc (gets a copy).
deliveryemail, sms or both. Text messages need the Business plan.
routing_orderFor sequential signing. Defaults to the order you list them.
access_codeOptional code the signer must enter before viewing.

Field types: signature, initials, date_signed, full_name, email, company, title, text, checkbox. Positions in fields are in PDF points (1/72 inch) measured from the top-left of the page; width/height are optional. Up to 10 documents, 25 MB each (PDF, JPG or PNG).

The response is the envelope object.

Text tags (automatic field placement)

Instead of coordinates, tell HydraSign what text to look for. It finds every occurrence in the PDF and places the field right after it (or on top of it with "position": "on"). Great for forms your system already generates — print a label like Customer signature:, or a hidden tag like \s1\ in white text.

PropertyNotes
textText to find (case-insensitive unless match_case).
recipient, typeWho fills it and what kind of field.
offset_x, offset_yNudge in points. Default: 6pt right of the text, sitting on the line.
width, height, required, labelOptional.
documentLimit to one document (index). Default: all.

If a tag isn't found, the request fails with a 400 that names it — nothing is sent.

Templates

Build a template once in HydraSign (documents, roles and fields), then send it with only the people:

GET/templates — lists templates and their role names.

POST /envelopes
{
  "template_id": "1f0c...",
  "recipients": [
    { "role_name": "Customer",   "name": "Ali Hassan", "email": "ali@example.com" },
    { "role_name": "Technician", "name": "Sam Ruiz",   "phone": "+12065550100", "delivery": "sms" }
  ],
  "metadata": { "job_id": "T-1002" }
}

Status & signed PDF

GET/envelopes/{id} — the envelope object.
GET/envelopes?status=completed&limit=25 — newest first; page with before=<created_at>. Filter by your IDs with metadata_key=job_id&metadata_value=T-1001.
GET/envelopes/{id}/pdf — the sealed, signed PDF with Certificate of Completion (when completed).
GET/envelopes/{id}/documents/{document_id} — an original document.
POST/envelopes/{id}/remind · POST/envelopes/{id}/void {"reason": "..."} · POST/envelopes/{id}/send (for drafts)

Envelope object

{
  "id": "6b1e...", "title": "Work Authorization — Job T-1001", "status": "completed",
  "metadata": { "job_id": "T-1001" }, "source": "api",
  "created_at": "...", "sent_at": "...", "completed_at": "...", "signed_pdf_sha256": "c50c...",
  "documents": [ { "id": "...", "name": "authorization", "pages": 2 } ],
  "recipients": [ { "id": "...", "name": "Jane Customer", "email": "jane@example.com", "role": "signer",
                    "status": "signed", "viewed_at": "...", "signed_at": "..." } ],
  "fields": [ { "id": "...", "recipient_id": "...", "type": "text", "label": "Site address", "value": "18500 Main St" } ]
}

Statuses: envelope — draft, sent, completed, declined, voided, expired. Recipient — created (not their turn yet), sent, viewed, signed, declined, completed (CC copy sent).

In-person signing

POST/envelopes/{id}/signing-link {"recipient_id": "..."} returns a fresh signing URL for a signer whose turn it is — open it on your tablet or phone and hand it over. Their previously emailed link stops working.

Webhooks

Add an endpoint under Integrations (or POST/webhooks {"url": "...", "events": []}). HydraSign POSTs JSON to it when something happens:

EventWhen
envelope.sentAn envelope was sent.
recipient.sentA signer was sent their link (it's their turn).
recipient.viewedA signer opened the document.
recipient.signedA signer finished.
envelope.completedEveryone signed — the signed PDF is ready.
envelope.declined · envelope.voided · envelope.expiredThe envelope ended without completing.
POST https://your-app.com/hydrasign-webhook
HydraSign-Event: envelope.completed
HydraSign-Signature: t=1794677735,v1=5f2c...

{ "id": "evt uuid", "type": "envelope.completed", "created_at": "...",
  "data": { "envelope": { ...envelope object... }, "recipient": null } }

Return any 2xx within 10 seconds. Failed deliveries are retried for about two days (1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h). The data shows the envelope as it is when delivered; use id to ignore duplicates.

Verify the signature

// Node.js — use the raw request body
const crypto = require('crypto');
function verify(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
  const expected = crypto.createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Zapier / Make: create a "Webhooks by Zapier → Catch Hook" (or Make "Custom webhook") trigger and paste its URL as a HydraSign webhook. To send documents from a Zap, use a "Webhooks by Zapier → POST" action to /api/v1/envelopes with your API key.

Claude connector

Every API key also works as a Claude connector. In Claude, open Settings → Connectors → Add custom connector, name it HydraSign, and paste https://your-domain/mcp/hs_live_... (shown when you create the key). Then ask things like "who still hasn't signed?", "send the work authorization template to Jane at jane@example.com", or "remind everyone on the Job T-1001 envelope". Tools: account summary, list/get envelopes, list templates, send from template, send reminder, void, in-person signing link.

Errors & limits

StatusMeaning
400Something in the request is wrong — the error message says what.
401Missing, invalid or revoked API key.
402Your plan doesn't include this (API on Pro/Business; texts on Business), or the trial/subscription has ended.
404Not found, or belongs to another company.
429More than 300 requests per minute — slow down and retry.

All errors look like {"error": "message"}.