{ "error": "...", "details"?: {...} }. Read error first: it names the cause. See Errors and rate limits for the full status table.
400 Bad Request
Invalid JSON body. The body could not be parsed. Check for trailing commas, unquoted keys or an empty body.- The action does not fit the resource’s state, such as sending a package that is not a
DRAFT, or sending from a template whose workflow still has a sender question unanswered. The message says which.
401 Unauthorized
The API could not accept the key. The body is always{ "error": "Unauthorized" }, so check each of these:
- No
Authorizationheader, a header that is notBearer <key>, or a token that does not start withfsk_. - Unknown key. Keys are shown once; if the value is lost, create a new one at Settings > API keys.
- Revoked or expired key. Revocation is immediate, and a key with an expiry stops working once that moment passes. Create a new key.
- The key’s role lost the API access permission. An administrator can restore it from Roles & Permissions.
- Wrong
X-Workspace-Id. The header may only repeat the key’s own workspace id. Omit it, or read the id fromGET /api/v1/workspaces. To act in another workspace, create a key for it.
402 Payment Required
- The plan does not include the API (or webhooks, on
/api/v1/webhooksroutes, or custom fields, on/api/v1/custom-fields). These are Enterprise plan features; the message names the missing one. - No credit left to send. Sending charges one package against the organisation’s allowance.
- A plan limit would be exceeded, such as the number of recipients on a package or the number of templates. The message says which.
403 Forbidden
Missing permission: ...names the permission the key’s role lacks, such ascanSendPackages(orMissing permission: one of ...when any of several would do). Grant it from Roles & Permissions, or issue a key on a role that has it.Insufficient template access: ... required. The key’s role has a lower template access level than the call needs. Raise it from Roles & Permissions.IP address not allowed. The organisation has an IP allowlist (Settings > Security) and the request came from outside it. Check the address your request actually leaves from: a cloud function or a CI runner is not your office.This action requires a signed-in session, not an API key. The route is an admin route for signed-in users only, not part of the public API.
404 Not Found
The resource does not exist in the workspace the key acts in, or the key’s role cannot see it. A resource in another workspace is a404, not a 403: create a key for that workspace.
409 Conflict
The request conflicts with the resource’s current state:- Another member is editing the package or template in the app. Documents and fields cannot be changed through the API while that edit lock is held, and a locked draft cannot be sent. Try again once they are done.
- Void on a package that has already ended, on hold on one that is not
IN_PROGRESS, or resume on one that is notON_HOLD. - Send before every file has arrived.
PUTeach document’s bytes to itsuploadUrlbefore sending; a package with no documents is refused the same way. - Download before completion. Signed copies and the certificate exist only once the package has completed.
- Duplicate
externalId. Another package already carries it. OnPOST /api/v1/packages/from-template, repeating theexternalIdof a package the key can see returns that package instead. - 50 active keys. An organisation can hold at most 50; revoke one to make room.
413 Payload Too Large
POST /api/v1/templates/{templateId}/documents refuses a document whose fileSize is over the per-document limit. GET /api/v1/packages/{packageId}/download refuses documents too large to merge into one PDF; use GET /api/v1/packages/{packageId}/download/zip instead.
422 Unprocessable Entity
The JSON was well-formed but failed validation.details maps each failing field path to its messages: recipients.0.email is the email of the first recipient, and details.pageSize on a GET means a query parameter. Unknown merge field, metadata or role keys produce the same shape.
429 Too Many Requests
All/api/v1 routes share one limit of 120 requests per 60-second window, counted per source IP address. Wait at least the Retry-After seconds before retrying, and prefer webhooks over polling.
502 Bad Gateway
POST /api/v1/templates/{templateId}/documents/{documentId}/convert returns 502 when the document conversion service fails. Retry with backoff; if it persists, contact support@flowsign.app.
Upload URL expired
AnuploadUrl is single-use and expires after two hours. If the PUT fails, add the document again with POST /api/v1/packages/{packageId}/documents (or the template equivalent) and upload to the new URL.
Webhook not arriving
- The endpoint is Failing. After 10 consecutive failed deliveries the endpoint is skipped for new events. Resume it in Settings > Webhooks or with
PATCH /api/v1/webhooks/{endpointId}and{ "enabled": true }. A paused endpoint receives nothing either. - Signature mismatch. Sign the
x-flowsign-timestampheader, a., and the raw request body with HMAC-SHA256, then compare with eachv1=entry inx-flowsign-signature. Use the raw bytes, not a re-serialised body: re-serialising changes whitespace and key order, so the digest no longer matches. See Webhooks. - Private address refused. Endpoints must be public
https://URLs. A private, loopback or link-local address is refused at registration, and a delivery whose host resolves that way is exhausted without retries. - Slow or redirecting responses. Respond
2xxwithin 10 seconds; a3xxcounts as a failure because redirects are not followed.
GET /api/v1/webhooks/{endpointId}, shows each attempt’s status and error.

