# Signature requests API reference

> Send a template to people for signing and track progress.

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

## List signature requests

`GET https://app.signwith.co/api/v1/signature_requests`

Read-only keys can call this.

Lists signature requests, newest first. Use it to build a dashboard of outstanding documents
or to reconcile state if you missed webhooks. List items include signers but not their field
values or the signed documents; fetch a single signature request for those.

### Query parameters

| Name | Type | Description |
| --- | --- | --- |
| `limit` | integer | Number of items per page, 1–100. Values outside that range fall back to 20 (below 1) or 100 (above 100). Default `20`. |
| `cursor` | integer | The `next_cursor` from the previous page. Omit it for the first page. |
| `template_id` | integer | Only signature requests created from this template. |
| `q` | string | Case-insensitive search on signer name, email or phone. |
| `status` | string | Filter by status. `open` includes requests that are `sent` or `in_progress`; `expired` returns unfinished requests past their `expires_at`. Any other value returns `422 invalid_parameter`.  |

### Request sample

cURL:

```bash
curl https://app.signwith.co/api/v1/signature_requests \
  -H "Authorization: Bearer $SIGNWITH_API_KEY"
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/signature_requests', {
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
  },
})

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

Python:

```python
import os

import requests

response = requests.get(
    "https://app.signwith.co/api/v1/signature_requests",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
    },
)

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

### Response 200

A page of signature requests.

```json
{
  "object": "list",
  "data": [
    {
      "object": "signature_request",
      "id": 4812,
      "status": "in_progress",
      "template": {
        "id": 311,
        "name": "Residential lease"
      },
      "signing_order": "sequential",
      "source": "api",
      "created_by": {
        "id": 42,
        "email": "ada@acme.co",
        "name": "Ada Lovelace"
      },
      "signers": [
        {
          "object": "signer",
          "id": 9120,
          "signature_request_id": 4812,
          "role": "Tenant",
          "name": "Grace Hopper",
          "email": "grace@example.com",
          "phone": null,
          "external_id": "cust_8841",
          "metadata": {},
          "status": "signed",
          "signing_url": null,
          "sent_at": "2026-09-27T09:00:02Z",
          "viewed_at": "2026-09-27T09:41:18Z",
          "signed_at": "2026-09-27T09:44:51Z",
          "declined_at": null,
          "created_at": "2026-09-27T09:00:01Z",
          "updated_at": "2026-09-27T09:44:51Z"
        },
        {
          "object": "signer",
          "id": 9121,
          "signature_request_id": 4812,
          "role": "Landlord",
          "name": "Ada Lovelace",
          "email": "ada@acme.co",
          "phone": null,
          "external_id": null,
          "metadata": {},
          "status": "sent",
          "signing_url": "https://app.signwith.co/s/q8LkT2mZpV4r",
          "sent_at": "2026-09-27T09:44:53Z",
          "viewed_at": null,
          "signed_at": null,
          "declined_at": null,
          "created_at": "2026-09-27T09:00:01Z",
          "updated_at": "2026-09-27T09:44:53Z"
        }
      ],
      "expires_at": "2026-10-27T00:00:00Z",
      "completed_at": null,
      "canceled_at": null,
      "created_at": "2026-09-27T09:00:01Z",
      "updated_at": "2026-09-27T09:44:53Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 422 | The request is valid JSON but can't be processed. See `error.code`; the codes each endpoint can return are described in the endpoint's description and in the error table above.  |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Send a signature request

`POST https://app.signwith.co/api/v1/signature_requests`

Needs a full-access key. Accepts `Idempotency-Key`.

Creates a signature request from a template and invites the signers. This is the main call
for getting a document signed from your product.

- Assign each signer to a template role with `role`. Signers without a `role` fill the
  template's roles in order. You can't send more signers than the template has roles, and
  each role can be given to only one signer.
- `signers` is a list of objects. Each signer needs a valid `email` or a `phone`
  (`422 invalid_signer`); `prefill` and `metadata` must be objects (`422 invalid_parameter`).
