> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alforse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Errors & Codes

> HTTP status codes, business error codes, and handling guidance for the Alforse API.

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:

```json theme={null}
{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request"
}
```

Domain errors can return a stable business code:

```json theme={null}
{
  "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

| 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 and `message` 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 return `403 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 return `400 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 return `400 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 return `422 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 uses `422 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 `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`.
