sign.ytDocs

Core concepts

Rate limits

Each API key may make 100 requests per second, counted in fixed one-second windows.

Headers#

Every metered API-key response carries:

HeaderMeaning
X-RateLimit-LimitRequests allowed per window (100).
X-RateLimit-RemainingRequests left in the current window.
X-RateLimit-ResetUnix time (seconds) when the current window ends and the counter resets.

Over the limit the API answers 429 with code rate_limited and a Retry-After header in seconds:

HTTP/1.1 429 Too Many Requests
Retry-After: 1
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1792400401
Content-Type: application/json

{"code":"rate_limited","message":"API key rate limit exceeded","detail":"API key rate limit exceeded","request_id":"5c1d9e0a7b3f4e21"}

The limit is per key, not per organization: separate keys for separate integrations do not share a budget. Authentication and scope failures are rejected before metering.

Other limits#

WhatLimit
Request body30 MB (413 payload_too_large)
POST /documents payload JSON64 KB; up to 50 recipients and 200 fields per document
POST /documents/bulk500 CSV rows per call
Company lookup (GET /lookup/company)30 lookups per minute per organization (429, Retry-After: 60)
Public verification (POST /verify, GET /verify/code/{code})10 requests per 10 minutes per IP
Monthly documents, SMS, storagePlan quotas (402 with codes such as documents_per_month, sms_quota_exceeded)

Handling 429#

  • Wait at least Retry-After seconds, then retry with exponential backoff and jitter (for example 0.5 s, 1 s, 2 s, 4 s, each multiplied by a random factor between 0.5 and 1).
  • Spread batch jobs out instead of firing them in parallel; watch X-RateLimit-Remaining and pause when it reaches 0.
  • For many documents prefer bulk sending (one request for up to 500 drafts) or templates over hundreds of individual uploads.
  • Use webhooks instead of polling for status changes.
import os
import random
import time
import httpx

def get_with_backoff(http: httpx.Client, path: str, attempts: int = 5) -> httpx.Response:
    for attempt in range(attempts):
        resp = http.get(path)
        if resp.status_code not in (429, 500, 502, 503):
            return resp
        retry_after = float(resp.headers.get("Retry-After", 0))
        backoff = 0.5 * 2**attempt * (0.5 + random.random() / 2)
        time.sleep(max(retry_after, backoff))
    return resp

http = httpx.Client(
    base_url="https://api.sign.yt/v1",
    headers={"Authorization": f"Bearer {os.environ['SIGNYT_API_KEY']}"},
)
print(get_with_backoff(http, "/documents?limit=10").json())

The official SDKs already retry GET, PUT and DELETE on 429 and 5xx, honoring Retry-After (capped at 60 seconds).