AnySign API

Invoicing and e-signatures over plain HTTPS + JSON. Everything the dashboard does, your code can do — it's the same API. Money is integer cents. Field coordinates are fractions of the page (x from the left, y from the top). Base URL: https://api.anysignhq.com

OpenAPI spec

Everything on this page comes from one OpenAPI 3.1 document, and it is served as-is at /openapi.yaml. Import it into Postman or Insomnia, or generate a client from it — you do not need the repository.

A test keeps the two honest: an endpoint cannot appear in the spec without appearing here, or here without existing in the spec.

Download the spec
use it
# grab it from this site
curl -O <this-site>/openapi.yaml

# generate a typed client from it
npx @openapitools/openapi-generator-cli generate \
  -i openapi.yaml -g typescript-fetch -o ./anysign-client

# or skip codegen — maintained SDKs ship for
# TypeScript, Python, Ruby, PHP, Java and .NET
npm install @anysign/sdk

Authentication

Authenticate /v1 requests with a bearer API key. Live keys start with sk_live_; test keys with sk_test_ and never send real email. Create and revoke keys in Settings → API keys.

A key carries exactly the scopes you tick when you create it — envelopes:read, org:admin and so on. Tick nothing for a full-access key. Either way, keep them server-side, never in a browser.

curl
curl https://api.anysignhq.com/v1/invoices \
  -H "Authorization: Bearer sk_live_..."

Errors & idempotency

Errors return conventional status codes with a JSON body: { error: { code, message } }. 4xx means the request needs fixing; 5xx means we do.

Every POST accepts an Idempotency-Key header — retry a timed-out create safely and you'll get the original result instead of a duplicate.

error shape
HTTP/1.1 422 Unprocessable Entity

{
  "error": {
    "code": "invalid_field",
    "message": "line_items[0].unit_cents must be a positive integer"
  }
}

Versioning

Send Anysign-Version to pin the behaviour you built against. Leave it off and you get the current version.

Every response echoes the version it was served under, so you can assert on it. A version we do not know is refused with a 400 rather than quietly served under different rules than you expect.

Breaking changes arrive as a new dated version; the one you pinned keeps working.

curl
curl https://api.anysignhq.com/v1/envelopes \
  -H "Authorization: Bearer sk_live_..." \
  -H "Anysign-Version: 2026-08-14"

# every response carries it back
Anysign-Version: 2026-08-14

SDKs and Zapier

Every SDK is a thin, dependency-free wrapper over the same /v1 endpoints documented here — same resources, same idempotency, same errors. Nothing is available through an SDK that is not available over plain HTTPS.

Prefer no code? The Zapier app covers the events most workflows hang off: triggers for envelope completed, declined, approved and paid, recipient reassigned, invoice paid and new customer, and actions to create an invoice, create an envelope (optionally from a template) or tag one. It uses your API key and pins Anysign-Version, so a future breaking change cannot alter what a published Zap receives.

During the beta the Zapier app is shared privately — email [email protected] and we will add you.

install
npm install @anysign/sdk        # TypeScript / JavaScript
pip install anysign              # Python
gem install anysign              # Ruby
composer require anysign/sdk     # PHP
# Maven: dev.anysign:anysign     # Java
dotnet add package AnySign       # .NET

Guide · Create and send an invoice

One call creates the invoice, computes totals server-side, assigns the number and emails the hosted view/pay link (send: true).

curl
curl https://api.anysignhq.com/v1/invoices \
  -H "Authorization: Bearer sk_live_..." \
  -H "Idempotency-Key: inv-2026-07-0042" \
  -d '{
    "customer_id": "cus_9d2f1c",
    "currency": "USD",
    "due_date": "2026-07-27",
    "tax_percent": 8.75,
    "line_items": [
      { "description": "Brand identity — phase 2",
        "quantity": 1, "unit_cents": 480000 },
      { "description": "Design system retainer",
        "quantity": 2, "unit_cents": 110000 }
    ],
    "send": true
  }'
TypeScript
const res = await fetch("https://api.anysignhq.com/v1/invoices", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANYSIGN_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "inv-2026-07-0042",
  },
  body: JSON.stringify({
    customer_id: "cus_9d2f1c",
    currency: "USD",
    due_date: "2026-07-27",
    tax_percent: 8.75,
    line_items: [
      { description: "Brand identity — phase 2", quantity: 1, unit_cents: 480_000 },
      { description: "Design system retainer", quantity: 2, unit_cents: 110_000 },
    ],
    send: true, // create + send in one call
  }),
});

