Errors & limits
Status codes, rate limits, and the monthly signature-request allowance per plan.
Error responses
Errors use conventional HTTP status codes with a JSON body describing the
problem. Alongside the human message, most carry a stable code — branch
on code, not on the message text:
| Status | code | When |
|---|---|---|
400 | invalid_values | A submitted value is missing or malformed. details names each offending values key. |
400 | — | The request body failed validation — a missing role, a malformed email. The message lists what to fix. |
401 | — | No API key, or a key that is unknown, revoked, or expired. |
403 | plan_missing_feature | The workspace's plan no longer includes e-signatures. |
403 | key_creator_left_organization | The person who created this key has left the workspace. Create a replacement — see Authentication. |
403 | limit_reached | The monthly signature-request allowance is used up. Carries resource, limit and used. |
404 | — | Unknown id, or a template that exists but hasn't been published. |
429 | — | Rate limited. |
A 400 from a bad values map tells you exactly which key to fix — the
message quotes the human label the template shows, and details gives the key
your payload uses:
{
"statusCode": 400,
"error": "Bad Request",
"message": "\"Client Name\" is required",
"code": "invalid_values",
"details": [{ "key": "client_name", "label": "Client Name", "reason": "is required" }]
}Rate limit
Two limits apply, and you hit whichever is tighter:
- 120 requests per minute per IP address — shared by everything calling from that address, including other traffic from your network.
- 600 requests per minute per API key — your integration's own budget.
Both report through x-ratelimit-limit, x-ratelimit-remaining and
x-ratelimit-reset (seconds until the window resets); a 429 also carries
retry-after. If you're polling many signature requests, spread the polls out
rather than bursting — or list them in one call with
GET /esign/submissions.
Monthly signature-request allowance
Sending a signature request — from the app or through the API — counts against your workspace's monthly allowance, which resets at the start of each calendar month (UTC):
| Plan | Signature requests / month |
|---|---|
| Starter | 1 |
| Professional | 10 |
| Max | 25 |
| Team Standard | 50 (whole workspace) |
| Team Premium | 100 (whole workspace) |
| Enterprise | Unlimited |
When the allowance is exhausted, POST /esign/submissions returns 403 with
code: limit_reached (and the message limit_reached:signatureRequests),
carrying the limit and how much was used. Listing templates, polling
status, reading usage, and downloading signed documents are never metered, and
a retried request with an already-used idempotencyKey is not charged again.
Rather than discovering the ceiling as a failed send, read
GET /esign/usage
before a batch.
Generating a filled document without sending it for signature (available in the app) doesn't count against the allowance either — only signature requests do.

