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

# Identity Link API Error Codes and Responses

> Complete reference of HTTP status codes and errors from the Identity Link API with causes and resolution steps.

The VU Identity Link API uses standard HTTP status codes to indicate the result of every request. This page groups all errors by status code, explains why they occur, and provides concrete steps to resolve them. It also documents the behavior changes introduced in version 2.2.0.

## Error response format

All error responses share the same schema:

```json theme={null}
{
  "type": "ErrorResponse",
  "message": "Human-readable description of the error"
}
```

Link-specific errors (status 409) use the `LinksErrorGetResponse` schema, where `code` is **numeric**:

```json theme={null}
{
  "code": 4091,
  "name": "LinkExpired",
  "description": "The link has already been used or expired",
  "data": {}
}
```

The 404 for a route that does not exist uses a third format, without `type`: `{"message": "...", "resource": "..."}`. See [404 Not Found](#404-not-found).

## 400 Bad Request

| Scenario | Cause | Resolution |
| - | - | - |
| `invalid request body` | The JSON body does not match the expected schema or contains incorrect data types. | Validate the JSON against the endpoint schema before sending. |
| `missing required field` | A required field such as `type` in `POST /links` or `grant_type` in `POST /oauth/token` is absent. | Review the endpoint documentation and include all required fields. |
| `invalid grant_type` | The `grant_type` value is not `client_credentials`. | Use only `grant_type=client_credentials` in the token request. |
| `device source without coordinates` | A geolocation request declared a device `source` (`gps`, `wifi`, or `cell`) without `deviceLatitude` and `deviceLongitude`. | Include the device coordinates whenever the source is device-based. Nothing downstream can use either half alone. |
| `server-derived field sent by client` | The client sent `tier`, `policy`, `ipDistanceKm`, or `serverIp` on `PATCH /verifications`. | All four are derived server-side and are not accepted properties. Remove them from the payload. |
| `capturedAt out of range` | The reported `capturedAt` is more than 24 hours from the server's clock. | Sync the device clock and send the real sample timestamp. |
| `invalid or missing email` | `PATCH /verifications/identify` received a missing or malformed email. | Validate the email client-side before sending. |

## 401 Unauthorized

| Scenario | Cause | Resolution |
| - | - | - |
| `expired token` | The `access_token` exceeded its 3600-second lifetime. | Request a new token with `POST /oauth/token`. |
| `missing token` | The `Authorization: Bearer <token>` header is absent. | Add the authorization header to all protected requests. |
| `invalid clientId/clientSecret` | The credentials in the `Authorization: Basic` header are incorrect or disabled. | Verify that `clientId` and `clientSecret` are correct. Retrieve them from `GET /users/me`. |

## 403 Forbidden

| Scenario | Cause | Resolution |
| - | - | - |
| `no token provided` | The server detected an authenticated request without a valid token. | Include the Bearer token in the `Authorization` header. |
| `linkId missing or mismatched` | `GET /verifications/{id}/status` was called without `linkId`, with one that does not match the verification, or the verification does not exist. | Always send the `linkId` that originated the verification. It is mandatory from version 2.2.0. |
| `subscription does not belong to caller` | `GET /billing/{idSubscription}` was called with a subscription owned by another company. | Query only subscriptions belonging to your own company. |

## 404 Not Found

| Scenario | Cause | Resolution |
| - | - | - |
| `verification not found` | The `verificationId` does not exist, has expired, or its link is no longer valid. | Confirm the UUID and list available verifications with `GET /verifications`. |
| `link not found` | The `linkId` does not exist. | Check the link UUID or list all links with `GET /links`. |
| `user not found` | The account associated with the token does not exist. | Verify the token belongs to an active account. |
| `customer not found` | The billing customer or subscription does not exist. | Verify the subscription identifier in Stripe. |
| `given resource is not implemented` | The request did not match any API route. This 404 refers to the route, not to a missing record. The `resource` field returns the path exactly as the server received it. | Check that the URL includes the `/api/v1` prefix: this is the most common cause. Also check the path and the HTTP method against the documentation. Nothing needs to be enabled on your account: every documented endpoint is available on the same base URL. |

<Tip>
  From version 2.2.0, `PATCH /verifications`, `PATCH /verifications/error`, and `PATCH /verifications/identify` return **404** when the verification does not exist or has expired. In versions prior to 2.2.0, these endpoints returned 200 without making changes.
</Tip>

<Tip>
  The 404 for a route that does not exist has its own body: it has no `type`, and it exposes `resource` with the path received.

  ```json theme={null}
  {"message": "given resource is not implemented", "resource": "/webhook-endpoints"}
  ```

  The most common cause is losing `/api/v1` when the path is joined to a base URL:

  ```js theme={null}
  new URL('/webhook-endpoints', 'https://api.identity.vu-one.com/api/v1')
  // → https://api.identity.vu-one.com/webhook-endpoints
  new URL('webhook-endpoints', 'https://api.identity.vu-one.com/api/v1')
  // → https://api.identity.vu-one.com/api/webhook-endpoints
  ```

  End the base URL with `/` and write the path without a leading `/`, or use the full URL.
</Tip>

## 409 Conflict

| Scenario | Cause | Resolution |
| - | - | - |
| `link already used` | The link was previously consumed by another user. | Create a new link with `POST /links`. |
| `link expired` | The link exceeded the expiration time configured in your company settings. | Generate a new link or increase `linkConfig.expirationTime` via `PATCH /users/me/company`. |
| `verification status does not allow operation` | An update was attempted on a verification already in `success` or `failed` state. | Do not send updates once the verification has finalized. |
| `identifierAlreadyBound` | `PATCH /verifications/identify` received a different email for a link whose `externalUserId` was supplied by the API at creation. | An API-supplied identifier cannot be overwritten. Create a new link with the correct identifier. |

<Tip>
  From version 2.2.0, `PATCH /verifications` and `PATCH /verifications/error` return **409** when the verification status does not permit the requested operation. In versions prior to 2.2.0, these endpoints returned 200 without making changes.
</Tip>

## 410 Gone

| Scenario | Cause | Resolution |
| - | - | - |
| `verification expired` | The verification exceeded its maximum lifetime. | Create a new link and restart the verification flow. |

## 422 Unprocessable Entity

| Scenario | Cause | Resolution |
| - | - | - |
| `max verifications reached` | The monthly verification quota has been consumed. | Check consumption with `GET /users/me/stats` or contact support to raise the limit. |

## 429 Too Many Requests

| Scenario | Cause | Resolution |
| - | - | - |
| `too many requests` | The rate limit was exceeded. Applies to `POST /vuone/contact-request`, among others. | Implement exponential backoff and respect the `Retry-After` header when present. |

## 500 Internal Server Error

| Scenario | Cause | Resolution |
| - | - | - |
| `internal server error` | A transient issue in the VU infrastructure. | Retry the request with exponential backoff. If the error persists, contact support. |

## 501 Not Implemented

| Scenario | Cause | Resolution |
| - | - | - |
| `grant_type not supported` | A `grant_type` other than `client_credentials` was sent. | Use only `client_credentials` for OAuth2 authentication. |

## 503 Service Unavailable

| Scenario | Cause | Resolution |
| - | - | - |
| `service unavailable` | The service is under maintenance or experiencing degradation. | Check `GET /health/status` for service health and retry later. |

## General recommendations

<Steps>
  <Step title="Retry with exponential backoff">
    For 429, 500, and 503 errors, wait 1 second before the first retry, then 2, 4, and 8 seconds, up to a maximum of 5 attempts.
  </Step>

  <Step title="Do not retry client errors">
    Status codes 400, 401, 403, 404, 409, and 422 signal a problem with the request. Retrying them unchanged produces the same result.
  </Step>

  <Step title="Validate the request body before sending">
    Use a JSON Schema validator to ensure all required fields are present and typed correctly.
  </Step>

  <Step title="Cache tokens">
    The `access_token` lasts 3600 seconds. Reuse it until expiry instead of requesting a new token on every call to avoid unnecessary 401 errors.
  </Step>

  <Step title="Monitor service health">
    Implement periodic checks of `GET /health/status` to detect degradation before it affects your users.
  </Step>
</Steps>


## Related topics

- [Interpreting responses](/en/vucs/face-analysis/responses.md)
- [Reading the response](/en/vucs/antispoofing-face/responses.md)
- [Identity Link API Changelog](/en/identity-link/changelog.md)
- [Errors and diagnostics](/en/vucs/antispoofing-face/errors.md)


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