Skip to main content
Alforse clients should handle errors in two layers:
  1. Use the HTTP status to decide whether to retry, re-authenticate, fix input, or escalate.
  2. When present, use error.code for product-specific handling and user-facing guidance.

Response shapes

Framework validation and authentication errors usually use the NestJS default shape:
{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request"
}
Domain errors can return a stable business code:
{
  "error": {
    "code": "PLAN_FEATURE_NOT_ENABLED",
    "message": "Feature is not enabled for this plan",
    "details": {
      "feature": "workflowAutomation"
    }
  }
}
message may be a string, an array of validation messages, or a structured object depending on the endpoint and failure type.

HTTP status codes

StatusMeaningTypical handling
400 Bad RequestMalformed JSON, invalid DTO field, unsupported option, failed human verification, invalid file input, invalid money value, or a write that must use another API.Fix the request body, query parameters, headers, or user input before retrying.
401 UnauthorizedMissing bearer token, expired token, invalid token, invalid credentials, invalid MFA code, revoked refresh token, inactive tenant, inactive user, inactive membership, or inactive role.Re-authenticate, refresh the token if possible, or ask an administrator to restore access.
403 ForbiddenAuthenticated user lacks the required permission, role, subject scope, feature entitlement, plan capacity, request origin, or API signature.Do not retry unchanged. Ask an administrator to grant access, upgrade the plan, or correct request-signing/origin settings.
404 Not FoundResource does not exist, is deleted, is outside the caller’s tenant, or is hidden by subject scope / owner scope.Verify the identifier and caller scope. Do not reveal cross-tenant resource existence.
409 ConflictA unique value already exists, such as subject name, member email, invitation email, enterprise ID, stage code, transition code, or invoice number.Ask the user to choose a different unique value or load the existing resource.
422 Unprocessable EntityThe request is syntactically valid but violates a domain rule: workflow gate, dynamic field rule, lifecycle rule, contract import limit, required evidence, or ownership scope.Show the business message, resolve the missing condition, then retry.
429 Too Many RequestsRate limit exceeded on sensitive endpoints such as authentication.Back off before retrying. Avoid parallel retries.
500 Internal Server ErrorUnhandled server error.Retry only after checking whether the original write succeeded. Escalate with request time and correlation details if available.
503 Service UnavailableTransient dependency failure, object storage unavailable, file scanner unavailable, or human verification temporarily unavailable.Retry with backoff for idempotent reads. For writes, check current resource state before retrying.

Authentication and security

These errors usually rely on HTTP status and message rather than a stable error.code.
StatusMessage examplesWhat it means
400Human verification is required, Human verification failed, Human verification action is invalid, Human verification hostname is invalidThe auth request is missing or failed its Turnstile verification.
400Invitation token is required, Invitation is not pending, Invitation has expired, Password reset token is invalid, Password reset token has expiredThe invitation or password-reset flow cannot continue with the supplied token.
400Unsupported SSO provider, Unsupported SSO client, <Provider> SSO is not configuredThe requested SSO path is not enabled for the tenant or deployment.
401Missing bearer token, Invalid or expired access token, Invalid tenant access tokenThe tenant API token is absent, expired, malformed, or has the wrong scope.
401Invalid credentials, Invalid MFA code, Invalid refresh token, Refresh token has been revokedSign-in, MFA, or refresh-token verification failed.
401Tenant membership is no longer active, Tenant role is no longer active, User is not activeThe identity exists but no longer has active access.
403Browser write requests require an origin or referer, Browser write request origin is not allowed, API request signature is invalidRequest-integrity protection blocked the write.
429Too many requestsRate limiting blocked the request.
503Human verification is temporarily unavailableTurnstile verification could not be completed because its dependency was unavailable.

Plan and quota codes

