# POST /cvs/process

> Upload a CV for parsing. Returns the extracted candidate name, latest employer and role, plus a signed URL to the stored source file. Does not render a formatted document.

Source: https://www.remakecv.com/help/api-reference/endpoints/process-a-cv
Last updated: 2026-08-21

---
`POST /cvs/process` uploads a CV to RemakeCV as multipart form data, parses it, and returns the extracted candidate name, latest employer and latest role plus a signed URL to the stored file. It requires the file and `acting_user_email`, needs CV storage enabled, and consumes one credit per call.

> **Danger:** 
**This endpoint does not render a document.** It extracts and stores a CV. The `download_url` it returns points at the **source file you uploaded**, converted to PDF — not a CV rendered into your template. Template rendering is not available on the public API today. If you need branded output, use the web app or contact support@remakecv.com.

> **Warning:** 
**CV storage must be enabled for your company.** If it is not, every call still runs the full pipeline and **spends a credit**, then returns `400 storage_required`. Confirm storage is on before you start integrating.

## Request

`POST /cvs/process` · `multipart/form-data` · **Authentication required**

- `file` _binary_ (required) — 
The CV to process. Accepts `.pdf`, `.doc` and `.docx`. Maximum 10MB by default.

- `acting_user_email` _string_ (required) — 
Email address of the consultant this request is on behalf of. Determines template visibility and which credit limits apply.

- `template_id` _string | null_ — 
Influences the **extraction schema** for a small number of company-specific configurations. It does not render anything, and it is not validated — an unknown value is accepted silently.

When omitted, a separate public-API setting is used, falling back to the literal `default`. That setting is **not** the same as the `is_default` template returned by [`GET /templates`](https://www.remakecv.com/help/api-reference/endpoints/list-templates.md); contact support@remakecv.com to set it.

- `gender` _string_ — 
Free text passed into the extraction prompt as context about the candidate. It biases how the model reads the CV. Omit it unless you have a specific reason.

- `blurb` _string_ — 
A **style exemplar**, not content. It is shown to the model as an example summary to imitate when generating a candidate summary, and never appears verbatim in the output. It is only consulted when the CV has no existing summary.

```bash
curl -X POST "https://app.remakecv.com/api/public/v1/cvs/process" \
  -H "Authorization: Bearer $REMAKECV_API_KEY" \
  -F "file=@candidate-cv.pdf" \
  -F "acting_user_email=consultant@agency.com" \
  -F "template_id=42"
```

## Response

```json
{
  "data": {
    "id": 1234,
    "stored": true,
    "storage_enabled": true,
    "candidate_name": "Alex Morgan",
    "latest_company": "Northwind Logistics",
    "latest_role": "Operations Manager",
    "processing_method": "text",
    "download_url": "https://storage.googleapis.com/..."
  },
  "pagination": null,
  "error": null
}
```

- `id` _integer | null_ — 
The stored CV's identifier, or `null` when CV storage is disabled for your company.

- `stored` _boolean_ — 
Always `true` on a 200 response. A CV that could not be stored returns an error instead.

- `storage_enabled` _boolean_ — 
Always `true` on a 200 response — storage is a prerequisite, so a company without it never reaches this response.

- `candidate_name` _string | null_ — 
Extracted candidate name. `null` if it could not be determined.

- `latest_company` _string | null_ — 
The candidate's most recent employer.

- `latest_role` _string | null_ — 
The candidate's most recent job title.

- `processing_method` _string_ — 
`text` when the document had an extractable text layer, `image` when OCR was required.

- `download_url` _string_ — 
Signed URL for **the source CV you uploaded, as a PDF** (Word files are converted). Valid for **1 hour**.

> **Warning:** 
`download_url` expires after **1 hour**. Do not store it in a database or send it to a client. Store `id` instead and fetch a fresh URL from [`GET /cvs/{cvId}/file`](https://www.remakecv.com/help/api-reference/endpoints/get-cv-file.md) when you need one.

## What the API does not expose

Worth knowing before you design around it:

| Not available | Detail |
|---|---|
| Template-rendered output | No public endpoint renders a document |
| The parsed CV JSON | Stored, but not returned by any public endpoint |
| Reprocessing | The reprocess flag is fixed off; every call is a new CV and costs a credit |
| Forcing OCR | Processing mode is fixed to automatic |
| Filtering CVs by consultant | Not exposed on [`GET /cvs`](https://www.remakecv.com/help/api-reference/endpoints/list-cvs.md) |

## Errors

| Status | Code | Cause |
|---|---|---|
| `400` | `upload_required` | No file in the `file` field |
| `400` | `acting_user_required` | `acting_user_email` missing |
| `400` | `validation_error` | File too large, or malformed multipart body |
| `401` | `invalid_api_key` | Key invalid, revoked or expired |
| `400` | `storage_required` | CV storage is disabled — **a credit is still spent** |
| `403` | `api_disabled` | Public API not enabled for this company |
| `400`/`500` | `process_failed` | Processing failed. Credit rejections arrive here, with the reason in `message` |
| `400`/`500` | `storage_failed` | Parsed, but storing failed — **credit already spent, and no `download_url` is returned** |
| `404` | `acting_user_invalid` | Acting user is not a member of this company |
| `429` | `rate_limit_exceeded` | Over 30 requests per minute |

See [errors](https://www.remakecv.com/help/api-reference/errors.md).

## Notes

- **One credit per call that reaches processing.** Validation, auth and rate-limit rejections cost nothing, but `storage_required` and `storage_failed` occur *after* the credit is deducted.
- **`processing_method: "image"` means OCR ran.** Those results warrant closer review — see [scanned PDFs and OCR](https://www.remakecv.com/help/troubleshooting/scanned-pdfs-and-ocr.md).
- **`template_id` is not validated.** An unknown ID is accepted and quietly ignored.

## Frequently asked questions

### What is the maximum file size?

10MB by default, configurable per company. Exceeding it returns 400 validation_error.

### Does download_url give me the formatted CV?

No. It points at the source file you uploaded, converted to PDF. The public API does not render CVs into your template — that is only available in the web app.

### How long does download_url stay valid?

One hour. For longer-lived access, store the returned CV id and fetch a fresh URL from GET /cvs/{cvId}/file when needed.

### Does a failed call consume a credit?

Usually not — validation, auth and rate-limit rejections are free. But storage_required and storage_failed happen after the credit is deducted, so those do cost one.
