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

# Errors

> Nuvion uses conventional HTTP status codes and a consistent error object to communicate what went wrong and how to resolve it.

## The error object

All error responses share the same structure:

```json theme={null}
{
  "status": "400",
  "message": "You don't have enough funds for this transfer. Your available balance is 1,250.00 USD.",
  "type": "error_transfer_insufficient_funds"
}
```

<ResponseField name="status" type="string" required>
  The HTTP status code as a string, mirroring the response status header.
</ResponseField>

<ResponseField name="message" type="string" required>
  A human-readable description of what went wrong and what to do next. Safe to surface to your users.
</ResponseField>

<ResponseField name="type" type="string" required>
  A machine-readable error code. Use this to handle specific error cases programmatically. Follows the format `error_{domain}_{specific_condition}`.
</ResponseField>

<ResponseField name="validations" type="array">
  Present only on validation errors (`error_validation_error`). Contains field-level details when multiple fields fail.

  <Expandable title="validations fields">
    <ResponseField name="[field_name]" type="object">
      An object keyed by the name of the field that failed validation.

      <Expandable title="properties">
        <ResponseField name="type" type="string">
          The specific validation error type for this field.
        </ResponseField>

        <ResponseField name="message" type="string">
          A human-readable description of why this field failed.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### Validation error example

When a request fails validation on multiple fields, the `validations` array provides field-level detail:

```json theme={null}
{
  "status": "422",
  "message": "Validation failed for one or more fields.",
  "type": "error_validation_error",
  "validations": [
    {
      "email": {
        "error_type": "error_validation_email_invalid",
        "message": "That email address doesn't look right. Please check it and try again."
      }
    },
    {
      "phone": {
        "error_type": "error_validation_phone_invalid",
        "message": "Please enter a valid phone number with country code (e.g., +1234567890)."
      }
    }
  ]
}
```

***

## HTTP status codes

| Code  | Meaning               | When it occurs                                                                               |
| ----- | --------------------- | -------------------------------------------------------------------------------------------- |
| `400` | Bad Request           | Malformed request or a business rule violation (e.g. insufficient funds, invalid state)      |
| `401` | Unauthorized          | Missing, invalid, or expired API key                                                         |
| `403` | Forbidden             | Valid key but insufficient permissions for this action                                       |
| `404` | Not Found             | The requested resource doesn't exist                                                         |
| `409` | Conflict              | A uniqueness or state conflict (e.g. duplicate resource, concurrent modification)            |
| `422` | Unprocessable Entity  | Request is well-formed but fails a business rule (e.g. KYC incomplete, compliance rejection) |
| `429` | Too Many Requests     | Rate limit exceeded                                                                          |
| `500` | Internal Server Error | Unexpected error on Nuvion's end                                                             |
| `503` | Service Unavailable   | A Nuvion service or downstream dependency is temporarily unavailable                         |
| `504` | Gateway Timeout       | Request timed out                                                                            |

***

## Handling errors

Check the `type` field to handle specific error cases in your integration. Use the `message` field to surface a reason to your users.