const invoice = await res.json();
console.log(invoice.number, invoice.hosted_url);

Guide · Send an envelope for signature

Create the envelope with documents (base64), signers and fields in a single call — at create time, signer_id and document_id accept index strings ("0", "1", …). Then send.

curl
# 1. create — documents, signers, fields in one call.
#    signer_id / document_id take index strings at create.
curl https://api.anysignhq.com/v1/envelopes \
  -H "Authorization: Bearer sk_live_..." \
  -d '{
    "title": "Consulting agreement",
    "signing_order": "sequential",
    "signers": [
      { "name": "Ada Chen",  "email": "[email protected]",  "order": 1 },
      { "name": "R. Okafor", "email": "[email protected]",   "order": 2 }
    ],
    "documents": [
      { "name": "agreement.pdf", "content_base64": "'$(base64 -i agreement.pdf)'" }
    ],
    "fields": [
      { "document_id": "0", "signer_id": "0", "kind": "signature",
        "page": 4, "x": 0.12, "y": 0.68, "w": 0.22, "h": 0.055 },
      { "document_id": "0", "signer_id": "0", "kind": "date",
        "page": 4, "x": 0.12, "y": 0.75 },
      { "document_id": "0", "signer_id": "1", "kind": "signature",
        "page": 4, "x": 0.58, "y": 0.68, "w": 0.22, "h": 0.055 }
    ]
  }'

# 2. send — emails tokenized signing links
curl -X POST https://api.anysignhq.com/v1/envelopes/env_8f14e2/send \
  -H "Authorization: Bearer sk_live_..."
TypeScript
import { readFile } from "node:fs/promises";

const pdf = (await readFile("agreement.pdf")).toString("base64");

const create = await fetch("https://api.anysignhq.com/v1/envelopes", {
  method: "POST",
  headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    title: "Consulting agreement",
    signing_order: "sequential",
    signers: [
      { name: "Ada Chen", email: "[email protected]", order: 1 },
      { name: "R. Okafor", email: "[email protected]", order: 2 },
    ],
    documents: [{ name: "agreement.pdf", content_base64: pdf }],
    // index strings resolve to the records created above
    fields: [
      { document_id: "0", signer_id: "0", kind: "signature",
        page: 4, x: 0.12, y: 0.68, w: 0.22, h: 0.055 },
      { document_id: "0", signer_id: "1", kind: "signature",
        page: 4, x: 0.58, y: 0.68, w: 0.22, h: 0.055 },
    ],
  }),
});
const envelope = await create.json();

await fetch(`https://api.anysignhq.com/v1/envelopes/${envelope.id}/send`, {
  method: "POST",
  headers: { Authorization: `Bearer ${key}` },
});

Guide · Embedded signing sessions

Keep signers inside your product: mint a short-lived signing URL for a specific signer and redirect (or iframe) them to it. Links live 15 minutes and work once.

curl
curl https://api.anysignhq.com/v1/envelopes/env_8f14e2/signing_sessions \
  -H "Authorization: Bearer sk_live_..." \
  -d '{
    "signer_id": "sgn_1a9b3c",
    "return_url": "https://yourapp.com/deals/42?signed=1"
  }'

# → { "url": "https://vault.anysignhq.com/sign/tok_…", "expires_at": "…" }
#   valid 15 minutes, single use — redirect or iframe your signer there
TypeScript
const res = await fetch(
  `https://api.anysignhq.com/v1/envelopes/${envelopeId}/signing_sessions`,
  {
    method: "POST",
    headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
    body: JSON.stringify({
      signer_id: signerId,
      return_url: "https://yourapp.com/deals/42?signed=1",
    }),
  },
);

const { url, expires_at } = await res.json();
// valid 15 minutes, single use
redirect(url);

Guide · Verify webhook signatures

Deliveries are signed with HMAC-SHA256 over <timestamp>.<raw body> using your whsec_ secret. Verify in constant time and reject stale timestamps.

the delivery
# Deliveries look like:
POST /hooks/anysign HTTP/1.1
Anysign-Signature: t=1760358000,v1=5f8a2c…
Content-Type: application/json

