E-signature API
Send documents for signature from your own product, follow every signer with webhooks, and pay per document. A REST API with JSON requests and responses, on every SignWith account.
- Base URL
- app.signwith.co/api/v1
- Auth
- Bearer API key
- Endpoints
- 20
- Webhook events
- 11
Send a document in one request
Once you have a template, one call to POST /signature_requests emails each signer their own signing link. This example sends a lease to a tenant first and the landlord second, with some fields already filled in.
curl -X POST https://app.signwith.co/api/v1/signature_requests \
-H "Authorization: Bearer $SIGNWITH_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"template_id": 311,
"signing_order": "sequential",
"expires_at": "2026-10-27T00:00:00Z",
"reply_to": "[email protected]",
"redirect_url": "https://acme.co/lease/signed",
"message": {
"subject": "Your lease for 14 Riverside Ave is ready to sign",
"body": "Hi Grace, please review and sign your lease."
},
"signers": [
{
"role": "Tenant",
"name": "Grace Hopper",
"email": "[email protected]",
"external_id": "cust_8841",
"metadata": {
"crm_deal_id": "D-2291"
},
"prefill": {
"Tenant name": "Grace Hopper",
"Monthly rent": "2150",
"Start date": "2026-11-01"
},
"require_email_otp": true
},
{
"role": "Landlord",
"name": "Ada Lovelace",
"email": "[email protected]"
}
]
}'const response = await fetch('https://app.signwith.co/api/v1/signature_requests', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
template_id: 311,
signing_order: 'sequential',
expires_at: '2026-10-27T00:00:00Z',
reply_to: '[email protected]',
redirect_url: 'https://acme.co/lease/signed',
message: {
subject: 'Your lease for 14 Riverside Ave is ready to sign',
body: 'Hi Grace, please review and sign your lease.',
},
signers: [
{
role: 'Tenant',
name: 'Grace Hopper',
email: '[email protected]',
external_id: 'cust_8841',
metadata: {
crm_deal_id: 'D-2291',
},
prefill: {
'Tenant name': 'Grace Hopper',
'Monthly rent': '2150',
'Start date': '2026-11-01',
},
require_email_otp: true,
},
{
role: 'Landlord',
name: 'Ada Lovelace',
email: '[email protected]',
},
],
}),
})
console.log(response.status, await response.json())import os
import uuid
import requests
response = requests.post(
"https://app.signwith.co/api/v1/signature_requests",
headers={
"Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"template_id": 311,
"signing_order": "sequential",
"expires_at": "2026-10-27T00:00:00Z",
"reply_to": "[email protected]",
"redirect_url": "https://acme.co/lease/signed",
"message": {
"subject": "Your lease for 14 Riverside Ave is ready to sign",
"body": "Hi Grace, please review and sign your lease.",
},
"signers": [
{
"role": "Tenant",
"name": "Grace Hopper",
"email": "[email protected]",
"external_id": "cust_8841",
"metadata": {
"crm_deal_id": "D-2291",
},
"prefill": {
"Tenant name": "Grace Hopper",
"Monthly rent": "2150",
"Start date": "2026-11-01",
},
"require_email_otp": True,
},
{
"role": "Landlord",
"name": "Ada Lovelace",
"email": "[email protected]",
},
],
},
)
print(response.status_code, response.json())How it works
- Create a template from a PDF or image, with fields for each role, using
POST /templatesor the SignWith editor. - Send it with
POST /signature_requests, naming a signer for each role. - Follow progress with webhooks such as
signer.signed, or withGET /signature_requests/{id}. - Download the result. When everyone has signed, the request links to the signed documents and the audit trail.
The quick start does all four in a few minutes.
All endpoints
Every endpoint, generated from the OpenAPI spec (also as JSON) that you can import into Postman, Insomnia or a code generator.
Webhooks
SignWith calls your server when signers view, sign or decline and when documents complete, signed with HMAC-SHA256. See webhooks, the event reference and how to verify signatures.
Pricing: pay per document
There is no API plan or monthly fee. The API uses the same credits as the SignWith dashboard: 3 free documents every month, then one-time credit packs from $9, down to $0.58 per document on Business. One credit covers one signed document, however many people sign it. See credits and billing and the pricing page.
Frequently asked questions
- Is there a free e-signature API?
- Every SignWith account can create API keys, and the 3 free documents each month work through the API too. After that you buy credits once, from $9, with no subscription or API plan. See credits and billing.
- Can I test the API without sending real emails?
- Keys that start with
sw_test_act on your test account, whose data is kept apart from live data. You can also create a signature request withsend_email: falseand share each signer'ssigning_urlyourself. See authentication. - Can I show the signing page inside my own app?
- Create the signature request with
send_email: false. Signers get no email, and each signer's privatesigning_urlis in the response for you to deliver. Useredirect_urlto send them back to your app after signing. - How do I know when a document is signed?
- Add a webhook endpoint and subscribe to
signature_request.completed, or pollGET /signature_requests/{id}untilstatusiscompleted. The completed request includes download links for the signed documents and the audit trail. - Can Claude or ChatGPT send documents for signature?
- Yes. SignWith runs an MCP server with 18 tools that AI assistants use to list templates, send signature requests and follow signers. See the MCP server docs.
Start building
The API and MCP server come with every account. 3 free documents a month, then pay per document.