Skip to content

Error Format ​

All error responses use RFC 7807 Problem Details with Content-Type: application/problem+json.

Response shape ​

json
{
  "type":     "https://docs.comprobify.com/errors/validation-error",
  "title":    "Validation Failed",
  "status":   400,
  "code":     "VALIDATION_FAILED",
  "detail":   "Validation failed",
  "instance": "/v1/documents"
}
FieldDescription
typeURL linking to the documentation page for this error type (this site)
titleShort, stable description of the error type
statusHTTP status code (same as the response status)
codeStable machine-readable key — use this for i18n and programmatic handling
detailHuman-readable explanation of this specific occurrence
instanceThe request path that produced the error

Using code for programmatic handling ​

The code field is the stable key your client application should switch on. It never changes for a given situation, regardless of changes to the human-readable detail text.

js
switch (error.code) {
  case 'CERTIFICATE_EXPIRED':
    return 'Your signing certificate has expired. Replace it in issuer settings.';
  case 'RESEND_COOLDOWN':
    return 'Please wait before requesting another email.';
  case 'QUOTA_EXCEEDED':
    return 'Monthly invoice limit reached. Upgrade your plan.';
  default:
    return error.detail;
}

Validation errors ​

When code is VALIDATION_FAILED, an additional errors array lists each field that failed:

json
{
  "type":   "https://docs.comprobify.com/errors/validation-error",
  "title":  "Validation Failed",
  "status": 400,
  "code":   "VALIDATION_FAILED",
  "detail": "Validation failed",
  "instance": "/v1/documents",
  "errors": [
    {
      "field":   "buyer.email",
      "message": "Buyer email is required and must be a valid email address",
      "code":    "buyer.email",
      "value":   ""
    }
  ]
}

Each entry in errors has:

FieldDescription
fieldThe request body path that failed (e.g. buyer.email, items[0].taxes[0].code)
messageEnglish description of the failure
codeField path with array indices stripped — stable key for field-level localization (e.g. items.taxes.code)
valueThe value that was submitted

SRI errors ​

POST /:accessKey/send and GET /:accessKey/authorize are asynchronous (see Send to SRI) — SRI_SUBMISSION_FAILED can no longer be returned as an HTTP response from either endpoint. A network failure now happens in the background and is recorded as an ERROR document event instead; see SRI Submission Failed for details. The shape below is kept for reference:

When code is SRI_SUBMISSION_FAILED, an additional sriMessages array contains the raw messages returned by the SRI SOAP service:

json
{
  "type":   "https://docs.comprobify.com/errors/sri-error",
  "title":  "SRI Submission Failed",
  "status": 502,
  "code":   "SRI_SUBMISSION_FAILED",
  "detail": "SRI rejected the document",
  "instance": "/v1/documents/1503.../send",
  "sriMessages": [
    {
      "identifier": "35",
      "message":    "ARCHIVO NO CUMPLE ESTRUCTURA XML",
      "type":       "ERROR"
    }
  ]
}

All error codes ​

Most errors carry a specific code that is more precise than the HTTP status alone. Switch on code, not on status, to handle errors programmatically.

400 Bad Request ​

CodeWhen
VALIDATION_FAILEDOne or more request fields failed validation — see errors[]
CERTIFICATE_INVALIDP12 file is corrupted or not a valid PKCS#12 archive
CERTIFICATE_PASSWORD_INVALIDP12 password is incorrect
CERTIFICATE_KEY_NOT_FOUNDSigning key bag not found inside the P12
CERTIFICATE_EXPIREDCertificate notAfter date has passed
ISSUER_ID_REQUIREDX-Issuer-Id header is missing on a document endpoint
ISSUER_ID_INVALIDX-Issuer-Id is not a valid UUID
INVALID_OR_EXPIRED_TOKENEmail verification token is invalid or has expired
DOCUMENT_TYPE_NOT_ENABLEDRequested document type is not active for this issuer
DOCUMENT_TYPE_NOT_SUPPORTEDDocument type code is not registered in the system
INVALID_STATE_TRANSITIONDocument operation is not valid for its current status
DOCUMENT_NOT_AUTHORIZEDOperation (RIDE, email, void) requires document status AUTHORIZED
DOCUMENT_VOID_CONFIRMATION_REQUIREDPOST /:accessKey/void was called without confirmedSriVoid: true
SELF_REVOCATION_FORBIDDENCannot revoke the API key used to authenticate this request
INVALID_FILE_UPLOADUploaded file is missing, the wrong type, or exceeds the field's size limit (e.g. a logo over 500 KB)
PROOF_FILE_LIMIT_REACHEDPayment already has the maximum number of active proof files (10) — delete one before uploading more
VERSION_MISMATCHThe Terms version being accepted does not match the currently published one (web app only — the current document is shown again)
LAST_ISSUER_CANNOT_BE_REMOVEDTenant has only one active issuer left — it cannot be removed
LAST_DOCUMENT_TYPE_CANNOT_BE_REMOVEDIssuer has only one active document type left — it cannot be removed
ISSUER_HAS_DOCUMENTSIssuer has issued documents (in either environment) and cannot be removed
SEQUENTIAL_CANNOT_DECREASEnextSequential is not greater than the counter's current value
TIER_CHANGE_NO_OPRequested tier and billing interval on Change Tier both match the subscription's current values
SEAT_CHANGE_NO_OPRequested extraSeats on Change Seats matches the subscription's current count
INVALID_BILLING_INTERVALbillingInterval on Create Subscription or Change Tier is not MONTHLY or YEARLY
BAD_REQUESTOther malformed request (fallback — read detail)

