API · Webhooks · Templates

Signatures from your own software.

Create signing requests from your app, let your signers sign on your branded page, and get the sealed PDF and its audit trail back by webhook. A REST API with idempotency keys, signed events and stable error codes.

API keys and webhooks come with the Enterprise plan. Public docs, an OpenAPI 3.1 spec, no SDK to install.

curl https://api.wesign.now/v1/signing-requests \
  -H "Authorization: Bearer $WSK_KEY" \
  -H "Idempotency-Key: case-4711/poa" \
  -F "file=@power-of-attorney.pdf" \
  -F 'signers=[{"email":"anna@example.ch","role":"client","name":"Anna Muster"}]' \
  -F "placement=anchors" \
  -F 'metadata={"case_id":"4711"}'

# → 201 Created
# {
#   "documentId": "8a1e4f9a-…",
#   "status": "pending",
#   "signers": [{ "role": "client", "signingUrl": "https://yourco.wesign.now/en/sign/…", "emailed": true, … }], …
# }
How it works

Four steps from your code to a sealed PDF.

Nothing to install: HTTPS, JSON and multipart. Each step links to the page of the docs that is its contract.

  1. Step 1

    Create the request

    One POST /v1/signing-requests with the PDF, the signers and how the fields are placed: anchors finds [[ls:signature:client]] markers in the PDF, explicit takes coordinates, auto_append adds a signature page. The answer carries the documentId and one signingUrl per signer.

    In the docs
    curl https://api.wesign.now/v1/templates/$TEMPLATE_ID/instantiate \
      -H "Authorization: Bearer $WSK_KEY" \
      -H "Idempotency-Key: case-4711/mandate" \
      -H "Content-Type: application/json" \
      -d '{
        "recipients": [{ "slot": 1, "email": "anna@example.ch", "name": "Anna Muster" }],
        "field_values": { "company.legal_name": "Muster AG", "company.tax_id": "CHE-123.456.789" },
        "metadata": { "case_id": "4711" }
      }'

    The same send from a locked template: POST /v1/templates/{id}/instantiate merges your field_values into the {{placeholders}} and invites the recipients.

  2. Step 2

    Your signer signs

    We email the invitation in the signer's language from your branded subdomain — or you deliver the link yourself with send_emails: false. Add a mobile number and require_sms_verification, and the signer enters a one-time code first: an advanced electronic signature (AES) instead of the email-link level (SES).

    In the docs
    "signers": [{
      "email": "anna@example.ch",
      "role": "client",
      "name": "Anna Muster",
      "locale": "de",
      "phone_e164": "+41791112233",
      "require_sms_verification": true
    }]
    
    # The invitation goes out in German from your branded subdomain.
    # Anna asks for the code on the signing page; the signature is AES once verified.
    # Deliver the link yourself instead: send_emails=false
  3. Step 3

    You get the event

    Register a webhook once for the workspace, or pass callback_url per request. Every delivery is HMAC-SHA256 signed, retried with exponential backoff and listed in a delivery log you can redeliver from. document.completed arrives once per document with signed_pdf_url, audit_trail_url and the file's sha256.

    In the docs
    POST https://your-app.example/wesign/callback
    X-WeSign-Event: document.completed
    X-WeSign-Signature: t=1757404800,v1=9c3b…a2f1
    
    {
      "event": "document.completed",
      "document_id": "8a1e4f9a-…",
      "metadata": { "case_id": "4711" },
      "signed_pdf_url": "https://api.wesign.now/v1/documents/8a1e4f9a-…/signed",
      "audit_trail_url": "https://api.wesign.now/v1/documents/8a1e4f9a-…/audit-trail",
      "sha256": "4f9a…d21c", …
    }
  4. Step 4

    Fetch the files

    GET /v1/documents/{id}/signed streams the PAdES-sealed PDF, every signature under one seal; /audit-trail renders the event log — SHA-256, time stamp, masked IPs — as a PDF, always in English. Both need your key. Compare the hash and store both files on your side.

    In the docs
    curl -LOJ -H "Authorization: Bearer $WSK_KEY" \
      https://api.wesign.now/v1/documents/$DOC_ID/signed
    
    curl -OJ -H "Authorization: Bearer $WSK_KEY" \
      https://api.wesign.now/v1/documents/$DOC_ID/audit-trail
    
    # Compare the file's SHA-256 with the event's sha256, then store both files on your side.