```javascript theme={null}
const response = await fetch('https://api.nuvion.dev/transfers', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${API_KEY}` },
  body: JSON.stringify(payload)
});

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

  switch (error.type) {
    case 'error_transfer_insufficient_funds':
      // Prompt the user to fund their account
      break;
    case 'error_auth_rate_limit_exceeded':
      // Back off and retry after a delay
      break;
    case 'error_validation_error':
      // Surface field-level errors from error.validations
      break;
    default:
      // Log the error and surface error.message to the user
  }
}
```

<Tip>
  Every error response includes an `X-Request-ID` header. Include this in any support request — it lets the Nuvion team trace the exact request in our systems.
</Tip>

***

## Error reference

Error types follow the format `error_{domain}_{specific_condition}`. The domain indicates which part of the API the error originates from.

### Authentication & authorization

<Expandable title="View error codes">
  | Type                                          | Status | Description                                         |
  | --------------------------------------------- | ------ | --------------------------------------------------- |
  | `error_auth_credentials_invalid`              | 401    | Missing or invalid credentials                      |
  | `error_auth_credentials_revoked`              | 401    | API key has been revoked                            |
  | `error_auth_permission_denied`                | 403    | Insufficient permissions for this action            |
  | `error_auth_elevated_permission_required`     | 403    | Action requires administrator permissions           |
  | `error_auth_rate_limit_exceeded`              | 429    | Too many requests — retry after the indicated delay |
  | `error_auth_api_version_locked`               | 403    | API access is locked to a specific version          |
  | `error_auth_api_version_not_supported`        | 400    | The requested API version does not exist            |
  | `error_auth_api_version_not_available`        | 403    | The requested API version is not yet available      |
  | `error_auth_api_version_deprecated`           | 410    | The requested API version has been discontinued     |
  | `error_auth_api_version_access_denied`        | 403    | No access to the requested API version              |
  | `error_auth_verification_token_not_found`     | 404    | Verification token not found                        |
  | `error_auth_verification_token_expired`       | 410    | Verification token has expired                      |
  | `error_auth_verification_token_already_used`  | 409    | Verification token has already been used            |
  | `error_auth_verification_token_invalid`       | 401    | Verification token is invalid                       |
  | `error_auth_email_verification_required`      | 403    | Email must be verified before proceeding            |
  | `error_auth_mfa_already_enrolled`             | 409    | MFA method is already enrolled                      |
  | `error_auth_mfa_enrollment_not_found`         | 404    | MFA enrollment not found                            |
  | `error_auth_mfa_enrollment_already_completed` | 409    | MFA enrollment is already complete                  |
  | `error_auth_mfa_enrollment_inactive`          | 400    | MFA method is inactive                              |
  | `error_auth_mfa_permission_denied`            | 403    | Insufficient permissions to manage this MFA method  |
  | `error_auth_mfa_code_invalid`                 | 401    | MFA verification code is incorrect                  |
  | `error_auth_mfa_verification_in_progress`     | 409    | An MFA verification is already in progress          |
  | `error_auth_mfa_verification_not_in_progress` | 400    | No MFA verification in progress                     |
  | `error_auth_mfa_not_enrolled`                 | 400    | No MFA methods enrolled                             |
</Expandable>

### Validation

<Expandable title="View error codes">
  | Type                                            | Status | Description                                                    |
  | ----------------------------------------------- | ------ | -------------------------------------------------------------- |
  | `error_validation_error`                        | 422    | One or more fields failed validation — see `validations` array |
  | `error_validation_required_field_missing`       | 400    | A required field is missing from the request                   |
  | `error_validation_invalid_format`               | 400    | A field value has an invalid format                            |
  | `error_validation_email_invalid`                | 422    | Email address is invalid                                       |
  | `error_validation_phone_invalid`                | 422    | Phone number is invalid or missing country code                |
  | `error_validation_date_invalid`                 | 422    | Date format is invalid — use `YYYY-MM-DD`                      |
  | `error_validation_amount_invalid`               | 422    | Amount must be a positive number with up to 2 decimal places   |
  | `error_validation_value_out_of_range`           | 400    | Field value falls outside the allowed range                    |
  | `error_validation_invalid_id`                   | 400    | Resource ID is malformed                                       |
  | `error_validation_value_not_supported`          | 422    | Value is not supported for this field                          |
  | `error_validation_customer_location_restricted` | 422    | Operation not supported in the entity's location               |
  | `error_validation_password_reused`              | 422    | Password has been used recently                                |
  | `error_validation_password_weak`                | 422    | Password does not meet strength requirements                   |
  | `error_validation_mfa_medium_invalid`           | 400    | MFA method is not supported                                    |
  | `error_validation_mfa_entity_required`          | 400    | Missing required entity details for this MFA method            |
  | `error_validation_date_range_month`             | 400    | Date range must be within a single month                       |
  | `error_validation_date_range_order`             | 400    | Start date must be before or equal to end date                 |
  | `error_validation_payload_too_large`            | 400    | Request payload exceeds the size limit                         |
  | `error_validation_csv_file_structure`           | 400    | CSV must include a header row and at least one data row        |
  | `error_validation_file_empty`                   | 400    | Uploaded file is empty                                         |
  | `error_validation_file_format_array`            | 400    | File content must be an array of rows                          |
  | `error_validation_file_no_rows`                 | 400    | File contains no rows                                          |
</Expandable>

### Entities

<Expandable title="View error codes">
  | Type                                         | Status | Description                                                            |
  | -------------------------------------------- | ------ | ---------------------------------------------------------------------- |
  | `error_entity_invite_resend_not_available`   | 410    | Invitation cannot be resent yet                                        |
  | `error_entity_has_active_dependencies`       | 400    | Entity has active accounts or dependencies that must be resolved first |
  | `error_entity_invite_expired`                | 410    | Invitation has expired                                                 |
  | `error_entity_invite_already_accepted`       | 409    | Invitation has already been accepted                                   |
  | `error_entity_person_document_link_mismatch` | 422    | Document does not match the person on record                           |
  | `error_entity_user_has_no_access`            | 403    | User does not have access to this entity                               |
  | `error_entity_user_already_has_access`       | 409    | User already has access to this entity                                 |
  | `error_entity_status_due_diligence_required` | 422    | Entity requires additional verification                                |
  | `error_entity_status_not_incomplete`         | 400    | Action requires an incomplete entity profile                           |
</Expandable>

### KYC

<Expandable title="View error codes">
  | Type                                        | Status | Description                                                  |
  | ------------------------------------------- | ------ | ------------------------------------------------------------ |
  | `error_kyc_identity_verification_failed`    | 422    | Identity could not be verified with the provided information |
  | `error_kyc_document_expired`                | 422    | Uploaded document has expired                                |
  | `error_kyc_document_quality_insufficient`   | 422    | Document image quality is too poor to process                |
  | `error_kyc_document_type_not_accepted`      | 422    | Document type is not accepted for this country               |
  | `error_kyc_documents_incomplete`            | 422    | Required documents are missing                               |
  | `error_kyc_application_rejected`            | 422    | KYC application was rejected                                 |
  | `error_kyc_under_compliance_review`         | 422    | Application is under compliance review                       |
  | `error_kyc_sanctions_check_failed`          | 422    | Sanctions check failed — contact support                     |
  | `error_kyc_enhanced_due_diligence_required` | 422    | Enhanced due diligence is required — Nuvion will follow up   |
</Expandable>

### KYB

<Expandable title="View error codes">
  | Type                                        | Status | Description                                            |
  | ------------------------------------------- | ------ | ------------------------------------------------------ |
  | `error_kyb_business_verification_failed`    | 422    | Business registration could not be verified            |
  | `error_kyb_tax_id_invalid`                  | 422    | Tax ID or EIN does not match records                   |
  | `error_kyb_incorporation_documents_missing` | 422    | Incorporation documents are required                   |
  | `error_kyb_beneficial_owners_missing`       | 422    | Beneficial owners with ≥25% ownership must be provided |
  | `error_kyb_business_type_not_supported`     | 422    | Business type is not supported                         |
  | `error_kyb_application_rejected`            | 422    | KYB application was rejected                           |
  | `error_kyb_under_compliance_review`         | 422    | Business application is under compliance review        |
</Expandable>

### Accounts

<Expandable title="View error codes">
  | Type                                   | Status | Description                                                        |
  | -------------------------------------- | ------ | ------------------------------------------------------------------ |
  | `error_account_kyc_incomplete`         | 400    | Identity verification must be completed before creating an account |
  | `error_account_limit_reached`          | 400    | Maximum number of accounts reached                                 |
  | `error_account_type_unavailable`       | 422    | Account type is not available for this entity                      |
  | `error_account_already_exists`         | 409    | An account with these settings already exists                      |
  | `error_account_already_verified`       | 409    | Account is already verified                                        |
  | `error_account_access_blocked`         | 403    | Account access is blocked                                          |
  | `error_account_status_prevents_action` | 400    | Account status does not allow this action                          |
  | `error_account_balance_not_zero`       | 400    | Account must have a zero balance before it can be closed           |
  | `error_account_not_active`             | 400    | Account is not yet active                                          |
  | `error_account_suspended`              | 403    | Account has been suspended                                         |
  | `error_account_closed`                 | 400    | Account is closed                                                  |
</Expandable>

### Transfers

<Expandable title="View error codes">
  | Type                                        | Status | Description                                                          |
  | ------------------------------------------- | ------ | -------------------------------------------------------------------- |
  | `error_transfer_insufficient_funds`         | 400    | Account does not have enough available balance                       |
  | `error_transfer_daily_limit_exceeded`       | 400    | Transfer would exceed the daily limit                                |
  | `error_transfer_transaction_limit_exceeded` | 400    | Transfer amount exceeds the per-transaction limit                    |
  | `error_transfer_monthly_volume_exceeded`    | 400    | Monthly transfer limit has been reached                              |
  | `error_transfer_account_not_active`         | 400    | Account is not active                                                |
  | `error_transfer_counterparty_not_approved`  | 400    | Recipient has not been approved yet                                  |
  | `error_transfer_same_day_cutoff_passed`     | 400    | Same-day cutoff has passed — transfer will process next business day |
  | `error_transfer_outside_business_hours`     | 400    | Wire transfers are only available during business hours              |
  | `error_transfer_compliance_rejected`        | 422    | Transfer was rejected by compliance                                  |
  | `error_transfer_recipient_flagged`          | 403    | Recipient has been flagged — contact support                         |
  | `error_transfer_purpose_code_required`      | 422    | A purpose code is required for this international transfer           |
  | `error_transfer_beneficiary_name_too_long`  | 422    | Recipient name exceeds the character limit                           |
  | `error_transfer_network_unavailable`        | 503    | Payment network is temporarily unavailable                           |
  | `error_transfer_already_processing`         | 409    | Transfer is already being processed                                  |
  | `error_transfer_recipient_account_closed`   | 400    | Recipient account is closed                                          |
  | `error_transfer_bank_returned`              | 400    | Receiving bank returned the transfer — funds have been credited back |
</Expandable>

### Counterparties

<Expandable title="View error codes">
  | Type                                        | Status | Description                                                    |
  | ------------------------------------------- | ------ | -------------------------------------------------------------- |
  | `error_counterparty_account_number_invalid` | 400    | Account number is invalid for this bank                        |
  | `error_counterparty_routing_number_invalid` | 422    | Routing number does not match a known bank                     |
  | `error_counterparty_iban_invalid`           | 422    | IBAN is invalid                                                |
  | `error_counterparty_swift_code_invalid`     | 422    | SWIFT/BIC code is invalid                                      |
  | `error_counterparty_already_exists`         | 409    | A recipient with these bank details already exists             |
  | `error_counterparty_bank_details_missing`   | 422    | Bank name and country are required for international transfers |
  | `error_counterparty_sanctions_check_failed` | 422    | Recipient failed a sanctions check — contact support           |
  | `error_counterparty_verification_failed`    | 422    | Bank details could not be verified                             |
</Expandable>

### Stablecoin wallets

<Expandable title="View error codes">
  | Type                                    | Status | Description                                                       |
  | --------------------------------------- | ------ | ----------------------------------------------------------------- |
  | `error_wallet_generation_failed`        | 400    | Wallet address generation failed                                  |
  | `error_wallet_blockchain_not_supported` | 400    | Blockchain network is not supported                               |
  | `error_wallet_already_exists`           | 409    | A wallet already exists for this account on this network          |
  | `error_wallet_account_not_ready`        | 400    | Account must be approved and active before a wallet can be issued |
  | `error_wallet_blockchain_unavailable`   | 503    | Blockchain network is temporarily unavailable                     |
  | `error_wallet_limit_reached`            | 400    | Maximum number of wallet addresses reached                        |
</Expandable>

### Account details resolution

<Expandable title="View error codes">
  | Type                                   | Status | Description                                       |
  | -------------------------------------- | ------ | ------------------------------------------------- |
  | `error_resolution_account_not_found`   | 404    | No account found matching the provided details    |
  | `error_resolution_format_invalid`      | 422    | Account number format is invalid                  |
  | `error_resolution_bank_not_supported`  | 422    | Account lookups are not supported for this bank   |
  | `error_resolution_timeout`             | 504    | Account lookup timed out                          |
  | `error_resolution_multiple_matches`    | 400    | Multiple accounts matched — provide more detail   |
  | `error_resolution_service_unavailable` | 503    | Account lookup service is temporarily unavailable |
</Expandable>

### Card acquiring

<Expandable title="View error codes">
  | Type                                              | Status | Description                                                |
  | ------------------------------------------------- | ------ | ---------------------------------------------------------- |
  | `error_acquiring_encryption_keys_revoked`         | 403    | Encryption keys have been revoked                          |
  | `error_acquiring_encryption_keys_expired`         | 403    | Encryption keys have expired — rotate them                 |
  | `error_acquiring_decryption_failed`               | 400    | Failed to decrypt payment data                             |
  | `error_acquiring_payment_method_invalid`          | 422    | Payment method is not supported for this request           |
  | `error_acquiring_card_expired`                    | 422    | Card has expired                                           |
  | `error_acquiring_test_token_invalid`              | 422    | Live data cannot be used in the sandbox environment        |
  | `error_acquiring_payment_processing_failed`       | 503    | Payment could not be completed                             |
  | `error_acquiring_payment_initialization_failed`   | 503    | Payment initialization failed                              |
  | `error_acquiring_provider_response_invalid`       | 503    | Invalid response from the payment processor                |
  | `error_acquiring_session_token_generation_failed` | 503    | Payment session token could not be generated               |
  | `error_acquiring_payment_reference_invalid`       | 400    | Payment reference is invalid                               |
  | `error_acquiring_3ds_challenge_failed`            | 422    | 3DS challenge verification failed                          |
  | `error_acquiring_refund_amount_exceeds_charge`    | 400    | Refund amount exceeds the original charge                  |
  | `error_acquiring_refund_duplicate_request`        | 409    | Duplicate refund request detected                          |
  | `error_acquiring_refund_processing_failed`        | 503    | Refund could not be processed                              |
  | `error_acquiring_payment_already_processed`       | 409    | Payment has already been processed                         |
  | `error_acquiring_refund_status_invalid`           | 400    | Payment is not eligible for a refund in its current status |
</Expandable>

### Webhooks

<Expandable title="View error codes">
  | Type                              | Status | Description                                            |
  | --------------------------------- | ------ | ------------------------------------------------------ |
  | `error_webhook_url_invalid`       | 400    | Webhook URL must use HTTPS                             |
  | `error_webhook_delivery_failed`   | 422    | Webhook could not be delivered after multiple attempts |
  | `error_webhook_signature_invalid` | 401    | Webhook signature does not match the signing secret    |
</Expandable>

### Resources & system

<Expandable title="View error codes">
  | Type                                     | Status | Description                                                                                    |
  | ---------------------------------------- | ------ | ---------------------------------------------------------------------------------------------- |
  | `error_resource_not_found`               | 404    | Resource does not exist or the ID is incorrect                                                 |
  | `error_endpoint_not_found`               | 404    | API endpoint does not exist                                                                    |
  | `error_duplicate_resource`               | 409    | A record with this value already exists                                                        |
  | `error_operation_invalid_for_state`      | 400    | Action is not allowed given the resource's current status                                      |
  | `error_concurrent_modification_detected` | 409    | Resource was modified concurrently — refresh and retry                                         |
  | `error_idempotency_key_mismatch`         | 409    | Idempotency key reused with different parameters                                               |
  | `error_idempotency_request_processing`   | 409    | Original request is still processing — wait before retrying                                    |
  | `error_system_internal_error`            | 500    | Unexpected error on Nuvion's end — reference the `X-Request-ID` header when contacting support |
  | `error_system_service_unavailable`       | 503    | Service is temporarily unavailable                                                             |
  | `error_system_timeout`                   | 504    | Request timed out                                                                              |
  | `error_system_dependency_unavailable`    | 503    | A downstream dependency is temporarily unavailable                                             |
  | `error_system_maintenance`               | 503    | Scheduled maintenance is in progress                                                           |
</Expandable>