401 Unauthorized ​

CodeWhen
API_KEY_ENV_MISMATCHAPI key environment (sandbox/production) does not match the tenant's current environment
UNAUTHORIZEDMissing, invalid, or revoked API key (fallback)

402 Payment Required ​

CodeWhen
QUOTA_EXCEEDEDMonthly document quota reached — upgrade plan
BRANCH_LIMIT_REACHEDTenant has reached the maximum number of branches for their plan
ISSUE_POINT_LIMIT_REACHEDBranch has reached the maximum number of issue points for this plan
WEBHOOK_ENDPOINT_LIMIT_REACHEDTenant has reached the maximum number of webhook endpoints for their plan
API_KEY_LIMIT_REACHEDTenant has reached the maximum number of active API keys for their plan
DOCUMENT_TYPE_NOT_IN_TIERDocument type isn't included in the tenant's current plan — upgrade to enable it

403 Forbidden ​

CodeWhen
ISSUER_FORBIDDENX-Issuer-Id names an issuer that belongs to a different tenant
ACCOUNT_SUSPENDEDTenant account is suspended — contact support
INTERNAL_SERVICE_ONLYAction is reserved for the Comprobify web app — do it from there
EMAIL_VERIFICATION_REQUIREDOperation requires a verified email address
AGREEMENT_ACCEPTANCE_REQUIREDPromotion blocked — one or more legal agreements are still not accepted; accept them in the web app
PRODUCTION_KEY_REQUIRES_PROMOTIONProduction API key cannot be created before promoting to production
INSUFFICIENT_SCOPEThe API key doesn't carry the scope the endpoint requires — see API Keys → Scopes
SCOPE_ESCALATION_FORBIDDENPOST /v1/keys — requested scopes include one the requesting key doesn't itself hold
ISSUER_ISSUING_PAUSEDIssuer is active but has been paused (PATCH /v1/issuers/:id/can-issue) — cannot create or rebuild documents
FORBIDDENOther permission failure (fallback — read detail)

404 Not Found ​

CodeWhen
ISSUER_NOT_FOUNDIssuer ID in X-Issuer-Id or URL parameter does not exist
SOURCE_ISSUER_NOT_FOUNDsourceIssuerId not found or belongs to a different tenant
WEBHOOK_ENDPOINT_NOT_FOUNDWebhook endpoint not found or belongs to a different tenant
SUBSCRIPTION_NOT_FOUNDSubscription not found
PAYMENT_NOT_FOUNDPayment not found, or belongs to a different tenant
AGREEMENT_NOT_FOUNDNo document of the requested type (TERMS, PRIVACY, or DPA) has been published yet
NOT_FOUNDOther resource not found (document, API key — read detail)

409 Conflict ​

CodeWhen
ALREADY_VERIFIEDAttempting to resend verification to an already-verified account
SUBSCRIPTION_ALREADY_IN_FLIGHTTenant already has a subscription in progress (promotion with tier, or Admin's Create Subscription)
NO_ACTIVE_SUBSCRIPTIONCancel, Change Tier, or Change Seats requested but the tenant has no ACTIVE subscription
TIER_CHANGE_ALREADY_PENDINGA tier/billing-interval change is already scheduled, or its payment is already in flight, for this subscription — also returned by Change Seats when a billing-interval change is pending
SEAT_CHANGE_ALREADY_PENDINGA seat change is already scheduled, or its payment is already in flight, for this subscription
CANCELLATION_ALREADY_PENDINGA cancellation (DELETE /v1/subscriptions) is already scheduled for this subscription
PAYMENT_NOT_CANCELLABLEDELETE /v1/payments/:id was called on a payment that's no longer PENDING (proof already submitted or reviewed), or on a renewal payment
CONFLICTIdempotency key reused with a different payload, payment already decided, or other conflict

429 Too Many Requests ​

CodeWhen
RESEND_COOLDOWNResend verification requested again before the 60-second cooldown elapsed
TOO_MANY_REQUESTSAPI key rate limit exceeded

500 / 502 ​

CodeWhen
SRI_SUBMISSION_FAILEDSRI SOAP service returned an error or unexpected HTTP status — no longer surfaced via any HTTP response (see SRI errors above); now recorded as a document ERROR event
INTERNAL_ERRORUnexpected server error

Comprobify API Documentation — API v1.3.1