Every answer carries an X-Request-Id, and Settings → API keeps an API log of every call for 30 days — status, error code, the document concerned; bodies are never stored. An Idempotency-Key makes a retried send or instantiate safe. Each key may make 60 requests per minute.

Capabilities

Everything the API does today.

Templates and the field registry

Author a contract once with {{placeholders}}, lock it, and instantiate fills it from field_values. GET /v1/templates/{id} publishes the input schema; the workspace's field registry keeps keys and example values stable.

Anchors

Put [[ls:signature:client]] markers in your generated PDF and the fields land where the text is — no coordinates. The markers are masked before the signer sees the page.

SMS verification (AES)

phone_e164 and require_sms_verification: a one-time code before the document is shown or at the Sign press. Binds the signature to a phone — an advanced electronic signature.

Sequential signing

signing_mode: sequential invites one signer after the other; parallel is the default. Observers and webhooks follow each release.

Observers

observer_emails: CC-style recipients who never sign. Notified when the request goes out and when every signer has signed, with the final PDF and the certificate.

Multi-signer and envelopes

Several signers sign one PDF under one seal. An envelope of several files is several documents: each completes on its own and fires its own document.completed.

Embedded signing

Mint a short-lived single-signer session and render the signing view inside your own page — iframe or mobile webview, your branding, no API key in the browser. Enterprise.

Webhooks

Signed, retried with exponential backoff, full or minimal payload (without personal data), a delivery log with redelivery, and secret rotation that keeps the old secret valid for 24 hours.

PAdES-sealed and verifiable

Every signed PDF carries a PAdES seal; the RFC 3161 time stamp is kept with our records. Anyone can drop the file on /verify and get a verdict: authentic, tampered or unknown.

EU, CH or US data region

Each workspace pins its documents to one region: EU (default), Switzerland or US. Documents stay where they were created.

Swiss-made

Signatures framed under eIDAS and Swiss ZertES as SES and AES (no QES). Public docs, an OpenAPI 3.1 spec, and 90 days' notice before any breaking change.

Who builds on it

Software that puts a contract in front of a client.

Tax and fiduciary software

Engagement letters, powers of attorney and filing authorisations straight from the case file: the template carries the firm's text, your platform fills client and company data, the client signs on the firm's branded page. The audit trail answers a tax authority's query.

HR and recruiting platforms

Offers, contracts and staff-leasing agreements generated per candidate and sent sequentially — candidate first, then the employer — with the signed PDF back in the candidate record.

Fintech onboarding

Onboarding agreements and investor paperwork executed inside your flow, embedded or by link, with an SMS second factor where the risk asks for it, and a sealed, hash-verifiable PDF for compliance.

Agencies and document generators

Your tool produces the PDF, anchors place the fields, the client signs without an account. `metadata` carries your project id through every event back to your system.

Published customer stories:Zepf TaxesCurio Capital

API keys and webhooks come with Enterprise.

Legacy Teams workspaces keep their API keys and webhooks. Template sends through the API (instantiate, generate, confirm) and embedded signing are Enterprise only. Each key may make 60 requests per minute.

See plans and pricing

Questions

Is there a sandbox or a test key?

Not yet: every key is live. send_emails: false creates the document and the links without emailing anyone; validate_only: true checks an instantiate without creating anything; review: true stages a document for a person to confirm or discard.

Which signature level does the API produce?

A simple electronic signature (SES) by email link, or an advanced electronic signature (AES) when the signer verifies a one-time SMS code. No qualified signature (QES).

How do I know a webhook came from you?

Every delivery carries X-WeSign-Signature: t=<time>,v1=<hmac> — HMAC-SHA256 over the timestamp and the raw body with the hook's secret. Verify it before trusting the body; the docs have verifiers in Node and PHP.

What happens when my endpoint is down?

We retry with exponential backoff and keep a delivery log per hook; one delivery can be sent again from the log. You can also poll GET /v1/signing-requests/{id} at any time.

Can I retry a send without sending twice?

Yes. Send an Idempotency-Key with POST /v1/signing-requests or instantiate: the same key and body within 24 hours returns the first answer; the same key with a different body is refused.

Where are the documents stored?

In the region the workspace pins: EU (default), Switzerland or US. Encrypted in transit and at rest. A signed PDF can be deleted after a retention period you set, so store your copy on document.completed.

Signatures from your own software.

Tell us what you are connecting. The docs are public — read them first if you like.