These codes return 403 Forbidden because the user is authenticated but the tenant is not entitled to complete the action.
CodeMeaningFix
PLAN_CONTRACT_LIMIT_EXCEEDEDCreating or importing contracts would exceed the plan’s contract limit.Archive/delete unused contracts where appropriate or upgrade the plan.
PLAN_SEAT_LIMIT_EXCEEDEDAdding a member or invitation would exceed the plan’s seat limit.Remove inactive invitations/members or upgrade the plan.
PLAN_STORAGE_LIMIT_EXCEEDEDUploading the file would exceed the plan’s storage limit.Delete unused files or upgrade storage entitlement.
PLAN_FEATURE_NOT_ENABLEDThe endpoint requires a feature not enabled for the tenant’s plan.Upgrade the plan or disable the unavailable feature in the client.
PLAN_SUBSCRIPTION_REQUIREDThe tenant has no active subscription record.Contact Alforse support or the tenant administrator.
PLAN_SUBSCRIPTION_INACTIVEThe subscription exists but is not active or trialing.Reactivate or update the subscription.
PLAN_NOT_AVAILABLEThe subscription references an inactive or unavailable plan.Contact Alforse support or the tenant administrator.

File and upload codes

File errors generally return 400 Bad Request; missing file resources return 404 Not Found.
CodeMeaningFix
FILE_NAME_INVALIDFile name is empty or too long.Use a non-empty file name under the allowed length.
FILE_SIZE_EMPTYFile size is zero or not a positive integer.Upload a non-empty file and send the exact byte size.
FILE_TOO_LARGEFile exceeds the allowed size for its kind. Contract, invoice, proof, and receipt-proof files allow up to 20 MB; import files allow up to 10 MB.Compress or split the file.
FILE_CONTENT_TYPE_NOT_ALLOWEDMIME type is not allowed for the file kind.Use an accepted PDF, PNG, JPEG, CSV, TSV, TXT, XLS, or XLSX type depending on kind.
FILE_EXTENSION_NOT_ALLOWEDFile extension is not allowed for the file kind.Rename or export the file to an allowed extension.
FILE_KIND_NOT_ALLOWEDThe requested file kind is not supported.Use one of contract, invoice, proof, receipt-proof, or import.
FILE_REF_INVALIDA stored file reference is missing or malformed.Use a file returned by the file upload flow.
FILE_KIND_MISMATCHThe file kind does not match the requested operation.Use the correct file kind, such as contract file for OCR or invoice file for invoice evidence.
FILE_SCAN_NOT_CLEANFile scanning is pending, failed, skipped when downloads require clean scans, or returned a non-clean result.Wait for a clean scan or upload a safe replacement.
FILE_SCAN_REQUEST_FAILEDThe external scanner request failed.Retry after scanner availability is restored.
FILE_BINDING_CONTEXT_MISMATCHA file is being attached to a payment or contract it does not belong to.Upload or select a file in the correct resource context.
UPLOAD_OBJECT_KEY_MISMATCHUploaded object key does not match the upload intent.Use the exact object key from the presigned upload response.
UPLOAD_OBJECT_NOT_FOUNDThe object storage upload cannot be found.Re-upload using the presigned URL before confirming.
UPLOAD_OBJECT_SIZE_MISMATCHUploaded object size differs from the upload intent.Re-upload the exact file described in the intent.
UPLOAD_OBJECT_TYPE_MISMATCHUploaded content type differs from the upload intent.Upload with the exact content type from the intent.
UPLOAD_OBJECT_CHECKSUM_MISMATCHUploaded checksum differs from the upload intent.Re-upload the file and confirm with the correct checksum.
UPLOAD_TOKEN_INVALIDUpload confirmation token is malformed or does not match the intent.Start a new presign flow.
UPLOAD_TOKEN_EXPIREDUpload confirmation token expired.Start a new presign flow.
UPLOAD_METADATA_MISMATCHConfirmation metadata does not match the presigned upload intent.Confirm with the original file name, size, type, checksum, and object key.

Money and invoice codes

These codes usually return 400 Bad Request.
CodeMeaningFix
AMOUNT_REQUIREDRequired money field is missing.Provide the amount field.
AMOUNT_INVALIDAmount is not a finite plain decimal number.Send a decimal string or safe JSON number.
AMOUNT_UNSAFE_NUMBERAmount is too large to submit safely as a JSON number.Send the amount as a decimal string.
AMOUNT_OUT_OF_RANGEAmount is negative, zero when zero is not allowed, or greater than the allowed target.Adjust the amount to the permitted range.
AMOUNT_SCALE_INVALIDAmount has more decimal places than allowed.Round to the supported scale, usually two decimals.
UNSUPPORTED_CURRENCYCurrency code is not supported.Use a supported ISO currency code for the tenant.
INVOICE_AMOUNT_EXCEEDS_TARGETCumulative invoice amount would exceed the contract, payment, or receivable target.Lower the invoice amount or correct existing invoice records.