- `expires_at` must be an ISO 8601 date-time in the future (`422 invalid_parameter`).
- Use `prefill` to fill fields for a signer ahead of time, keyed by field name (see
  [`GET /templates/{id}`](#operation/getTemplate) for field names).
- Set `send_email: false` to create the request without emailing anyone — for example to
  embed or deliver the signers' `signing_url` yourself. Those signers have status `ready`
  when it's their turn.
- Set `require_email_otp: true` to require each signer to enter a one-time code sent to
  their email before they can view and sign.

The template must be active (`422 template_archived`) and have at least one field
(`422 template_has_no_fields` — add fields with [`PATCH /templates/{id}`](#operation/updateTemplate)
or in the editor). The request keeps a snapshot of the template's fields and documents, so later
template edits don't change what these signers see.

The first signature request from a template uses one credit when it's signed; if you have no
credits left the request is rejected with `402 insufficient_credits` — see
[Buying credits](#section/Buying-credits) for how to top up and retry. Send an
`Idempotency-Key` so retries don't send the document twice. Triggers the
`signature_request.created` webhook.

### Headers

| Name | Type | Description |
| --- | --- | --- |
| `Idempotency-Key` | string | A unique value (e.g. a UUID) that makes retries of this request safe. A successful response is stored for 24 hours and replayed for retries with the same key.  |

### Request body (`application/json`)

- `template_id` (integer, required). The template to send.
- `signers` (array of objects, required, at least 1 item). The people to invite. At most one per template role.
  - `role` (string). The template role this signer fills. If omitted, signers fill the template's roles in the order given.
  - `name` (string).
  - `email` (string, email address). Required unless `phone` is given.
  - `phone` (string). Phone number in international format.
  - `external_id` (string). Your own ID for this signer, returned in responses and webhooks.
  - `metadata` (object). Arbitrary key/value data stored with the signer.
  - `prefill` (object). Values to fill in for a signer before they sign, keyed by field name (see the template's `fields`). Values must suit the field type: text, dates as `YYYY-MM-DD`, checkboxes as booleans, and for image or signature fields a base64 image or an https URL.
  - `redirect_url` (string, URL). Where to send this signer after they sign. Overrides the request-level `redirect_url`.
  - `require_email_otp` (boolean). Require each signer to enter a one-time code sent to their email before they can view and sign. Overrides the request-level `require_email_otp` for this signer.
- `signing_order` (string, one of `sequential`, `parallel`, default `"sequential"`). `sequential` invites signers one at a time in role order; `parallel` invites everyone at once.
- `send_email` (boolean, default `true`). Set to `false` to create the request without emailing signers.
- `message` (object). Custom subject and body for the invitation email.
  - `subject` (string).
  - `body` (string).
- `reply_to` (string, email address). Reply-to address for emails sent to signers.
- `redirect_url` (string, URL). Where to send signers after they sign.
- `expires_at` (string (date-time)). ISO 8601 date-time in the future (e.g. `2026-12-31T17:00:00Z`). After it the request expires and can no longer be signed.
- `require_email_otp` (boolean, default `false`). Require each signer to enter a one-time code sent to their email before they can view and sign.

### Request sample

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())
```

### Response 201

The signature request was created and signers were invited.

```json
{
  "object": "signature_request",
  "id": 4812,
  "status": "sent",
  "template": {
    "id": 311,
    "name": "Residential lease"
  },
  "signing_order": "sequential",
  "source": "api",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "signers": [
    {
      "object": "signer",
      "id": 9120,
      "signature_request_id": 4812,
      "role": "Tenant",
      "name": "Grace Hopper",
      "email": "grace@example.com",
      "phone": null,
      "external_id": "cust_8841",
      "metadata": {
        "crm_deal_id": "D-2291"
      },
      "status": "sent",
      "signing_url": "https://app.signwith.co/s/Hn3cW8yRk2Qe",
      "sent_at": "2026-09-27T09:00:02Z",
      "viewed_at": null,
      "signed_at": null,
      "declined_at": null,
      "created_at": "2026-09-27T09:00:01Z",
      "updated_at": "2026-09-27T09:00:02Z",
      "values": [
        {
          "field": "Tenant name",
          "value": "Grace Hopper"
        },
        {
          "field": "Monthly rent",
          "value": "2150"
        },
        {
          "field": "Start date",
          "value": "2026-11-01"
        }
      ]
    },
    {
      "object": "signer",
      "id": 9121,
      "signature_request_id": 4812,
      "role": "Landlord",
      "name": "Ada Lovelace",
      "email": "ada@acme.co",
      "phone": null,
      "external_id": null,
      "metadata": {},
      "status": "waiting",
      "signing_url": "https://app.signwith.co/s/q8LkT2mZpV4r",
      "sent_at": null,
      "viewed_at": null,
      "signed_at": null,
      "declined_at": null,
      "created_at": "2026-09-27T09:00:01Z",
      "updated_at": "2026-09-27T09:00:01Z",
      "values": []
    }
  ],
  "expires_at": "2026-10-27T00:00:00Z",
  "completed_at": null,
  "canceled_at": null,
  "created_at": "2026-09-27T09:00:01Z",
  "updated_at": "2026-09-27T09:00:01Z"
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 400 | The request body is not valid JSON. |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 402 | Not enough credits to send this document. Buy credits with `GET /credit_packs` and `POST /checkouts`, then retry. See [Buying credits](#section/Buying-credits).  |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 409 | A request with the same `Idempotency-Key` is still being processed. Retry shortly. |
| 422 | The request is valid JSON but can't be processed. See `error.code`; the codes each endpoint can return are described in the endpoint's description and in the error table above.  |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Get a signature request

`GET https://app.signwith.co/api/v1/signature_requests/{id}`

Read-only keys can call this.

Returns a signature request with every signer's progress and field values. Once everyone has
signed (`status: completed`) it also includes download links for the signed `documents`, the
`audit_trail_url` and, when available, a `combined_document_url`. Use it after a
`signature_request.completed` webhook to download the final files.

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `id` (required) | integer | Signature request ID. |

### Request sample

cURL:

```bash
curl https://app.signwith.co/api/v1/signature_requests/4812 \
  -H "Authorization: Bearer $SIGNWITH_API_KEY"
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/signature_requests/4812', {
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
  },
})

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

Python:

```python
import os

import requests

response = requests.get(
    "https://app.signwith.co/api/v1/signature_requests/4812",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
    },
)

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

### Response 200

The signature request.

```json
{
  "object": "signature_request",
  "id": 4812,
  "status": "completed",
  "template": {
    "id": 311,
    "name": "Residential lease"
  },
  "signing_order": "sequential",
  "source": "api",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "signers": [
    {
      "object": "signer",
      "id": 9120,
      "signature_request_id": 4812,
      "role": "Tenant",
      "name": "Grace Hopper",
      "email": "grace@example.com",
      "phone": null,
      "external_id": "cust_8841",
      "metadata": {
        "crm_deal_id": "D-2291"
      },
      "status": "signed",
      "signing_url": null,
      "sent_at": "2026-09-27T09:00:02Z",
      "viewed_at": "2026-09-27T09:41:18Z",
      "signed_at": "2026-09-27T09:44:51Z",
      "declined_at": null,
      "created_at": "2026-09-27T09:00:01Z",
      "updated_at": "2026-09-27T09:44:51Z",
      "values": [
        {
          "field": "Tenant name",
          "value": "Grace Hopper"
        },
        {
          "field": "Monthly rent",
          "value": "2150"
        },
        {
          "field": "Start date",
          "value": "2026-11-01"
        },
        {
          "field": "Pets",
          "value": "Cat"
        },
        {
          "field": "Tenant signature",
          "value": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6NTUxfX0/signature.png"
        }
      ],
      "documents": [
        {
          "name": "Lease agreement",
          "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6NTUyfX0/lease-agreement.pdf"
        }
      ]
    },
    {
      "object": "signer",
      "id": 9121,
      "signature_request_id": 4812,
      "role": "Landlord",
      "name": "Ada Lovelace",
      "email": "ada@acme.co",
      "phone": null,
      "external_id": null,
      "metadata": {},
      "status": "signed",
      "signing_url": null,
      "sent_at": "2026-09-27T09:44:53Z",
      "viewed_at": "2026-09-27T10:12:30Z",
      "signed_at": "2026-09-27T10:14:58Z",
      "declined_at": null,
      "created_at": "2026-09-27T09:00:01Z",
      "updated_at": "2026-09-27T10:14:58Z",
      "values": [
        {
          "field": "Landlord signature",
          "value": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6NTYwfX0/signature.png"
        }
      ],
      "documents": [
        {
          "name": "Lease agreement",
          "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6NTYxfX0/lease-agreement.pdf"
        }
      ]
    }
  ],
  "expires_at": "2026-10-27T00:00:00Z",
  "completed_at": "2026-09-27T10:14:58Z",
  "canceled_at": null,
  "created_at": "2026-09-27T09:00:01Z",
  "updated_at": "2026-09-27T10:14:58Z",
  "documents": [
    {
      "name": "Lease agreement",
      "url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6NTYxfX0/lease-agreement.pdf"
    }
  ],
  "audit_trail_url": "https://app.signwith.co/file/eyJfcmFpbHMiOnsiZGF0YSI6NTYyfX0/audit-trail.pdf",
  "combined_document_url": null
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Cancel a signature request

`POST https://app.signwith.co/api/v1/signature_requests/{id}/cancel`

Needs a full-access key. Accepts `Idempotency-Key`.

Cancels a signature request so its signing links stop working — for example when a deal falls
through or the document was sent with a mistake. Fully signed requests can't be canceled
(`422 already_completed`). Canceling an already canceled request succeeds and returns it
unchanged. Triggers the `signature_request.canceled` webhook.

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `id` (required) | integer | Signature request ID. |

### Headers

| Name | Type | Description |
| --- | --- | --- |
| `Idempotency-Key` | string | A unique value (e.g. a UUID) that makes retries of this request safe. A successful response is stored for 24 hours and replayed for retries with the same key.  |

### Request sample

cURL:

```bash
curl -X POST https://app.signwith.co/api/v1/signature_requests/4812/cancel \
  -H "Authorization: Bearer $SIGNWITH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/signature_requests/4812/cancel', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(),
  },
})

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/4812/cancel",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
)

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

### Response 200

The canceled signature request.

```json
{
  "object": "signature_request",
  "id": 4812,
  "status": "canceled",
  "template": {
    "id": 311,
    "name": "Residential lease"
  },
  "signing_order": "sequential",
  "source": "api",
  "created_by": {
    "id": 42,
    "email": "ada@acme.co",
    "name": "Ada Lovelace"
  },
  "signers": [
    {
      "object": "signer",
      "id": 9120,
      "signature_request_id": 4812,
      "role": "Tenant",
      "name": "Grace Hopper",
      "email": "grace@example.com",
      "phone": null,
      "external_id": "cust_8841",
      "metadata": {},
      "status": "viewed",
      "signing_url": "https://app.signwith.co/s/Hn3cW8yRk2Qe",
      "sent_at": "2026-09-27T09:00:02Z",
      "viewed_at": "2026-09-27T09:41:18Z",
      "signed_at": null,
      "declined_at": null,
      "created_at": "2026-09-27T09:00:01Z",
      "updated_at": "2026-09-27T09:41:18Z",
      "values": []
    }
  ],
  "expires_at": null,
  "completed_at": null,
  "canceled_at": "2026-09-28T08:30:12Z",
  "created_at": "2026-09-27T09:00:01Z",
  "updated_at": "2026-09-28T08:30:12Z"
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 409 | A request with the same `Idempotency-Key` is still being processed. Retry shortly. |
| 422 | The request is valid JSON but can't be processed. See `error.code`; the codes each endpoint can return are described in the endpoint's description and in the error table above.  |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## Remind waiting signers

`POST https://app.signwith.co/api/v1/signature_requests/{id}/remind`

Needs a full-access key. Accepts `Idempotency-Key`.

Emails the signing link again to every signer who has been invited, hasn't signed or declined
yet, and has an email address. Use it to nudge people who haven't acted. Signers still
waiting for their turn in a sequential request are not reminded.

A request can be reminded at most once per hour (`429 remind_too_soon`, with `Retry-After`
set to the seconds left until it can be reminded again). Returns
`422 not_open` for canceled, declined or expired requests and `422 nothing_to_remind` when nobody is
waiting.

### Path parameters

| Name | Type | Description |
| --- | --- | --- |
| `id` (required) | integer | Signature request ID. |

### Headers

| Name | Type | Description |
| --- | --- | --- |
| `Idempotency-Key` | string | A unique value (e.g. a UUID) that makes retries of this request safe. A successful response is stored for 24 hours and replayed for retries with the same key.  |

### Request sample

cURL:

```bash
curl -X POST https://app.signwith.co/api/v1/signature_requests/4812/remind \
  -H "Authorization: Bearer $SIGNWITH_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

Node:

```javascript
const response = await fetch('https://app.signwith.co/api/v1/signature_requests/4812/remind', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}`,
    'Idempotency-Key': crypto.randomUUID(),
  },
})

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/4812/remind",
    headers={
        "Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
)

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

### Response 200

Which signers were reminded.

```json
{
  "object": "reminder",
  "signature_request_id": 4812,
  "reminded_signer_ids": [
    9121
  ]
}
```

### Errors

| Status | Meaning |
| --- | --- |
| 401 | The API key is missing, invalid or expired, or its account has been archived. |
| 403 | The key is read-only, or its user can't access this resource. |
| 404 | The resource doesn't exist or belongs to another account. |
| 409 | A request with the same `Idempotency-Key` is still being processed. Retry shortly. |
| 422 | The request is valid JSON but can't be processed. See `error.code`; the codes each endpoint can return are described in the endpoint's description and in the error table above.  |
| 429 | Rate limit exceeded (`rate_limited`, with `Retry-After`); more than 20 `POST /feedback` messages in an hour (`rate_limited`, with `Retry-After`: seconds until the next clock hour); or — for `POST /signature_requests/{id}/remind` — signers were reminded less than an hour ago (`remind_too_soon`, with `Retry-After`).  |
| 500 | Something went wrong on SignWith's side. It's safe to retry with the same `Idempotency-Key`. |

## The signature request object

Anchor: https://signwith.co/docs/api/signature-requests#the-signature-request-object

- `object` (string, required, always `signature_request`).
- `id` (integer, required).
- `status` (string, required, one of `sent`, `in_progress`, `completed`, `declined`, `expired`, `canceled`). `sent` — nobody has signed yet; `in_progress` — some signers have signed; `completed` — everyone signed; `declined` — a signer declined; `expired` — passed `expires_at` before completion; `canceled` — canceled. A fully signed request is always `completed`, even if it was later archived.
- `template` (object or null, required). The template this request was created from.
  - `id` (integer, required).
  - `name` (string, required).
- `signing_order` (string, required, one of `sequential`, `parallel`).
- `source` (string, required). Where the request was created: `api` (this API), `mcp` (an AI assistant through the SignWith MCP server), `invite` (dashboard), `link` (shared link), `bulk` or `embed`.
- `created_by` (object or null, required). A SignWith user (a member of your team).
  - `id` (integer, required).
  - `email` (string, required, email address).
  - `name` (string or null, required). First and last name, or `null` if not set.
- `signers` (array of objects, required). Signers in role order, with their field values.
  - `object` (string, required, always `signer`).
  - `id` (integer, required).
  - `signature_request_id` (integer, required).
  - `role` (string or null, required). The template role this signer fills.
  - `name` (string or null, required).
  - `email` (string or null, required, email address).
  - `phone` (string or null, required).
  - `external_id` (string or null, required). Your own ID for this signer.
  - `metadata` (object, required). Arbitrary key/value data you attached to the signer.
  - `status` (string, required, one of `waiting`, `ready`, `sent`, `viewed`, `signed`, `declined`). `waiting` — an earlier signer in a sequential request has to sign first; `ready` — it's their turn but they weren't emailed (e.g. `send_email: false`, or the email is still queued), so share `signing_url` yourself; `sent` — invited; `viewed` — opened the document; `signed` — finished signing; `declined` — declined to sign.
  - `signing_url` (string or null, required, URL). The signer's private signing link. Anyone with it can sign as this signer, so only share it with them. `null` once they've signed, or when the request is canceled, declined or expired, or its template is archived.
  - `sent_at` (string (date-time) or null, required).
  - `viewed_at` (string (date-time) or null, required).
  - `signed_at` (string (date-time) or null, required).
  - `declined_at` (string (date-time) or null, required).
  - `created_at` (string (date-time), required).
  - `updated_at` (string (date-time), required).
  - `values` (array of objects, required). Field values filled so far (prefilled or entered by the signer).
    - `field` (string, required). Field name (or a generated name such as `Text Field 2` for unnamed fields).
    - `value` (string or number or boolean or array of anys or null, required). The value entered or prefilled.
  - `documents` (array of objects). The signer's signed documents. Present only once they've signed.
    - `name` (string, required). File name without extension.
    - `url` (string, required, URL). Download link for the signed PDF.
- `expires_at` (string (date-time) or null, required).
- `completed_at` (string (date-time) or null, required). When the last signer signed.
- `canceled_at` (string (date-time) or null, required).
- `created_at` (string (date-time), required).
- `updated_at` (string (date-time), required).
- `documents` (array of objects). The final signed documents.
  - `name` (string, required). File name without extension.
  - `url` (string, required, URL). Download link for the signed PDF.
- `audit_trail_url` (string or null, URL). Download link for the audit trail PDF.
- `combined_document_url` (string or null, URL). Download link for all documents and the audit trail merged into one PDF, if generated.
