unauthenticated | 401 | no | The credential was absent, unreadable, unknown, wrong or revoked — this answer is deliberately identical for all of them, so it cannot be used to probe which keys exist. Retrying the same request changes nothing. Check the key in Settings or issue a new one. |
forbidden | 403 | no | The key is valid and the organisation’s plan does not grant what this operation does. Nothing about the credential needs to change, and it is deliberately MORE specific than 401 because the caller has already proved they hold the key. TWO SITUATIONS PRODUCE IT. (1) THE PLAN EXCLUDES THE OPERATION: POST /api/v1/templates on the Free plan, which does not include authoring templates. A template that already exists stays readable at GET /api/v1/templates; authoring one needs a plan that includes templates. (2) WE CANNOT ESTABLISH WHAT THE PLAN INCLUDES, on any operation, so nothing is granted. That one is ours rather than yours, an ordinary account does not meet it, and it means ask us. |
insufficient_scope | 403 | no | This key is scoped and does not hold the scope this operation requires — x-required-scope on the operation names it, and the WWW-Authenticate header on the refusal repeats it (RFC 6750 §3.1). ⚠️ Retrying cannot help and neither can editing the key: scopes are fixed when a key is minted and no endpoint or screen can widen them. Issue a new key with the access it needs. A key created before scopes existed carries an empty scope list, which means EVERY capability, so this refusal cannot reach an integration that was already working. |
not_found | 404 | no | No such resource — or none this key’s organisation can see, or one that has been archived, or an id that is not a uuid. Those four are one answer on purpose: “it exists but is not yours” is itself a disclosure. Do not retry; check the id against the list endpoint. |
document_too_complex | 422 | no | The document needs more memory or time to read than one document is allowed, what reading it produced is larger than one document may produce, or it could not be read through at all. Every uploaded PDF is read in an isolated service, one document at a time, under a fixed memory limit and a fixed time limit, and this one went past one of them; the message says which. Because nothing else was running there, the same document fails the same way. On an upload (POST /api/v1/templates, POST /api/v1/envelopes/one-off) nothing was stored or created; printing the document to a new PDF usually makes it simpler. On GET /api/v1/documents/{documentId}/pages/{pageNumber} or .../content, the document was stored before uploads were checked this way and its viewing copy cannot be made; the template, with every field and its position, is still readable from GET /api/v1/templates/{templateId}. Retrying gives the same answer. |
rate_limited | 429 | Exponential from 1s, doubling, with jitter. Honour Retry-After when present. | This key has spent its minute. The limit is per KEY and per minute, and it follows your PLAN rather than the kind of key — 600 requests a minute on every paid plan, 60 on the free plan, and the sandbox gets the same number as production so that an integration which passes in rehearsal passes live. Every successful authenticated response, and this one, carries RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset (seconds), so a client can slow down before it is made to. TWO OPERATIONS ALSO ANSWER IT FOR A REASON OF THEIR OWN. POST /api/v1/envelopes/batches costs one request per row and is refused WHOLE when its rows do not fit what is left of the key’s minute — RateLimit-Remaining says how many would. GET /api/v1/envelopes/{envelopeId}/documents/{position}/draft has its own per-envelope and per-organisation ceilings on renders each minute, and the message says which one refused; there Retry-After is that ceiling’s, while the RateLimit-* headers still describe the key. Retry-After on this refusal is at most 60 and is read from the stored window rather than computed, so two of our instances refusing the same key quote the same instant. ⚠️ A REFUSED REQUEST STILL COUNTS: hammering a limit you have already exceeded pushes the counter higher rather than holding it. Honour Retry-After. If one key genuinely needs more throughput, issue a second one in Settings — the ceiling is a fairness and blast-radius control, not a commercial meter. |
internal_error | 500 | Exponential from 1s, at most three attempts, then stop and alert a human. | Ours, not yours. ⚠️ RETRY WITH THE SAME Idempotency-Key YOU SENT THE FIRST TIME, on any operation that takes one — that is what makes a retry safe here, and sending a NEW key would create a second envelope or send the same one twice. The safe GETs in this document can be retried freely. (This entry used to say every operation here was a GET; the write endpoints have since shipped, and the reasoning moved with them.) |
service_unavailable | 503 | Honour Retry-After when the answer carries one; otherwise exponential from 5s, doubling, for a few minutes. Nothing was created. | Ours, and briefly. Something this operation depends on was not answering, or was already doing as much as it will at once. What it was depends on the operation: on a create, the service that renders a Word document to a PDF, or the isolated service every uploaded document is read in, when it is starting up, at capacity, or did not answer in time; on GET .../documents/{position}/draft, the service that renders the draft itself; on the two template-document reads (GET /api/v1/documents/{documentId}/pages/{pageNumber} and .../content), that same isolated service, which says so with Retry-After. ⚠️ THE DISTINCTION FROM 400 IS THE WHOLE POINT: your request is fine and your document is fine, so do not go and re-save it. On a create, nothing was created and no allowance was spent. On an operation that takes an Idempotency-Key, retry the identical request with the SAME one — a completed key replays, so a retry can never make a second envelope or a second template even if the first attempt got further than this answer suggests. A new key could. ⚠️ ON THE DRAFT READ THE ATTEMPT WAS ALREADY PAID FOR: the render is charged to the envelope’s and the organisation’s per-minute draft ceilings before the renderer is asked, and a render that then fails is not refunded. There is no key to reuse, because there is nothing to replay — so retry on the backoff above rather than at once, or an outage of ours becomes a rate_limited of yours. |