Contract and workflow codes

These codes usually return 422 Unprocessable Entity, except where noted.
CodeMeaningFix
OWNER_SCOPE_RESTRICTEDA sales-scoped user tried to create or own a contract for another owner.Use the signed-in user as owner or ask a broader-scope role to make the change.
ASSIGNEE_NOT_ACTIVE_TENANT_MEMBEROwner or assignee is not an active tenant member.Select an active member.
SUBJECT_NOT_FOUNDSubject company is missing or outside the caller’s scope.Select a visible subject company.
CONTRACT_TYPE_NOT_CONFIGUREDContract type code is not configured.Use an enabled contract type or configure it first.
LIFECYCLE_STAGE_NOT_CONFIGUREDRequested lifecycle stage is not configured for the selected template.Use a valid stage from the lifecycle template.
LIFECYCLE_TEMPLATE_NOT_AVAILABLERequested lifecycle template is missing or disabled.Use a published lifecycle template.
DYNAMIC_FIELDS_INVALIDdynamicFields is not an object.Send an object keyed by dynamic field key.
DYNAMIC_FIELD_UNKNOWNDynamic field key is not defined.Remove the field or create the field definition.
DYNAMIC_FIELD_REQUIREDA required dynamic field is empty.Provide a value for the required field.
DYNAMIC_FIELD_TYPE_INVALIDDynamic field value has the wrong type.Match the field type: text, number, money, date, select, multi-select, boolean, URL, member, or attachment.
DYNAMIC_FIELD_OPTION_INVALIDSelect or multi-select value is not in the allowed options.Use one of the configured options.
CONTRACT_PDF_REQUIREDTenant rules require a contract PDF before saving.Attach a contract PDF through the file flow.
REQUIRED_FIELDS_MISSINGTenant rules require additional contract fields.Provide every field listed in details.fields.
CONTRACT_CORE_FIELDS_LOCKEDWorkflow lock prevents direct edits to core fields.Use a workflow transition or ask an administrator to unlock the contract.
WORKFLOW_FIELDS_REQUIRE_TRANSITIONRequest tried to patch workflow/lifecycle fields directly. This returns 400 Bad Request.Use the workflow transition endpoint.
WORKFLOW_REQUIRED_FIELDS_MISSINGTransition requires fields that are still empty.Fill the required fields before transitioning.
WORKFLOW_REQUIRED_EVIDENCE_MISSINGTransition requires evidence files that are missing.Attach the required evidence before transitioning.
WORKFLOW_AI_REVIEW_PENDINGTransition requires AI review to finish or pass.Complete the review requirement before transitioning.
WORKFLOW_FULFILLMENT_OPENTransition requires fulfillment tasks to be closed.Complete or resolve open fulfillment tasks.
WORKFLOW_RECEIVABLES_OPENTransition requires receivables to be closed.Settle or resolve open receivables.
WORKFLOW_NOTE_REQUIREDTransition requires a note.Include a transition note.

Import limits

Contract import uses 422 Unprocessable Entity for invalid or unsafe spreadsheets:
ConditionLimit or meaning
CSV sizeUp to 2 MB.
XLSX sizeUp to 10 MB compressed and 20 MB expanded.
RowsUp to 1,000 imported rows.
ColumnsUp to 100 columns.
Archive safetyXLSX archives with too many files, invalid XML, or unsafe expansion are rejected.

Retry guidance

  • Safe to retry: idempotent GET requests, 503 reads, and 429 after backoff.
  • Check before retrying: POST, PATCH, and DELETE requests that timed out or returned a transient 5xx; the original write may have succeeded.
  • Do not retry unchanged: 400, 401, 403, 404, 409, and 422.