# E-signature API: send documents for signature

> Send documents for signature from your own product, follow every signer with webhooks, and pay per document.

Source: https://signwith.co/docs/api · Updated 2026-10-02

Base URL: `https://app.signwith.co/api/v1`. Authenticate with a Bearer [API key](https://signwith.co/docs/api/authentication). JSON in and out. 20 endpoints and 11 webhook events. OpenAPI spec: https://signwith.co/docs/openapi.yaml.

## Send a document in one request

cURL:

```bash
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": "leasing@acme.co",
  "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": "grace@example.com",
      "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": "ada@acme.co"
    }
  ]
}'
```

Node:

```javascript
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: 'leasing@acme.co',
    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: 'grace@example.com',
        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: 'ada@acme.co',
      },
    ],
  }),
})

console.log(response.status, await response.json())
```

Python:

```python
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": "leasing@acme.co",
        "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": "grace@example.com",
                "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": "ada@acme.co",
            },
        ],
    },
)

print(response.status_code, response.json())
```

## All endpoints

### [Account](https://signwith.co/docs/api/account)
- [Get the current API key's user and account](https://signwith.co/docs/api/account#get-the-current-api-keys-user-and-account): `GET /me`
- [Get the credit balance](https://signwith.co/docs/api/account#get-the-credit-balance): `GET /credits`

### [Templates](https://signwith.co/docs/api/templates)
- [List templates](https://signwith.co/docs/api/templates#list-templates): `GET /templates`
- [Create a template from documents](https://signwith.co/docs/api/templates#create-a-template-from-documents): `POST /templates`
- [Get a template](https://signwith.co/docs/api/templates#get-a-template): `GET /templates/{id}`
- [Update a template](https://signwith.co/docs/api/templates#update-a-template): `PATCH /templates/{id}`
- [Duplicate a template](https://signwith.co/docs/api/templates#duplicate-a-template): `POST /templates/{id}/duplicate`
- [Archive a template](https://signwith.co/docs/api/templates#archive-a-template): `POST /templates/{id}/archive`

### [Signature requests](https://signwith.co/docs/api/signature-requests)
- [List signature requests](https://signwith.co/docs/api/signature-requests#list-signature-requests): `GET /signature_requests`
- [Send a signature request](https://signwith.co/docs/api/signature-requests#send-a-signature-request): `POST /signature_requests`
- [Get a signature request](https://signwith.co/docs/api/signature-requests#get-a-signature-request): `GET /signature_requests/{id}`
- [Cancel a signature request](https://signwith.co/docs/api/signature-requests#cancel-a-signature-request): `POST /signature_requests/{id}/cancel`
- [Remind waiting signers](https://signwith.co/docs/api/signature-requests#remind-waiting-signers): `POST /signature_requests/{id}/remind`

### [Signers](https://signwith.co/docs/api/signers)
- [Get a signer](https://signwith.co/docs/api/signers#get-a-signer): `GET /signers/{id}`
- [Update a signer](https://signwith.co/docs/api/signers#update-a-signer): `PATCH /signers/{id}`

### [Documents](https://signwith.co/docs/api/documents)
- [Verify a signed PDF](https://signwith.co/docs/api/documents#verify-a-signed-pdf): `POST /documents/verify`

### [Billing](https://signwith.co/docs/api/billing)
- [List credit packs](https://signwith.co/docs/api/billing#list-credit-packs): `GET /credit_packs`
- [Start a credit purchase](https://signwith.co/docs/api/billing#start-a-credit-purchase): `POST /checkouts`
- [Get a checkout](https://signwith.co/docs/api/billing#get-a-checkout): `GET /checkouts/{id}`

### [Feedback](https://signwith.co/docs/api/feedback)
- [Send feedback to the SignWith team](https://signwith.co/docs/api/feedback#send-feedback-to-the-signwith-team): `POST /feedback`

## Pricing

No API plan or monthly fee: 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. See https://signwith.co/docs/api/credits.

## 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](https://signwith.co/docs/api/credits).

### 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 with `send_email: false` and share each signer's `signing_url` yourself. See [authentication](https://signwith.co/docs/api/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 private `signing_url` is in the response for you to deliver. Use `redirect_url` to 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 poll `GET /signature_requests/{id}` until `status` is `completed`. 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](https://signwith.co/docs/mcp).
