Quickstart
From zero to a signed PDF in under five minutes — terminal-only, no SDK.
This guide goes deeper than the home page summary. By the end you'll have downloaded a real PAdES-sealed PDF, seen a webhook fire against your endpoint, and you'll know which knobs to turn for production.
Every URL below uses the canonical host https://api.wesign.now/v1.
https://api.letssign.now/v1 is a permanent alias of the same API —
see Base URL for what is and isn't the
contract.
Prerequisites
- A workspace on Enterprise. API keys and the template endpoints both ship with it; Free, Pro and Branded can't mint keys. Only a workspace owner or admin can.
- Legacy Teams workspaces can still mint keys and use everything on
this page. What they can't do is send from templates:
instantiate,generateandconfirmanswer402 enterprise-requiredthere (and so does minting an embedded signing session). Listing and reading templates (GET /v1/templates,GET /v1/templates/{id}) works on Teams too. - A test PDF on disk. Any PDF works; if it doesn't have an anchor marker we just append a signature page.
- An email address you can check (or two — sender + signer can be the same address while you smoke-test).
Sending from a template instead of a PDF? The Template quickstart walks through that flow.
1 · Mint an API key
In your workspace, open
Developers → API keys and hit Create API key.
Copy the wsk_live_… plaintext to a terminal env var:
export WSK_KEY="wsk_live_…" # paste the whole key hereThe plaintext shows once. The dashboard keeps a wsk_live_a1b… prefix
so you can identify the key later. A key minted before the September
2026 rename starts with lsk_live_ and works exactly the same — no
need to re-mint.
2 · Send a real request
curl -X POST https://api.wesign.now/v1/signing-requests \
-H "Authorization: Bearer $WSK_KEY" \
-H "Idempotency-Key: smoke-$(date +%s)" \
-F "file=@/path/to/contract.pdf" \
-F 'signers=[{"email":"you@example.com","role":"signer"}]' \
-F 'placement=auto_append' | jq .Successful response (HTTP 201):
{
"documentId": "8a1e4f9a-b3c1-4d22-9e0a-3a92ee7c1f88",
"metadata": null,
"status": "pending",
"placement": "auto_append",
"presentedSha256": "4f9a…d21c",
"anchors": { "found": 0, "fields": 2 },
"signers": [
{
"role": "signer",
"email": "you@example.com",
"status": "pending",
"signingUrl": "https://yourco.letssign.now/en/sign/abc…",
"signingRequestId": "11111111-…",
"emailed": true,
"require_sms_verification": false,
"phone_masked": null,
"sms_verified_at": null,
"sms_gate": "before_sign",
"signature_level": "SES",
"reference": null,
"company": null,
"job_title": null
}
],
"observers": [],
"warnings": []
}"placement": "auto_append" with anchors.found: 0 means the PDF had no
anchor markers, so a signature page was appended.
emailed: true says we sent the invitation. That email carries the same
signing link on the email host — https://yourco.wesign.now/en/sign/abc…
— while the API hands you the yourco.letssign.now form; both open the
same page, the token decides. Open signingUrl in another browser tab to
play the signer side. To deliver the link yourself instead, send
-F 'send_emails=false': everything else is created as usual and
emailed comes back false.
3 · Watch a webhook fire (optional)
Skip if you'd rather poll. To see the events live, the easiest path is a free Webhook.site URL:
# webhook.site/<your-token> issued at https://webhook.site
curl -X POST https://api.wesign.now/v1/signing-requests \
-H "Authorization: Bearer $WSK_KEY" \
-F "file=@contract.pdf" \
-F 'signers=[{"email":"you@example.com","role":"signer"}]' \
-F 'callback_url=https://webhook.site/YOUR-TOKEN'The response now includes a callback.secret — store it. Each event
we POST to your URL is signed. The same three values arrive under two
header names; the X-LetsSign-* family is the pre-rename spelling and
is kept forever, so read whichever you like:
X-WeSign-Signature: t=1757404800,v1=9c3b…a2f1
X-WeSign-Event-Id: evt_…
X-WeSign-Event: signing_request.signed
X-LetsSign-Signature: t=1757404800,v1=9c3b…a2f1
X-LetsSign-Event-Id: evt_…
X-LetsSign-Event: signing_request.signedVerify the signature before trusting the body.
4 · Sign
Open signingUrl on your phone (real test) or in another browser
tab (lazy test). Sign. Watch the inbox for the completion email and
your webhook receiver for signing_request.signed →
document.completed.
5 · Pull the signed PDF programmatically
DOC_ID=8a1e4f9a-b3c1-4d22-9e0a-3a92ee7c1f88 # the documentId from step 2
curl -LOJ -H "Authorization: Bearer $WSK_KEY" \
https://api.wesign.now/v1/documents/$DOC_ID/signedReturns the fully PAdES-sealed PDF — every signer's signature
appended, RFC 3161 timestamp embedded, ready for your DMS. This is the
same URL document.completed hands you as signed_pdf_url: it needs
your key, so pin that fetch to api.wesign.now and send the bearer —
see signed_pdf_url.
Testing without a sandbox
There are no test keys yet: every key is live, every call creates real documents and sends real email and SMS, and SMS codes count against the monthly allowance. Three switches keep a test contained:
send_emails: falseonPOST /v1/signing-requestsorinstantiate— the document and the signing links are created and returned, no invitation is emailed, not even to the next signer of a sequential send when their turn comes. Open the links yourself. Automatic reminders (7 and 14 days after the send, by default) and the completion emails still go out, so use addresses you own, and withdraw what you leave unsigned.validate_only: trueoninstantiateandgenerate— the full check (oninstantiatethe SMS allowance included) and nothing is created. See Templates → dry run.review: trueoninstantiate(orgenerate) — the document is built and staged, nothing is sent. Look at it at thereview_url, then throw it away withPOST /v1/documents/{id}/discard. See Review before sending.
A sandbox with simulated email and SMS is planned — see Versioning → No sandbox yet.
What's next
- Template quickstart — send the same contract many times from a locked template.
- Placement modes — pick anchors, auto-append, or explicit coordinates.
- Second factor by SMS — require a one-time code on the signer's phone before they can sign.
- Webhooks — production-grade event delivery, retries, signature verification.
- Idempotency — safely retry network blips.
- Errors — full code table.