{ "type": "envelope.completed", "data": { "id": "env_8f14e2", … } }

# Recompute HMAC-SHA256 over "<t>.<raw body>" with your whsec_ secret,
# compare to v1 in constant time, and reject timestamps older than 5 min.
TypeScript (Node)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyAnysignSignature(
  payload: string,            // raw request body
  header: string,             // Anysign-Signature: t=<unix>,v1=<hex>
  secret: string,             // whsec_…
  toleranceSeconds = 300,
): boolean {
  const parts = Object.fromEntries(
    header.split(",").map((kv) => kv.split("=") as [string, string]),
  );
  const t = Number(parts.t);
  if (!parts.v1 || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) {
    return false; // stale or malformed — reject replays
  }

  const expected = createHmac("sha256", secret)
    .update(`${parts.t}.${payload}`)
    .digest("hex");

  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(parts.v1, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

Customers

The people and companies you bill and sign with. Customers are referenced by invoices via customer_id.

POST/v1/customersCreate customer
ParameterTypeDescription
name*stringDisplay name.
emailstringWhere invoices and signing requests are sent.
addressstringBilling address, shown on invoices.
tax_idstringTax identifier printed on invoices.
metadataobjectArbitrary key–value data.

↳ 201 · Customer

GET/v1/customersList customers
ParameterTypeDescription
limitintegerPage size, default 25.
starting_afterstringCursor — last customer id of the previous page.

↳ 200 · { data: Customer[], has_more }

GET/v1/customers/{id}Get customer

No body parameters.

↳ 200 · Customer

Invoices

Money is always integer cents — no floats, ever. Create as draft, then send; sending assigns the invoice number and emails your customer a hosted view/pay link.

POST/v1/invoicesCreate invoice (draft, or send immediately with send=true)
ParameterTypeDescription
customer_id*stringWho to bill.
currencystringISO 4217, default USD.
line_itemsLineItem[]{ description, quantity, unit_cents } each.
tax_percentnumberApplied after discount.
discount_percentnumberApplied to the subtotal.
issue_date / due_datedateYYYY-MM-DD.
notesstringPrinted at the bottom of the invoice.
sendbooleanSend immediately after create.

↳ 201 · Invoice

GET/v1/invoicesList invoices
ParameterTypeDescription
statusenumdraft · sent · viewed · partially_paid · paid · overdue · void
limit / starting_after—Cursor pagination.

↳ 200 · { data: Invoice[], has_more }

GET/v1/invoices/{id}Get invoice

No body parameters.

↳ 200 · Invoice

PATCH/v1/invoices/{id}Update draft invoice

No body parameters.

↳ 200 · Invoice

POST/v1/invoices/{id}/sendAssign number, email customer the hosted view/pay link

No body parameters.

↳ 200 · Invoice

POST/v1/invoices/{id}/voidVoid invoice

No body parameters.

↳ 200 · Invoice

GET/v1/invoices/{id}/pdfDownload rendered PDF

No body parameters.

↳ 200 · application/pdf

POST/v1/recurring_schedulesCreate recurring schedule — instantiates and sends its template invoice each interval
ParameterTypeDescription
customer_id*stringWho to bill.
template*InvoiceInputThe invoice to instantiate each run.
interval_unitenumweek · month (default) · year.
interval_countintegerEvery N units, default 1.
start_atdateFirst run; RFC 3339 or YYYY-MM-DD, default now.

↳ 201 · RecurringSchedule

GET/v1/recurring_schedulesList recurring schedules

No body parameters.

↳ 200 · { data }

GET/v1/recurring_schedules/{id}Get recurring schedule

No body parameters.

↳ 200 · RecurringSchedule

PATCH/v1/recurring_schedules/{id}Update schedule — pause/resume via active

No body parameters.

↳ 200 · RecurringSchedule

DELETE/v1/recurring_schedules/{id}Delete schedule

No body parameters.

↳ 204

Envelopes

An envelope is documents + signers + fields. Field coordinates are fractions of the page: x from the left, y from the TOP, w/h as fractions, page is 1-based. At create time, signer_id and document_id accept index strings ("0", "1", …) that resolve to the created records. Field kinds: signature · initials · date · text · checkbox · dropdown · radio · attachment. Give a field a name to reference it from another field's show_if_name (show it only when that field holds a value) or formula (arithmetic, e.g. "quantity * unit_price"). Formulas and read_only fields are filled by us, never by the signer.

POST/v1/envelopesCreate envelope — documents (base64), signers and fields in one call
ParameterTypeDescription
title*stringSubject of the signing request.
signers*Signer[]{ name, email, phone?, role?, order, access_code?, delivery? } each. role is signer (default), cc, approver or viewer; delivery in_person is never emailed a link.
documentsDocument[]{ name, content_base64 } — PDF or DOCX, or upload separately.
fieldsField[]{ document_id, signer_id, kind, name?, page, x, y, w, h, required, options?, read_only?, value?, show_if_name?, show_if_value?, formula? }.
tagsstring[]Free-form labels. These are the folders — an envelope can be in several at once.
allow_reassignbooleanMay a recipient hand their responsibility to someone else? Default true.
paymentPayment{ amount_cents, currency?, description? } — collect a card in Stripe Checkout before any signature is accepted.
remind_every_daysintegerAuto-remind pending signers every N days; 0 disables.
signing_orderenumparallel (default) or sequential.
signature_levelenumSES (default). AES, which verifies each signer via SMS code, is coming soon on Business and is rejected today.
languageenumen (default) · de · fr · es — signer emails + signing page.
template_idstringEnvelope template to merge defaults from.
expires_in_daysintegerDefault 30.

↳ 201 · Envelope

GET/v1/envelopesList envelopes
ParameterTypeDescription
statusenumdraft · sent · completed · declined · voided · expired.
qstringFree-text over titles and signer names/emails.
tagstringOnly envelopes carrying this tag.
limitintegerDefault 25, max 100.
starting_afterstringCursor — the last id from the previous page.

↳ 200 · { data, has_more }

GET/v1/envelopes/{id}Get envelope with signers, documents, fields

No body parameters.

↳ 200 · Envelope

POST/v1/envelopes/{id}/documentsUpload a PDF to a draft envelope (multipart or JSON base64)

No body parameters.

↳ 201 · EnvelopeDocument

POST/v1/envelopes/{id}/sendSend — emails tokenized signing links per signing order

No body parameters.

↳ 200 · Envelope

POST/v1/envelopes/{id}/voidVoid envelope

No body parameters.

↳ 200 · Envelope

POST/v1/envelopes/{id}/remindRe-send signing links to pending signers

No body parameters.

↳ 204

POST/v1/envelopes/{id}/signing_sessionsCreate an embedded signing URL for a signer (15 min, single use)
ParameterTypeDescription
signer_id*stringWhich signer the session is for.
return_urlstringWhere to send the signer afterwards.

↳ 201 · { url, expires_at }

POST/v1/envelopes/{id}/in_person_sessionsStart in-person signing on the host's own device (every plan, never emailed)
ParameterTypeDescription
signer_id*stringThe signer standing in front of you.

↳ 201 · { url, return_code, signer_name, expires_at }

POST/v1/envelopes/{id}/sender_sessionsEmbedded sender — a single-use URL to place fields and send from your own UI

No body parameters.

↳ 201 · { url, envelope_id, expires_at }

PUT/v1/envelopes/{id}/tagsReplace an envelope's tags

No body parameters.

↳ 200 · Envelope

GET/v1/envelope_tagsEvery tag in use, with counts

No body parameters.

↳ 200 · { data: TagCount[] }

GET/v1/field_kindsThe published field-type catalogue

No body parameters.

↳ 200 · { data: string[] }

GET/v1/envelopes/{id}/fields/{field_id}/attachmentDownload a file a signer uploaded into an attachment field

No body parameters.

↳ 200 · application/octet-stream

GET/v1/exports/envelopesZip of executed documents, certificates and manifests
ParameterTypeDescription
statusenumNarrow the archive to one status.
tagstringNarrow the archive to one tag.
include_auditbooleanAdd audit-trail.json per envelope.

↳ 200 · application/zip

GET/v1/envelope_tagsEvery tag in use, with envelope counts

No body parameters.

↳ 200 · { data: TagCount[] }

GET/v1/field_kindsThe published field-type catalogue

No body parameters.

↳ 200 · { data: string[] }

GET/v1/reports/envelopesEnvelope analytics — counts, completion rate, time to complete, per sender
ParameterTypeDescription
fromdateSent-at lower bound; defaults to 30 days ago.
todateInclusive upper bound; defaults to now.
formatenumcsv returns the rows instead of the summary.

↳ 200 · { sent, completed, declined, expired, voided, completion_rate, … } or text/csv

GET/v1/envelopes/{id}/audit_trailHash-chained audit trail

No body parameters.

↳ 200 · { data: AuditEvent[], chain_valid }

GET/v1/envelopes/{id}/documents/{doc_id}/downloadDownload executed (sealed), original, or certificate PDF
ParameterTypeDescription
variantenumexecuted (default) · original · certificate

↳ 200 · application/pdf

Templates

Reusable envelope field layouts or invoice defaults.

POST/v1/templatesCreate template
ParameterTypeDescription
kind*enumenvelope or invoice.
name*stringDisplay name.
layout*objectThe reusable layout payload.

↳ 201 · Template

GET/v1/templatesList templates (filter with ?kind=)

No body parameters.

↳ 200 · { data: Template[] }

GET/v1/templates/{id}Get template

No body parameters.

↳ 200 · Template

DELETE/v1/templates/{id}Delete template

No body parameters.

↳ 204

Bulk send

One envelope template plus a recipient list becomes one individual envelope per recipient — each recipient is the only signer on their own envelope and never sees the others. Business plan only; other workspaces get 402 plan_required. Maximum 500 recipients per batch. The whole list is validated before anything is sent: if any row is unusable the request returns 400 with a details array and nothing goes out. Fan-out is queued (one job per recipient) and each envelope consumes envelope quota exactly like a normal send.

POST/v1/bulk_sendsCreate and queue a bulk send
ParameterTypeDescription
template_id*stringAn envelope template — its fields and signing settings are snapshotted.
titlestringOverrides the template. Use {{column}} to personalise per recipient.
messagestringOverrides the template; also supports {{column}}.
documentsobject[]{ name, content_base64 } — the PDFs every recipient signs.
rowsobject[]{ name, email, phone?, access_code?, merge? } per recipient.
csvstringCSV alternative to rows. Needs "name" and "email" columns; any other column becomes a merge value. Handles BOM, CRLF and quoted fields.

↳ 201 · BulkSend · 400 with per-row details · 402 plan_required

GET/v1/bulk_sendsList bulk sends (limit, starting_after)

No body parameters.

↳ 200 · { data, has_more }

GET/v1/bulk_sends/{id}Get a bulk send with per-recipient status

No body parameters.

↳ 200 · BulkSend

POST/v1/bulk_sends/{id}/retryRe-queue failed recipients — already-sent ones are untouched

No body parameters.

↳ 200 · BulkSend · 409 when nothing failed

Webhook endpoints

We POST events to your endpoints, signed with HMAC-SHA256 in the Anysign-Signature header as t=<unix>,v1=<hex>. The whsec_ secret is returned once, on create.

POST/v1/webhook_endpointsCreate endpoint (secret returned once)
ParameterTypeDescription
url*stringHTTPS endpoint to deliver to.
eventsstring[]Event names to subscribe to; empty = all.

↳ 201 · WebhookEndpoint (with secret)

GET/v1/webhook_endpointsList endpoints

No body parameters.

↳ 200 · { data }

DELETE/v1/webhook_endpoints/{id}Delete endpoint

No body parameters.

↳ 204

GET/v1/webhook_eventsThe published event catalogue

No body parameters.

↳ 200 · { data: string[] }

GET/v1/webhook_deliveriesRecent delivery attempts, with status codes and errors
ParameterTypeDescription
endpoint_idstringOnly deliveries to this endpoint.
statusenumpending · delivered · failed.
limitintegerDefault 50, max 200.

↳ 200 · { data: WebhookDelivery[] }

GET/v1/webhook_deliveries/{id}One delivery, including the exact signed payload

No body parameters.

↳ 200 · WebhookDelivery

POST/v1/webhook_deliveries/{id}/replaySend it again — a new attempt; the original stays in the log

No body parameters.

↳ 202 · WebhookDelivery

Vault

Store a document once, then hand it out over links that are allowlisted, expiring, revocable and view-logged. Holding the link proves nothing: the recipient also has to be an address you named, and that is re-checked on every request, so revoking or de-allowlisting bites on their next click. It runs inbound too: a document request mints one open link with a named slot per file you want back, closes each slot as it fills, and chases the recipient on a cadence until everything is in. That link is write-only — the person uploading can never read what has already been sent. Both recipients' own endpoints are a browser flow, not an integration surface, and are not part of this API. One call turns a stored document into a draft envelope.

POST/v1/vault/documentsStore a document
ParameterTypeDescription
content_base64*stringThe file, up to 20 MB decoded.
namestringFilename shown in the app and on download.
thumbnail_base64stringOptional page-one preview for the grid, up to 120 KB. PNG, JPEG or WebP only — sniffed from the bytes, so an SVG is refused. Our own uploaders draw it in the browser; omit it and the tile falls back to an icon.

↳ 201 · VaultDocument (content_type is sniffed from the bytes, never your word for it)

GET/v1/vault/documentsList stored documents
ParameterTypeDescription
limitintegerPage size, default 25.
starting_afterstringCursor — last document id of the previous page.

↳ 200 · { data: VaultDocument[], has_more }

GET/v1/vault/documents/{id}Get a stored document

No body parameters.

↳ 200 · VaultDocument

DELETE/v1/vault/documents/{id}Delete a document and revoke every link pointing at it

No body parameters.

↳ 204 · the bytes and the thumbnail are destroyed (the blob purge is queued and retried); the audit record and access log are kept

GET/v1/vault/documents/{id}/downloadDownload the stored bytes — always an attachment, always nosniff

No body parameters.

↳ 200 · application/octet-stream (PDF, PNG and JPEG keep their media type)

GET/v1/vault/documents/{id}/thumbnailThe page-one preview, inline and cacheable — 404 when the document has none

No body parameters.

↳ 200 · image/png | image/jpeg | image/webp, ETag on the document hash

POST/v1/vault/documents/{id}/sharesOpen an allowlisted share link
ParameterTypeDescription
allow_emailsstring[]Addresses that may open it.
allow_domainsstring[]Domains that may open it; matched after the last @, exactly.
expires_in_daysinteger0 = never, maximum 365.
namestringWhat you call this link internally.
nda_textstringA click-through NDA the recipient acknowledges before the first view. Recorded with their email, IP and browser — an audit line, not an executed agreement.
watermarkbooleanStamp every page of the PDFs this link serves with the viewer's email and the time they opened it. Paid. Non-PDFs are served unchanged; a digitally signed PDF answers 409 rather than being served unmarked.

↳ 201 · VaultShare with the url · 400 if the allowlist is empty · 402 unless your plan sells viewer watermarking

GET/v1/vault/documents/{id}/sharesList a document's share links
ParameterTypeDescription
limitintegerPage size, default 25.
starting_afterstringCursor — last share id of the previous page.

↳ 200 · { data: VaultShare[], has_more } — without their urls

POST/v1/vault/documents/{id}/envelopeSend a stored document for signature — creates a draft envelope
ParameterTypeDescription
signers{ name, email }[]Who it is going to.
titlestringDefaults to the document's name.
messagestringShown to the signers.

↳ 201 · { envelope_id, url } — the builder, where the fields get placed · 409 for anything but PDF/Word

POST/v1/vault/sharesOpen one link over a set of documents
ParameterTypeDescription
document_ids*string[]1–20 documents, in the order the recipient sees them; the first is the primary. Repeats are collapsed. Only this route takes it — the document-scoped create answers 400.
allow_emailsstring[]Addresses that may open it.
allow_domainsstring[]Domains that may open it; matched after the last @, exactly.
expires_in_daysinteger0 = never, maximum 365.
namestringWhat you call this link internally.
nda_textstringA click-through NDA the recipient acknowledges before the first view. Recorded with their email, IP and browser — an audit line, not an executed agreement.
watermarkbooleanSee POST /v1/vault/documents/{id}/shares.

↳ 201 · VaultShare with the url · 402 unless your plan sells sharing several documents on one link

GET/v1/vault/sharesEvery link your workspace has sent, newest first
ParameterTypeDescription
limitinteger1–100, default 25.
starting_afterstringA share id from the previous page.

↳ 200 · { data: VaultShare[], has_more } — each row carries document_name, never the url. Links whose document was deleted still list, revoked.

GET/v1/vault/shares/{id}One share link in full, including its NDA text

No body parameters.

↳ 200 · VaultShare — the list projection carries has_nda only. Every read carries documents[], the link's files with their names and sizes in order.

PATCH/v1/vault/shares/{id}Change a live link's watermark or expiry
ParameterTypeDescription
watermarkbooleanOmit to leave it as it is. Turning it on is checked against your plan; turning it off never is.
expires_in_daysintegerA new deadline counted from now, 0..365, where 0 is never. Omit to leave the expiry alone — send only the fields you changed, because 0 is a value rather than an absent field.

↳ 200 · VaultShare · 402 unless your plan sells viewer watermarking · 409 on a revoked or expired link

POST/v1/vault/shares/{id}/documentsAdd documents to a link that is already out — the URL does not change
ParameterTypeDescription
document_idsstring[]Appended after the link's current documents; ids already on it are ignored. The 20-document cap and the plan check apply to the resulting total, so growing a one-document link to two is checked exactly as creating a two-document link is.

↳ 200 · VaultShare · 402 unless your plan sells multi-document links · 409 on a revoked or expired link

POST/v1/vault/shares/{id}/revokeRevoke a link, killing every grant and code already issued on it

No body parameters.

↳ 200 · VaultShare

POST/v1/vault/shares/{id}/revealShow a share's URL again

No body parameters.

↳ 200 · { url }

PUT/v1/vault/shares/{id}/allowlistReplace who may open a share — takes effect on their next request
ParameterTypeDescription
allow_emailsstring[]The complete new list, not a patch.
allow_domainsstring[]The complete new list, not a patch.

↳ 200 · VaultShare

PUT/v1/vault/shares/{id}/ndaSet or clear the click-through NDA a recipient accepts before the first view
ParameterTypeDescription
nda_textstringUp to 20000 characters. Empty removes the click-through; the acceptances already recorded are kept.

↳ 200 · VaultShare · 402 unless your plan sells the click-through NDA

POST/v1/vault/requestsAsk someone for documents — one open, write-only link
ParameterTypeDescription
name*stringWhat you are asking for; the recipient sees it.
items*{ name, note }[]1–20 named slots, one file each.
recipient_emailstringWho to send it to and chase. Required if chase_every_days > 0.
recipient_namestringHow to address them.
messagestringA note shown on the upload page and in the email.
expires_in_daysinteger0 = never, maximum 365.
chase_every_daysinteger0 = never, maximum 30.
max_chasesinteger1–12, default 6 — the reminder loop always ends.

↳ 201 · VaultRequest with the url · 400 if there are no items or chasing has nobody to chase

GET/v1/vault/requestsList document requests with their received counts
ParameterTypeDescription
limitintegerPage size, default 25.
starting_afterstringCursor — last request id of the previous page.

↳ 200 · { data: VaultRequest[], has_more } — without their urls

GET/v1/vault/requests/{id}Get a request and each item's status

No body parameters.

↳ 200 · VaultRequest

POST/v1/vault/requests/{id}/closeClose a request — the link stops accepting files and the chase stops

No body parameters.

↳ 200 · VaultRequest

POST/v1/vault/requests/{id}/revealShow a request's URL again

No body parameters.

↳ 200 · { url }

GET/v1/vault/shares/{id}/viewsA share's access log, newest first
ParameterTypeDescription
limitintegerPage size, default 25.
starting_afterstringCursor — last view id of the previous page.

↳ 200 · { data: VaultShareView[], has_more } — opened · otp_sent · otp_failed · denied · verified · viewed · downloaded

GET/v1/vault/shared-with-meLive links other workspaces opened onto your address, by exact match or your domain
ParameterTypeDescription
limitintegerPage size, default 25, max 100.

↳ 200 · { data: VaultInboxShare[], has_more } · 403 for an API key, which is not a person, or an unconfirmed address

Compliance status

Which compliance features are live on the deployment you are talking to, and what an operator still has to switch on. Owner-only. Every feature degrades gracefully — nothing reported here ever blocks a signer.

GET/v1/compliance/statusDeployment compliance posture and operator warnings

No body parameters.

↳ 200 · { env, features: [{ key, label, status, message }], warnings, ready_for } · 403 if not an owner