Skip to content
SignWithDocs
Esc
  • Developer docs homeDocs
  • ChangelogDocs
  • OverviewREST API · Get started
  • Quick startREST API · Get started
  • Text tagsREST API · Get started
  • AuthenticationREST API · Get started
  • Making requestsREST API · Get started
  • ErrorsREST API · Get started

API requests: pagination and idempotency

The rules every SignWith API endpoint shares: where requests go, what they look like, how to page through lists, and how to retry without doing anything twice.

Updated

Base URL and format

All requests go to https://app.signwith.co/api/v1. They accept and return JSON (Content-Type: application/json) in UTF-8, except two uploads that also accept multipart/form-data: creating a template and verifying a document.

  • Timestamps are ISO 8601 strings, such as 2026-09-27T09:00:01Z.
  • IDs are integers, except template field IDs, which are UUID strings, and checkout IDs, which are UUIDs.
  • Where an endpoint takes PATCH, PUT is accepted as an alias.
  • A path that doesn't exist returns 404 not_found with the method and path in the message.

Every request needs an API key.

Pagination

List endpoints return the newest items first, a page at a time, in this envelope:

JSON
{ "object": "list", "data": [ ... ], "has_more": true, "next_cursor": 4812 }
  • limit sets the page size, from 1 to 100 (default 20). Values below 1 fall back to 20, and values above 100 to 100.
  • cursor gets the next page: pass the next_cursor from the page before.
  • Keep going while has_more is true. On the last page next_cursor is null.

This fetches every signature request, 100 at a time:

JavaScript
const items = []
let cursor = null
do {
  const url = new URL('https://app.signwith.co/api/v1/signature_requests')
  url.searchParams.set('limit', '100')
  if (cursor) url.searchParams.set('cursor', String(cursor))
  const response = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.SIGNWITH_API_KEY}` },
  })
  const page = await response.json()
  items.push(...page.data)
  cursor = page.has_more ? page.next_cursor : null
} while (cursor)
Python
import os

import requests

items, cursor = [], None
while True:
    params = {"limit": 100}
    if cursor:
        params["cursor"] = cursor
    page = requests.get(
        "https://app.signwith.co/api/v1/signature_requests",
        headers={"Authorization": f"Bearer {os.environ['SIGNWITH_API_KEY']}"},
        params=params,
    ).json()
    items.extend(page["data"])
    if not page["has_more"]:
        break
    cursor = page["next_cursor"]

The list endpoints are GET /templates, GET /signature_requests and GET /credit_packs, which always returns every pack on one page.

Idempotency

Networks fail. To retry a POST without doing it twice, for example sending the same document to the same people again, send a unique Idempotency-Key header. A UUID v4 works well:

HTTP
Idempotency-Key: 5f1c6c1e-0b1a-4d38-9d0e-8a7a1f2f8d11
  • The first successful (2xx) response is stored for 24 hours per API key and path. A retry with the same key gets that stored response back, with the header Idempotent-Replayed: true.
  • Failed responses aren't stored, so you can retry a failed request with the same key.
  • If the first request is still running, a retry returns 409 idempotency_key_in_use. Wait a moment and try again.
  • Reusing a key with a different request body returns 422 idempotency_key_reused. Use a new key for each different request.

Every POST endpoint accepts the header; the API reference marks them. The code samples in these docs generate a new key for each run.

Retrying safely

ResponseRetry?
429 rate_limitedYes, after the Retry-After seconds when the header is present. See rate limits.
409 idempotency_key_in_useYes, with the same key, after a short wait.
500 internal_errorYes, with the same Idempotency-Key for a POST. Contact support if it keeps happening.
502 payment_provider_errorLater. Nothing was charged.
Other 4xxNo. Fix the request first; the error.code says what's wrong.

Start building

The API and MCP server come with every account. 3 free documents a month, then pay per document.