Skip to content

Errors & Response Format

Standard error shape

Errors across the API return the same shape. Fields are omitted when null, so a typical error response is short:

{
  "errorCode": 1008,
  "errorDescription": "Template with this name already exists"
}

at the HTTP status the error corresponds to. The full field set, when present:

Field Type Meaning
httpStatusCode integer Mirrors the response's actual HTTP status
success boolean false on any error path
message string Optional human-readable summary, separate from errorDescription
errorCode integer Numeric error code — see Reference → Error Codes
errorDescription string The resolved error message
responseBody any Optional extra payload attached to specific errors

Common errors at a glance

What a customer is most likely to hit, and where to go next:

errorDescription they'll quote HTTP What it actually means
"Your package has been expired." 400 The organization's package lapsed — blocks sending and signing for everyone in it. See Billing
"Insufficient credit balance to perform this action." 400 The organization is out of credits
"Electronic/Advanced/Qualified signature quota exceeded." 400 That user's personal quota, not the organization's — a colleague may still be able to sign
"Your service plan is currently inactive…" 500 A billing state, not an outage, despite the 500
Link/code expired 400 Signing link is past its configured lifetime. Links can't be extended — re-dispatch to that recipient
OTP invalid / expired / throttled 400 / 400 / 429 Identity verification: 6 digits, 10-minute lifetime, 5 attempts, 30-second resend throttle
Identity not verified 403 Must complete the OTP challenge before signing — see Guest Signing
Invalid document type 400 Not pdf/doc/docx — or replacing an existing file with a non-PDF
Invalid workflow status 400 Recipients and fields are frozen once sent; only DRAFT is editable
Session expired 401 Re-login required, not a fault — see below

Validation errors

A failed request-body validation returns HTTP 400:

{
  "errorCode": 11001,
  "errorDescription": "name: size must be between 2 and 50"
}

A malformed JSON body — unparseable, or a field with the wrong type — returns:

{
  "errorCode": 11001,
  "errorDescription": "Invalid possible value for field: recipientOrder"
}

This one specifically means the type was wrong (a string where a number belonged, an unrecognized enum value), not that the value was out of range.


Worked examples

What the full exchange looks like for the errors that come up most.

Package expired on send

POST /workflow/v1/887/commence
Content-Type: application/json

{ "title": "Please sign", "message": "..." }
HTTP/1.1 400 Bad Request

{
  "errorCode": 16003,
  "errorDescription": "Your package has been expired."
}

Blocks sending and signing across the whole organization — so it presents as "nothing works for anyone here," not as a single stuck document.

Recipient name rejected

POST /workflow/v1/887/recipients
Content-Type: application/json

[ { "name": "J", "emailAddress": "jane@example.com", "useDigitalCert": false, "recipientColor": "#4F46E5" } ]
HTTP/1.1 400 Bad Request

{
  "errorCode": 11001,
  "errorDescription": "name: size must be between 2 and 50"
}

Names also reject digits and punctuation — letters and single interior spaces only, 2–50 characters.

OTP resent too quickly

POST /workflow/v1/887/identity/send-otp
HTTP/1.1 429 Too Many Requests

{
  "errorCode": 16008,
  "errorDescription": "Please wait before requesting another code."
}

The only 429 on the platform. Wait 30 seconds.

Editing a workflow that's already sent

PUT /workflow/v1/887/recipients
HTTP/1.1 400 Bad Request

{
  "errorCode": 11002,
  "errorDescription": "Invalid workflow status"
}

Recipients and fields are frozen once sent — that's what makes the audit trail meaningful. Delegate instead, or void and restart.


Unexpected/unhandled exceptions

A small category of unhandled conditions returns HTTP 401 rather than 400 or 500. If a request carrying a valid, unexpired token comes back 401 and clearly isn't an auth problem, it's likely one of these — suspect the payload (a bad reference id, a constraint violation) rather than the credentials.

Genuinely unexpected server errors return a generic internal-error code at HTTP 500.


HTTP status code conventions

Status Meaning in vScrawl
200 OK Success, with a response body
201 Created Resource created (e.g. document upload)
202 Accepted Async work started — Power Survey dispatch. Also means "TOTP required" on mobile sign-in (details)
204 No Content Success, no response body
400 Bad Request Validation failure, malformed body, or a business-rule rejection (expired package, quota exceeded)
401 Unauthorized Missing/invalid/expired token, or one of the unhandled-exception cases above
403 Forbidden Authenticated but not permitted — usually member-vs-owner, or identity not yet verified
404 Not Found Doesn't exist, or isn't visible to the caller
409 Conflict Duplicate — template name, client id, app name
410 Gone Endpoint deliberately retired
422 Unprocessable Entity Semantically invalid signing input (remote-signing authorization data)
429 Too Many Requests OTP resend throttle — the only place this appears
500 Internal Server Error Unexpected failure — or an inactive service plan, which is a billing state, not an outage

The one exception

The session layer can reject a request before it reaches the rest of the API — in that one case the body doesn't follow the shape above at all:

HTTP/1.1 401 Unauthorized

{ "error": "Session expired, please log in again", "code": "SESSION_EXPIRED" }

Note the different field names (error/code, not errorDescription/errorCode). Any client parsing errors generically must handle both shapes. See Authentication → Session cookie.