# Errors and status codes

> Every RemakeCV API error returns a code, a human-readable message and a request_id. Full reference of every error code the API can return.

Source: https://www.remakecv.com/help/api-reference/errors
Last updated: 2026-08-21

---
API errors return an object containing a machine-readable `code`, a human-readable `message` and a `request_id`. Branch your logic on `code` rather than `message`, since messages may be reworded. Always log the `request_id` — it is what support needs to trace a specific failed call.

## Error shape

```json
{
  "error": {
    "code": "validation_error",
    "message": "File exceeds maximum size of 10MB",
    "request_id": "3f9a1c72-8b04-4e51-9d2a-77c0e5b1a934"
  }
}
```

The same identifier is returned in the `X-Request-Id` response header on **every** response, successful or not.

## Every error code

| Status | Code | Meaning | What to do |
|---|---|---|---|
| `400` | `validation_error` | Request was malformed, or the file exceeded the size limit | Fix the request; the message names the specific problem |
| `400` | `upload_required` | No file was included on a request that needs one | Send the file in the `file` multipart field |
| `400` | `acting_user_required` | `acting_user_email` was not supplied | Add it |
| `400` | `storage_required` | The operation needs CV storage, which is disabled | Enable CV storage for your company |
| `401` | `unauthorized` | `Authorization` header missing or malformed | Send `Authorization: Bearer <key>` |
| `401` | `invalid_api_key` | Key not found, inactive, revoked or expired | Check the key; request a replacement if needed |
| `403` | `api_disabled` | Public API not enabled for this company | Email support@remakecv.com |
| `403` | `cv_storage_disabled` | CV storage is off, so stored CVs cannot be listed or fetched | Enable storage, or use the `download_url` returned at processing time |
| `403` | `forbidden` | The key is not permitted to access this resource | Check the resource belongs to your company |
| `404` | `not_found` | The requested CV does not exist | Check the `cvId` |
| `404` | `company_not_found` | The key's company no longer exists | Contact support |
| `404` | `acting_user_invalid` | The acting user is not a member of this company | Use a valid consultant's email |
| `429` | `rate_limit_exceeded` | Too many requests | Back off and retry — see [rate limits](https://www.remakecv.com/help/api-reference/rate-limits.md) |
| `500` | `internal_error` | Something failed on our side | Retry once; if it persists, send us the `request_id` |
| `400` / `500` | `process_failed` | Processing failed — **also how credit rejections surface** | Read `message` |
| `400` / `500` | `storage_failed` | Processed, but could not be stored | The `download_url` may still work |

## Which errors are worth retrying?

| Code | Retry? |
|---|---|
| `rate_limit_exceeded` | Yes, with exponential backoff — costs nothing |
| `internal_error` | Once, then escalate |
| `process_failed` / `storage_failed` | **Cautiously** — these can occur after a credit was spent, so each retry may cost another |
| Everything else | No — retrying will produce the same result |

> **Warning:** 
Do not retry `4xx` errors in a loop. They indicate a problem with the request, so a retry fails identically while consuming your rate-limit budget.

## Do errors consume credits?

Usually not. Validation failures, authentication failures and rate limits are rejected before any processing, so they cost nothing.

**Two exceptions both spend a credit**, because they occur after the CV has already been processed:

| Error | Why the credit is gone |
|---|---|
| `400 storage_required` | CV storage is disabled for your company. The pipeline runs, the credit is deducted, and *then* the storage check fails |
| `400`/`500 storage_failed` | The CV parsed, but storing it failed |

Neither response includes a `download_url` — there is no way to recover the file from them.

> **Warning:** 
If CV storage is disabled for your company, **every** `POST /cvs/process` call spends a credit and returns an error. Confirm storage is enabled before you begin integrating.

## Credit rejections come back as `process_failed`

There is no dedicated credit error code. RemakeCV returns `400 process_failed` with `message` set to either `No credits left` (company balance exhausted) or `credit limit reached` (a per-user or shared-pool cap). Branch on `message` for these two, since the remedies differ — see [credits explained](https://www.remakecv.com/help/account-and-billing/credits-explained.md).

## What should I log?

At minimum: `request_id`, `code`, HTTP status, the endpoint, and the `acting_user_email`. That set is enough for support to reconstruct almost any failure without a further round trip.

## Frequently asked questions

### Should I branch on the code or the message?

Always the code. Messages are written for humans and may be reworded; codes are the stable contract.

### What is request_id for?

It uniquely identifies the call in our logs. Include it when contacting support and we can trace exactly what happened. It is also returned in the X-Request-Id response header.

### Do failed requests consume credits?

Usually not — validation, auth and rate-limit rejections are free. But storage_required and storage_failed occur after processing, so those do spend a credit.
