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

# Error Code Reference

> The error envelope returned by the Verification REST API, and every error code you can receive from v2 endpoints.

## Error Response Format

Every Verification REST API error uses one envelope:

```json theme={null}
{
  "error": {
    "code": "SESSION_VERIFICATION_NOT_FOUND",
    "message": "Verification not found",
    "details": {
      "verificationId": "019bc4f2-8a31-7c5e-9d02-4f7a1b3e60d8",
      "hint": "Check that the verification ID is correct and belongs to your client"
    }
  },
  "request_id": "9f4c2e8b-31d7-4a06-b25e-8c1f70a9d34e"
}
```

### Response Fields

| Field | Type | Description |
| - | - | - |
| `error.code` | string | Machine-readable identifier in `SCREAMING_SNAKE_CASE`. Stable across releases. Switch on this. |
| `error.message` | string | Human-readable description. May change. Do not switch on it. |
| `error.details` | object | Optional structured context (which parameter failed, allowed values, a hint). |
| `request_id` | string | UUID for this request. Quote it when you contact support. |

<Note>
  Request-body validation failures (a missing or mistyped field) use the lowercase code `validation_error` and list the problems under `details.validation_errors`. Everything else uses the uppercase codes below.
</Note>

## Error Code Structure

Codes are domain-prefixed:

* `AUTH_*`: authentication and access
* `VALIDATION_*`: request validation
* `SESSION_*`: verification session state
* `PROVIDER_*`: eID provider and connection availability
* `RESOURCE_*`: referenced resources (workflows, connection instances)
* `SYSTEM_*`: system errors

## Authentication Errors

<ResponseField name="Invalid Credentials" type="error">
  **Code**: `AUTH_INVALID_CREDENTIALS`
  **HTTP Status**: 401

  The `Authorization` header is missing, is not Basic, is malformed, or the App ID / App Secret pair is wrong.

  **Common Causes**:

  * Sending a Workspace `Bearer` key to a Verification REST endpoint
  * Using credentials from a different app
  * The secret has been rotated
</ResponseField>

<ResponseField name="Data Protected" type="error">
  **Code**: `AUTH_DATA_PROTECTED`
  **HTTP Status**: 403

  Tokens and user data cannot be released for this session. Not reachable for sessions created with the REST API.
</ResponseField>

<Note>
  The OIDC token endpoint (`/v2/token`) does not use this envelope. It answers with standard OAuth 2.0 errors, `{ "error": "...", "error_description": "..." }`: for example `400 invalid_grant` when the authorization code has expired (5 minutes), was already used, or the PKCE verifier does not match, and `401 invalid_client` when client authentication fails. See [Token](/v2/api-reference/oidc/token).
</Note>

## Validation Errors

<ResponseField name="Invalid Parameter" type="error">
  **Code**: `VALIDATION_INVALID_PARAMETER`
  **HTTP Status**: 400

  A parameter is present but not acceptable. `details.parameter` names it and `error.message` explains why.

  **Common Causes**:

  * An unknown `workflowId` was supplied at session creation
  * The app is not provisioned for v2 verification
  * Not exactly one of `connectionId`, `connectionInstanceId`, and `providerId` was sent, `credentialId` was sent without `providerId`, or the provider key is ambiguous
  * The connection is not activated for the app or not available in its environment
  * The connection is not available in this app environment (sandbox or production)
  * A required `userInput` field is missing, or a `select` field has a value outside its options

  **Example Response**:

  ```json theme={null}
  {
    "error": {
      "code": "VALIDATION_INVALID_PARAMETER",
      "message": "Invalid parameter 'userInput.personalNumber': 'personalNumber' is required.",
      "details": { "parameter": "userInput.personalNumber" }
    },
    "request_id": "1e6b40df-7a91-4c33-95f8-2d0ba48e7f16"
  }
  ```
</ResponseField>

<ResponseField name="Invalid User Data" type="error">
  **Code**: `VALIDATION_INVALID_USER_DATA`
  **HTTP Status**: 422

  A `userInput` value is present but the connection or its provider rejected it, for example an `ng-nin` `nationalIdentityNumber` that is not 11 digits. `details.required` names the expected input and `details.hint` explains the rule. A missing required field returns `400 VALIDATION_INVALID_PARAMETER` instead.
</ResponseField>

<ResponseField name="Redirect URI Required" type="error">
  **Code**: `VALIDATION_REDIRECT_URI_REQUIRED`
  **HTTP Status**: 400

  The verification would start a `redirect` flow, but the request has no `redirectUri`. REST creation does not fall back to the app's redirect URI allowlist. Send `redirectUri` in the Create Verification body.
