- Use the HTTP status to decide whether to retry, re-authenticate, fix input, or escalate.
- When present, use
error.codefor product-specific handling and user-facing guidance.
Response shapes
Framework validation and authentication errors usually use the NestJS default shape:message may be a string, an array of validation messages, or a structured object depending
on the endpoint and failure type.
HTTP status codes
| Status | Meaning | Typical handling |
|---|---|---|
400 Bad Request | Malformed 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 Unauthorized | Missing 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 Forbidden | Authenticated 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 Found | Resource 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 Conflict | A 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 Entity | The 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 Requests | Rate limit exceeded on sensitive endpoints such as authentication. | Back off before retrying. Avoid parallel retries. |
500 Internal Server Error | Unhandled server error. | Retry only after checking whether the original write succeeded. Escalate with request time and correlation details if available. |
503 Service Unavailable | Transient 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 andmessage rather than a stable error.code.
| Status | Message examples | What it means |
|---|---|---|
400 | Human verification is required, Human verification failed, Human verification action is invalid, Human verification hostname is invalid | The auth request is missing or failed its Turnstile verification. |
400 | Invitation token is required, Invitation is not pending, Invitation has expired, Password reset token is invalid, Password reset token has expired | The invitation or password-reset flow cannot continue with the supplied token. |
400 | Unsupported SSO provider, Unsupported SSO client, <Provider> SSO is not configured | The requested SSO path is not enabled for the tenant or deployment. |
401 | Missing bearer token, Invalid or expired access token, Invalid tenant access token | The tenant API token is absent, expired, malformed, or has the wrong scope. |
401 | Invalid credentials, Invalid MFA code, Invalid refresh token, Refresh token has been revoked | Sign-in, MFA, or refresh-token verification failed. |
401 | Tenant membership is no longer active, Tenant role is no longer active, User is not active | The identity exists but no longer has active access. |
403 | Browser write requests require an origin or referer, Browser write request origin is not allowed, API request signature is invalid | Request-integrity protection blocked the write. |
429 | Too many requests | Rate limiting blocked the request. |
503 | Human verification is temporarily unavailable | Turnstile verification could not be completed because its dependency was unavailable. |
Plan and quota codes
These codes return403 Forbidden because the user is authenticated but the tenant is not
entitled to complete the action.
| Code | Meaning | Fix |
|---|---|---|
PLAN_CONTRACT_LIMIT_EXCEEDED | Creating or importing contracts would exceed the plan’s contract limit. | Archive/delete unused contracts where appropriate or upgrade the plan. |
PLAN_SEAT_LIMIT_EXCEEDED | Adding a member or invitation would exceed the plan’s seat limit. | Remove inactive invitations/members or upgrade the plan. |
PLAN_STORAGE_LIMIT_EXCEEDED | Uploading the file would exceed the plan’s storage limit. | Delete unused files or upgrade storage entitlement. |
PLAN_FEATURE_NOT_ENABLED | The endpoint requires a feature not enabled for the tenant’s plan. | Upgrade the plan or disable the unavailable feature in the client. |
PLAN_SUBSCRIPTION_REQUIRED | The tenant has no active subscription record. | Contact Alforse support or the tenant administrator. |
PLAN_SUBSCRIPTION_INACTIVE | The subscription exists but is not active or trialing. | Reactivate or update the subscription. |
PLAN_NOT_AVAILABLE | The subscription references an inactive or unavailable plan. | Contact Alforse support or the tenant administrator. |
File and upload codes
File errors generally return400 Bad Request; missing file resources return 404 Not Found.
| Code | Meaning | Fix |
|---|---|---|
FILE_NAME_INVALID | File name is empty or too long. | Use a non-empty file name under the allowed length. |
FILE_SIZE_EMPTY | File size is zero or not a positive integer. | Upload a non-empty file and send the exact byte size. |
FILE_TOO_LARGE | File 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_ALLOWED | MIME 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_ALLOWED | File extension is not allowed for the file kind. | Rename or export the file to an allowed extension. |
FILE_KIND_NOT_ALLOWED | The requested file kind is not supported. | Use one of contract, invoice, proof, receipt-proof, or import. |
FILE_REF_INVALID | A stored file reference is missing or malformed. | Use a file returned by the file upload flow. |
FILE_KIND_MISMATCH | The 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_CLEAN | File 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_FAILED | The external scanner request failed. | Retry after scanner availability is restored. |
FILE_BINDING_CONTEXT_MISMATCH | A 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_MISMATCH | Uploaded object key does not match the upload intent. | Use the exact object key from the presigned upload response. |
UPLOAD_OBJECT_NOT_FOUND | The object storage upload cannot be found. | Re-upload using the presigned URL before confirming. |
UPLOAD_OBJECT_SIZE_MISMATCH | Uploaded object size differs from the upload intent. | Re-upload the exact file described in the intent. |
UPLOAD_OBJECT_TYPE_MISMATCH | Uploaded content type differs from the upload intent. | Upload with the exact content type from the intent. |
UPLOAD_OBJECT_CHECKSUM_MISMATCH | Uploaded checksum differs from the upload intent. | Re-upload the file and confirm with the correct checksum. |
UPLOAD_TOKEN_INVALID | Upload confirmation token is malformed or does not match the intent. | Start a new presign flow. |
UPLOAD_TOKEN_EXPIRED | Upload confirmation token expired. | Start a new presign flow. |
UPLOAD_METADATA_MISMATCH | Confirmation 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 return400 Bad Request.
| Code | Meaning | Fix |
|---|---|---|
AMOUNT_REQUIRED | Required money field is missing. | Provide the amount field. |
AMOUNT_INVALID | Amount is not a finite plain decimal number. | Send a decimal string or safe JSON number. |
AMOUNT_UNSAFE_NUMBER | Amount is too large to submit safely as a JSON number. | Send the amount as a decimal string. |
AMOUNT_OUT_OF_RANGE | Amount is negative, zero when zero is not allowed, or greater than the allowed target. | Adjust the amount to the permitted range. |
AMOUNT_SCALE_INVALID | Amount has more decimal places than allowed. | Round to the supported scale, usually two decimals. |
UNSUPPORTED_CURRENCY | Currency code is not supported. | Use a supported ISO currency code for the tenant. |
INVOICE_AMOUNT_EXCEEDS_TARGET | Cumulative 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 return422 Unprocessable Entity, except where noted.
| Code | Meaning | Fix |
|---|---|---|
OWNER_SCOPE_RESTRICTED | A 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_MEMBER | Owner or assignee is not an active tenant member. | Select an active member. |
SUBJECT_NOT_FOUND | Subject company is missing or outside the caller’s scope. | Select a visible subject company. |
CONTRACT_TYPE_NOT_CONFIGURED | Contract type code is not configured. | Use an enabled contract type or configure it first. |
LIFECYCLE_STAGE_NOT_CONFIGURED | Requested lifecycle stage is not configured for the selected template. | Use a valid stage from the lifecycle template. |
LIFECYCLE_TEMPLATE_NOT_AVAILABLE | Requested lifecycle template is missing or disabled. | Use a published lifecycle template. |
DYNAMIC_FIELDS_INVALID | dynamicFields is not an object. | Send an object keyed by dynamic field key. |
DYNAMIC_FIELD_UNKNOWN | Dynamic field key is not defined. | Remove the field or create the field definition. |
DYNAMIC_FIELD_REQUIRED | A required dynamic field is empty. | Provide a value for the required field. |
DYNAMIC_FIELD_TYPE_INVALID | Dynamic 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_INVALID | Select or multi-select value is not in the allowed options. | Use one of the configured options. |
CONTRACT_PDF_REQUIRED | Tenant rules require a contract PDF before saving. | Attach a contract PDF through the file flow. |
REQUIRED_FIELDS_MISSING | Tenant rules require additional contract fields. | Provide every field listed in details.fields. |
CONTRACT_CORE_FIELDS_LOCKED | Workflow lock prevents direct edits to core fields. | Use a workflow transition or ask an administrator to unlock the contract. |
WORKFLOW_FIELDS_REQUIRE_TRANSITION | Request tried to patch workflow/lifecycle fields directly. This returns 400 Bad Request. | Use the workflow transition endpoint. |
WORKFLOW_REQUIRED_FIELDS_MISSING | Transition requires fields that are still empty. | Fill the required fields before transitioning. |
WORKFLOW_REQUIRED_EVIDENCE_MISSING | Transition requires evidence files that are missing. | Attach the required evidence before transitioning. |
WORKFLOW_AI_REVIEW_PENDING | Transition requires AI review to finish or pass. | Complete the review requirement before transitioning. |
WORKFLOW_FULFILLMENT_OPEN | Transition requires fulfillment tasks to be closed. | Complete or resolve open fulfillment tasks. |
WORKFLOW_RECEIVABLES_OPEN | Transition requires receivables to be closed. | Settle or resolve open receivables. |
WORKFLOW_NOTE_REQUIRED | Transition requires a note. | Include a transition note. |
Import limits
Contract import uses422 Unprocessable Entity for invalid or unsafe spreadsheets:
| Condition | Limit or meaning |
|---|---|
| CSV size | Up to 2 MB. |
| XLSX size | Up to 10 MB compressed and 20 MB expanded. |
| Rows | Up to 1,000 imported rows. |
| Columns | Up to 100 columns. |
| Archive safety | XLSX archives with too many files, invalid XML, or unsafe expansion are rejected. |
Retry guidance
- Safe to retry: idempotent
GETrequests,503reads, and429after backoff. - Check before retrying:
POST,PATCH, andDELETErequests that timed out or returned a transient5xx; the original write may have succeeded. - Do not retry unchanged:
400,401,403,404,409, and422.