Skip to main content
Every error response is { "error": "...", "details"?: {...} }. Read error first: it names the cause. See Errors and rate limits for the full status table.

401 Unauthorized

The API could not accept the key. One of:
  • No Authorization header, or a token that does not start with fsk_.
  • 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 at the end of that day. 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 from GET /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/webhooks routes). Both are Enterprise plan features; the message names the missing one.
  • No credit left to send. Sending charges one package against the organisation’s allowance.

403 Forbidden

  • Missing permission: ... names the permission the key’s role lacks, such as canSendPackages. Grant it from Roles & Permissions, or issue a key on a role that has it.
  • 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 a 404, 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 not ON_HOLD.
  • Send before every file has arrived. PUT each document’s bytes to its uploadUrl before 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.
  • 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.

Upload URL expired

An uploadUrl 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. Compute the HMAC-SHA256 over the raw request bytes, not a re-serialised body: re-serialising changes whitespace and key order, so the digest no longer matches x-flowsign-signature.
  • 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 2xx within 10 seconds; a 3xx counts as a failure because redirects are not followed.
The delivery log in Settings > Webhooks, or GET /api/v1/webhooks/{endpointId}, shows each attempt’s status and error.

Network or CORS error from a browser

The API is meant to be called from your server, not from a web page. A request made directly from browser code fails on CORS before it reaches Flowsign, and it would expose your key to anyone who can open the page. Call the API from your backend and have the page talk to that.