</ResponseField>

<ResponseField name="Request Validation Failed" type="error">
  **Code**: `validation_error`
  **HTTP Status**: 400

  The request body does not match the schema, for example `connectionInstanceId` is a number instead of a string.

  **Example Response**:

  ```json theme={null}
  {
    "error": {
      "code": "validation_error",
      "message": "Request validation failed",
      "details": {
        "validation_errors": ["connectionInstanceId must be a string"],
        "url": "/connect/v2/verifications",
        "method": "POST"
      }
    },
    "request_id": "3a5e91c7-284b-4f60-8d17-b6c04e92a1f8"
  }
  ```
</ResponseField>

## Session Errors

<ResponseField name="Verification Not Found" type="error">
  **Code**: `SESSION_VERIFICATION_NOT_FOUND`
  **HTTP Status**: 404

  No verification with this id is visible to your app.

  **Common Causes**:

  * Wrong or expired verification id
  * The session belongs to another app
  * The stored session environment does not match the authenticated app

  <Note>
    Foreign-app and environment-mismatched lookups return the same response as an unknown ID.
  </Note>
</ResponseField>

<ResponseField name="Invalid Status Transition" type="error">
  **Code**: `SESSION_INVALID_STATUS_TRANSITION`
  **HTTP Status**: 409

  The session is not in a state that allows the operation. `details.currentStatus` and `details.allowed_statuses` explain the mismatch.

  **Common Causes**:

  * Calling `/userinfo` before the status is `completed`
  * Cancelling a session that is already `completed`, `failed`, or `cancelled`
</ResponseField>

<ResponseField name="Invalid Flow" type="error">
  **Code**: `SESSION_INVALID_FLOW`
  **HTTP Status**: 400

  The requested flow cannot be started for this connection.
</ResponseField>

## Workflow configuration

`409 WORKFLOW_NOT_CONFIGURED` means the app has no workflow. Create one before starting a verification. Get Connections remains available but returns instances as disabled until a workflow enables them.

## Provider and Connection Errors

<ResponseField name="Disabled In Workflow" type="error">
  **Code**: `PROVIDER_DISABLED_IN_WORKFLOW`
  **HTTP Status**: 403

  The connection is activated for your app but is not enabled in the workflow this verification resolved to. Enable it on the workflow's **Connections** tab, or pass a `workflowId` where it is enabled.

  **Example Response**:

  ```json theme={null}
  {
    "error": {
      "code": "PROVIDER_DISABLED_IN_WORKFLOW",
      "message": "The requested eID is not enabled in the selected workflow",
      "details": {
        "hint": "Enable this eID in the workflow configuration, or use a workflow where it is enabled."
      }
    },
    "request_id": "c9a35b71-8e4f-4d20-b6a1-5f82e07d3c94"
  }
  ```
</ResponseField>

<ResponseField name="Initialization Failed" type="error">
  **Code**: `PROVIDER_INITIALIZATION_FAILED`
  **HTTP Status**: 502

  The eID provider did not accept the new session. The verification is recorded as `failed`. Start a new one.

  **Common Causes**:

  * Provider outage or timeout
  * Provider rejected the request data
</ResponseField>

<ResponseField name="Provider Error" type="error">
  **Code**: `PROVIDER_ERROR`
  **HTTP Status**: 502

  Generic provider error during the session.
</ResponseField>

<ResponseField name="Provider Unavailable" type="error">
  **Code**: `PROVIDER_UNAVAILABLE`
  **HTTP Status**: 503

  The provider service is temporarily unavailable. Retry with backoff.
</ResponseField>

<Note>
  The v1 codes `PROVIDER_NOT_FOUND` and `PROVIDER_NOT_ACTIVATED` do not occur on v2 endpoints. On v2 you reference a **connection instance** that already exists because it was activated. An unknown or foreign instance id answers `RESOURCE_NOT_FOUND` instead.
</Note>

## Resource Errors

