Send your first envelope
Four requests in the sandbox: upload, create, send, check. The same steps are shown with curl, the Node SDK and the Python SDK.
Status. The SignWren API is opening in stages and may not be on your account yet. If Settings shows an API keys section, you can make sandbox keys now; live keys come with the Pro and Business plans. SignWren is an electronic signature app for small businesses; it is not a law firm and does not give legal advice.
What do I need before I start?
You need a sandbox key, which starts with sw_test_, made by an owner or admin in Settings under API keys. It is shown once, so copy it somewhere safe. Your business details must also be filled in under Settings, because SignWren shows them to every signer. In the sandbox, emails are only sent to members of your SignWren account with a verified address; mail for anyone else is kept in the sandbox outbox in the app, where owners and admins can read it and open the signing link. Using your own address as the signer is the simplest way to test.
Every example below talks to https://app.signwren.com/api/v1. A separate public host, api.signwren.com, is proposed and not live.
How do I upload the document?
Send the file as multipart form data in a field called file to POST /documents. PDF, Word (.docx), JPEG and PNG are accepted, up to 25 MB and 100 pages, and the type is read from the file's bytes rather than its name.
export SIGNWREN_API_KEY=sw_test_... # a sandbox key from Settings
export SIGNWREN_API=https://app.signwren.com/api/v1
curl "$SIGNWREN_API/documents" \
-H "Authorization: Bearer $SIGNWREN_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-F "file=@lease.pdf"The answer is the stored document. Keep its id; the document waits 24 hours to be put in an envelope.
{
"id": "doc_3f1c2a9e8b7d4c6fa1e2d3c4b5a69788",
"object": "document",
"filename": "lease.pdf",
"kind": "pdf",
"status": "ready",
"page_count": 2,
...
}How do I add the signer and the signature field?
Create the envelope with the document, the recipients and the fields in one call to POST /envelopes. Fields point at their recipient by position in the recipients list (recipient_index), and their position is in PDF points from the top-left corner of the page, with pages counted from 1.
curl "$SIGNWREN_API/envelopes" \
-H "Authorization: Bearer $SIGNWREN_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"title": "Lease, 14 Alder Court",
"document_ids": ["doc_3f1c2a9e8b7d4c6fa1e2d3c4b5a69788"],
"recipients": [{ "name": "Priya Raman", "email": "you@yourcompany.example", "role": "signer" }],
"fields": [{
"document_id": "doc_3f1c2a9e8b7d4c6fa1e2d3c4b5a69788",
"recipient_index": 0, "type": "signature",
"page": 2, "x": 72, "y": 600, "width": 180, "height": 40
}],
"metadata": { "crm_deal": "D-1042" }
}'The answer is the draft envelope, with ids for its documents, recipients and fields. metadata takes up to 50 string pairs of your own, such as the id of the deal or record the envelope belongs to, and comes back on every read and webhook.
How do I send it?
Call POST /envelopes/{envelope_id}/send, and SignWren emails each signer a private signing link, exactly as when you send from the app.
curl -X POST "$SIGNWREN_API/envelopes/env_7d1e0c2b9a8f4e3d8c7b6a5f4e3d2c1b/send" \
-H "Authorization: Bearer $SIGNWREN_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"If the document looks like a kind that e-signature laws exclude, such as a will, the answer is 422 WARNING_UNACKNOWLEDGED with the categories it found. Read them, and if you still want to send, repeat the call with acknowledge_warnings listing those categories; the acknowledgement goes into the audit trail. Sending twice is refused by the envelope's state (409 INVALID_STATE), so a retry can't email people twice.
How do I know when it's signed?
Ask for the envelope, or better, subscribe a webhook endpoint and SignWren will tell you as each person views, signs or declines. When status is completed, the sealed PDF and the certificate of completion can be downloaded.
curl "$SIGNWREN_API/envelopes/env_7d1e0c2b9a8f4e3d8c7b6a5f4e3d2c1b" \
-H "Authorization: Bearer $SIGNWREN_API_KEY"
# once "status" is "completed":
curl "$SIGNWREN_API/envelopes/env_7d1e0c2b9a8f4e3d8c7b6a5f4e3d2c1b/documents/combined" \
-H "Authorization: Bearer $SIGNWREN_API_KEY" -o lease-signed.pdfThe download carries an ETag with the file's SHA-256, so you can check you got every byte. The webhooks page shows how to subscribe and how to check each message is from SignWren.
What does the same thing look like with the Node SDK?
The Node SDK does the same four steps and adds the idempotency keys, retries and checksum check for you.
import { readFile, writeFile } from 'node:fs/promises';
import { SignWren } from '@signwren/sdk';
const sw = new SignWren({ apiKey: process.env.SIGNWREN_API_KEY ?? '' });
const doc = await sw.documents.upload({ file: await readFile('lease.pdf'), filename: 'lease.pdf' });
const envelope = await sw.envelopes.create({
title: 'Lease, 14 Alder Court',
document_ids: [doc.id],
recipients: [{ name: 'Priya Raman', email: 'you@yourcompany.example', role: 'signer' }],
fields: [
{ document_id: doc.id, recipient_index: 0, type: 'signature', page: 2, x: 72, y: 600, width: 180, height: 40 },
],
metadata: { crm_deal: 'D-1042' },
});
await sw.envelopes.send(envelope.id);
// Later, or from a webhook:
const latest = await sw.envelopes.get(envelope.id);
if (latest.status === 'completed') {
const pdf = await sw.envelopes.downloadSigned(envelope.id); // checked against its SHA-256
await writeFile('lease-signed.pdf', pdf.data);
}See the Node SDK page for how to install it. This flow, from upload to the sealed PDF, is also the SDK's end-to-end test against the sandbox.
What does it look like with the Python SDK?
The Python SDK takes the same four steps, with the same idempotency keys, retries and checksum check.
import os
from signwren import SignWren
sw = SignWren(os.environ["SIGNWREN_API_KEY"])
doc = sw.documents.upload("lease.pdf")
envelope = sw.envelopes.create({
"title": "Lease, 14 Alder Court",
"document_ids": [doc["id"]],
"recipients": [{"name": "Priya Raman", "email": "you@yourcompany.example", "role": "signer"}],
"fields": [{"document_id": doc["id"], "recipient_index": 0, "type": "signature",
"page": 2, "x": 72, "y": 600, "width": 180, "height": 40}],
"metadata": {"crm_deal": "D-1042"},
})
sw.envelopes.send(envelope["id"])
latest = sw.envelopes.get(envelope["id"])
if latest["status"] == "completed":
with open("lease-signed.pdf", "wb") as f:
f.write(sw.envelopes.download_signed(envelope["id"]).data) # checked against its SHA-256See the Python SDK page for how to install it. This flow is the Python SDK's end-to-end test against the sandbox too.
Why does the signed sandbox PDF say it isn't valid?
Every page of a sandbox document carries the watermark "SANDBOX: not valid for signature", the certificate is titled "Sandbox test", and the PDF is sealed with a test certificate rather than SignWren's production seal. That is on purpose: a sandbox envelope can never be mistaken for a signed agreement. The sandbox page covers the other differences.
Last checked against the API spec on .