Skip to content

Errors

How the Signkoi API reports errors: HTTP status codes, error types, stable error codes and request ids.

On this page

Successful requests return 2xx. Anything else returns the same JSON error object, so you can always branch on error.type and error.code.

The error object

422 · application/json
{
  "error": {
    "type": "invalid_request_error",
    "code": "validation_failed",
    "message": "The recipients.0.email field must be a valid email address.",
    "param": "recipients.0.email",
    "errors": {
      "recipients.0.email": ["The recipients.0.email field must be a valid email address."]
    },
    "request_id": "0f6c8f5e-2b1d-4c3a-9e7f-5a8b1c2d3e4f"
  }
}
Error object fields
FieldDescription
typeBroad family of the error (see below).
codeStable, machine-readable reason. Branch on this; new codes may be added over time.
messageHuman-readable explanation for logs and developers. It may change — never parse it.
paramThe parameter the error is about, when there is one, e.g. recipients.0.email or files.1.
errorsEvery invalid parameter with its messages (only on validation_failed).
required_scopeThe scope the key is missing (only on insufficient_scope).
request_idSame as the X-Request-Id response header. Include it when you contact support.

HTTP status codes

HTTP status codes
StatusMeaning
200, 201, 204Success. 201 when something was created, 204 when there is no body (deletes).
400The request is malformed.
401No valid API key.
402The plan’s monthly document allowance is used up.
403The key lacks a scope, or the account is suspended.
404The endpoint or resource doesn’t exist — or belongs to someone else.
405The HTTP method isn’t supported on this endpoint.
409The resource’s current state doesn’t allow the action (e.g. changing a sent envelope).
410The resource is gone.
413An upload is too large.
422Validation failed, or a business rule did (e.g. a signer without a signature field).
429Too many requests.
500, 502, 503Something went wrong on our side. Retry with backoff.

Error types

Error types
TypeWhen
invalid_request_errorThe request is invalid: bad parameters, unknown resource or endpoint, unreadable file.
authentication_errorThe API key is missing, invalid, expired or revoked.
permission_errorThe key is valid but may not do this.
conflict_errorThe resource exists but its state doesn’t allow the action.
billing_errorA plan limit was reached.
rate_limit_errorToo many requests; slow down.
api_errorAn error on our side.

Error codes

Authentication and access

StatusCodes
401api_key_missinginvalid_api_key
403insufficient_scopeaccount_suspendedforbidden

Requests

StatusCodeMeaning
422validation_failedA parameter is invalid; see param and errors.
404resource_missingNo such envelope, recipient, template or webhook endpoint (or not yours).
404endpoint_missingUnknown URL. Check the path and the v1 prefix.
405method_not_allowedWrong HTTP method for this endpoint.
422invalid_idempotency_keyIdempotency-Key is empty or longer than 255 characters.
422idempotency_key_reusedThe Idempotency-Key was already used with a different request.
409idempotency_in_progressThe first request with this key is still running. Retry shortly.

Files (creating envelopes)

StatusCodeMeaning
422file_requiredNo file was sent.
422file_conflictBoth file and files[] were sent; use one.
422too_many_filesMore than 10 files.
422invalid_fileThe upload is missing or broken.
422invalid_base64content_base64 isn’t valid base64.
422file_not_pdfThe file isn’t a PDF.
422invalid_pdfThe PDF can’t be read (damaged or encrypted).
422invalid_jsonA multipart field that must hold JSON (recipients, fields, metadata, message) doesn’t parse.
413file_too_largeA file, or all files together, exceeds the size limit.

For file errors param is file, files, files.N or files.N.content_base64, so you know which file failed.

Envelope state

StatusCodeMeaning
409envelope_not_draftOnly drafts can be changed, deleted or sent. Void a sent envelope instead.
409envelope_not_sentThe envelope isn’t out for signature (draft, finished or expired).
409nobody_to_remindNo recipient is waiting for a reminder right now.
409recipient_finishedThe recipient has already finished.
409recipient_not_activeIt isn’t this recipient’s turn yet.
409recipient_in_personIn-person signers get no emails; use a signing URL.
409not_recipients_turnA signing URL is only available to the recipient whose turn it is.
404file_not_readyThe signed PDF and certificate exist once the envelope is completed.

Sending

StatusCodeMeaning
422no_recipientsAdd at least one recipient who signs, approves or views.
422missing_recipient_detailsA recipient lacks a name or email, or the data their verification method needs.
422unassigned_fieldsA field has no recipient, or belongs to someone who can’t fill fields.
422missing_signature_fieldEvery signer needs at least one signature field.
422expiredThe expiry date has already passed.

Plans, limits and our side

StatusCodeMeaning
402plan_limitThe monthly document allowance is used up.
422webhook_limit_reachedAn account can have up to 20 webhook endpoints.
429rate_limitedToo many requests; wait for Retry-After seconds.
500internal_errorUnexpected error. Retry; contact support with the request_id if it persists.

Handling errors

  • 4xx errors mean the request needs to change — don’t retry them unchanged. The one exception is 429.
  • 429 and 5xx are safe to retry with exponential backoff. Send POST requests with an Idempotency-Key so a retry never creates a second envelope.
  • Log the request_id of every failed request.
Branching on error.type
const res = await fetch(url, options);

if (!res.ok) {
    const { error } = await res.json();

    switch (error.type) {
        case 'rate_limit_error':
            // Wait for Retry-After seconds, then retry.
            break;
        case 'api_error':
            // Our side: retry with backoff, reusing the same Idempotency-Key.
            break;
        case 'billing_error':
            // plan_limit: ask the account owner to upgrade.
            break;
        default:
            // invalid_request_error, conflict_error, permission_error, authentication_error:
            // fix the request; don't retry it unchanged.
            console.error(error.code, error.param, error.message, error.request_id);
    }
}

404 instead of 403

To avoid revealing what exists, the API answers 404 resource_missing for resources that belong to someone else.