<ResponseField name="Resource Not Found" type="error">
  **Code**: `RESOURCE_NOT_FOUND`
  **HTTP Status**: 404

  A referenced resource does not exist. `details.resource` is `Workflow`, `Connection`, or `ConnectionInstance`.

  **Common Causes**:

  * `workflowId` does not exist for this app on Get Connections. Create Verification reports this as `400 VALIDATION_INVALID_PARAMETER`
  * `connectionId` is not a known catalog connection, or `connectionInstanceId` is unknown or belongs to another app

  **Example Response**:

  ```json theme={null}
  {
    "error": {
      "code": "RESOURCE_NOT_FOUND",
      "message": "ConnectionInstance not found",
      "details": { "resource": "ConnectionInstance", "identifier": "conn_01J8XK2P4M9QR3TV" }
    },
    "request_id": "b21d7f30-2c9a-41ee-8a56-90d4f1c72b03"
  }
  ```
</ResponseField>

## System Errors

<ResponseField name="Internal Error" type="error">
  **Code**: `SYSTEM_INTERNAL_ERROR`
  **HTTP Status**: 500

  Unexpected server error. Retry once after a short delay. If it persists, contact support with the `request_id`.
</ResponseField>

## Error Categories

| Category | HTTP Status Range | Description | Retry Strategy |
| - | - | - | - |
| `client` | 400 to 499 | Client errors | Do not retry automatically |
| `failure` | 502 to 503 | External service failures | Retry with exponential backoff |
| `error` | 500 | System errors | Retry once after delay |

## Error Handling Best Practices

### Retry Strategy

<Tabs>
  <Tab title="Retryable Errors">
    ```javascript theme={null}
    const RETRYABLE_CODES = [
      'PROVIDER_INITIALIZATION_FAILED',
      'PROVIDER_ERROR',
      'PROVIDER_UNAVAILABLE',
      'SYSTEM_INTERNAL_ERROR',
    ];

    async function retryWithBackoff(fn, maxRetries = 3) {
      for (let i = 0; i < maxRetries; i++) {
        try {
          return await fn();
        } catch (err) {
          const code = err.body?.error?.code;
          if (!RETRYABLE_CODES.includes(code) || i === maxRetries - 1) throw err;
          const delay = Math.min(1000 * Math.pow(2, i), 10000);
          await new Promise((resolve) => setTimeout(resolve, delay));
        }
      }
    }
    ```
  </Tab>

  <Tab title="Non-Retryable Errors">
    ```javascript theme={null}
    const NON_RETRYABLE_CODES = [
      'AUTH_INVALID_CREDENTIALS',
      'AUTH_DATA_PROTECTED',
      'VALIDATION_INVALID_PARAMETER',
      'VALIDATION_INVALID_USER_DATA',
      'VALIDATION_REDIRECT_URI_REQUIRED',
      'validation_error',
      'SESSION_VERIFICATION_NOT_FOUND',
      'SESSION_INVALID_STATUS_TRANSITION',
      'PROVIDER_DISABLED_IN_WORKFLOW',
      'RESOURCE_NOT_FOUND',
    ];

    function handleError(err) {
      const code = err.body?.error?.code;
      if (NON_RETRYABLE_CODES.includes(code)) {
        console.error('Non-retryable error:', err.body.error, err.body.request_id);
        return { success: false, error: err.body.error };
      }
    }
    ```
  </Tab>
</Tabs>

### User Communication

| Error Code | User-Friendly Message |
| - | - |
| `AUTH_INVALID_CREDENTIALS` | "Authentication failed. Please check your credentials." |
| `VALIDATION_INVALID_PARAMETER` | "Some required information is missing or invalid. Please try again." |
| `SESSION_VERIFICATION_NOT_FOUND` | "Your session has expired. Please start over." |
| `SESSION_INVALID_STATUS_TRANSITION` | "This verification has already been completed." |
| `PROVIDER_DISABLED_IN_WORKFLOW` | "This identity method is not available." |
| `PROVIDER_UNAVAILABLE` | "The identity service is temporarily unavailable. Please try again later." |
| `SYSTEM_INTERNAL_ERROR` | "Something went wrong on our end. Please try again." |

### Error Context

Always log the `request_id` together with your own context:

```javascript theme={null}
function logError(body, appContext) {
  console.error({
    code: body.error.code,
    message: body.error.message,
    details: body.error.details,
    requestId: body.request_id,
    verificationId: appContext.verificationId,
    environment: appContext.environment,
    // Never log the App Secret, access tokens, or user data
  });
}
```

## Support

For persistent errors or issues not covered here:

<Card title="Developer Support" icon="envelope">
  **Email**: [support@hopae.com](mailto:support@hopae.com)

  **Include in your report**:

  * Error code and `request_id`
  * Timestamp
  * Verification ID (if available)
  * Application environment (sandbox / production)
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.