Files
Reactive-Resume/docs/guides/using-the-patch-api.mdx
T
Amruth Pillai d46b4b5815 docs: rewrite the documentation for v6
Rewrite every guide for the redesigned app, add guides for new features (documents, editor modes, check, cover letters, assistant, applications, self-hosting upgrade and environment reference), remove v5-only pages with redirects, and replace every screenshot.
2026-09-30 05:07:06 +02:00

231 lines
9.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Using the patch API"
description: "Change individual fields of a Reactive Resume with JSON Patch (RFC 6902): add, remove, replace and move items, set dates and avoid overwriting edits."
---
The patch endpoint lets you make small, targeted changes to a resume's content without sending the whole document. You send a list of [JSON Patch (RFC 6902)](https://datatracker.ietf.org/doc/html/rfc6902) operations, and the server applies them together and returns the updated resume. This is the same mechanism the MCP server's `apply_resume_patch` tool uses.
## Before you start
- Create an API key and try a first request, as described in [Using the API](/guides/using-the-api).
- Find the resume's ID with `GET /api/openapi/resumes`, then fetch its current content with `GET /api/openapi/resumes/{id}`. Paths in your operations point into the `data` object of that response.
- Keep the [JSON resume schema](/guides/json-resume-schema) at hand. It lists every field, its type and which fields a new item needs.
## Choose PATCH or PUT
| You want to | Use |
| --- | --- |
| Change one field, such as the headline or a company name | `PATCH /resumes/{id}` |
| Add, remove or reorder entries in a section | `PATCH /resumes/{id}` |
| Change the template, colors, fonts or layout | `PATCH /resumes/{id}` |
| Rename the resume, change its slug or tags, or make it public | `PUT /resumes/{id}` |
| Replace the whole resume content at once | `PUT /resumes/{id}` with `data` |
PATCH only changes the resume's `data`. The name, slug, tags and public setting sit outside `data`, so change them with `PUT`, which updates only the fields you send.
## Send a patch
```http
PATCH /api/openapi/resumes/{id}
x-api-key: YOUR_API_KEY
Content-Type: application/json
```
The body holds the operations, and optionally the version of the resume you based them on:
```json
{
"expectedUpdatedAt": "2026-09-30T00:10:08.197Z",
"operations": [
{ "op": "replace", "path": "/basics/headline", "value": "Senior Game Developer" }
]
}
```
| Field | Required | Description |
| --- | --- | --- |
| `operations` | Yes | At least one JSON Patch operation. They run in order. |
| `expectedUpdatedAt` | No | The resume's `updatedAt` when you read it. If the resume has changed since, the patch is rejected with `409`. See [Avoid overwriting other edits](#avoid-overwriting-other-edits). |
Each operation has these properties:
| Property | Required | Description |
| --- | --- | --- |
| `op` | Yes | `add`, `remove`, `replace`, `move`, `copy` or `test` |
| `path` | Yes | A [JSON Pointer (RFC 6901)](https://datatracker.ietf.org/doc/html/rfc6901) into the resume data, such as `/basics/name` |
| `value` | For `add`, `replace` and `test` | The value to write or compare |
| `from` | For `move` and `copy` | A JSON Pointer to the source |
A successful patch returns `200` with the full updated resume, including its new `updatedAt`.
## Examples
### Replace basic fields
```bash
curl -X PATCH "https://rxresu.me/api/openapi/resumes/YOUR_RESUME_ID" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{ "op": "replace", "path": "/basics/name", "value": "David Kowalski" },
{ "op": "replace", "path": "/basics/headline", "value": "Senior Game Developer" }
]
}'
```
### Add an experience entry
A new entry must be a complete item: include every required field of that item type, a unique `id` (a UUID) and `"hidden": false`. Set its dates in `dates` and leave `period` empty; the server fills it in.
```bash
curl -X PATCH "https://rxresu.me/api/openapi/resumes/YOUR_RESUME_ID" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"operations": [
{
"op": "add",
"path": "/sections/experience/items/0",
"value": {
"id": "019a0000-0000-7000-8000-000000000001",
"hidden": false,
"company": "Northwind Games",
"position": "Senior Gameplay Engineer",
"location": "Remote",
"period": "",
"dates": { "start": "2024-01", "end": null, "present": true },
"website": { "url": "", "label": "" },
"description": "<p>Leading the combat systems team.</p>",
"roles": []
}
}
]
}'
```
A numeric index inserts at that position (`0` puts the entry first). The special index `-` appends to the end, as in `/sections/skills/items/-`.
### Remove an entry
Remove the second skill:
```json
{ "operations": [{ "op": "remove", "path": "/sections/skills/items/1" }] }
```
### Move an entry within a section
Move the first experience entry to the third position:
```json
{ "operations": [{ "op": "move", "from": "/sections/experience/items/0", "path": "/sections/experience/items/2" }] }
```
### Change the design
Switch the template and the primary color:
```json
{
"operations": [
{ "op": "replace", "path": "/metadata/template", "value": "bronzor" },
{ "op": "replace", "path": "/metadata/design/colors/primary", "value": "rgba(37, 99, 235, 1)" }
]
}
```
### Hide a section
```json
{ "operations": [{ "op": "replace", "path": "/sections/interests/hidden", "value": true }] }
```
## Dates
Experience (and its roles), education, projects and volunteer entries, and awards, certifications and publications, have a structured `dates` object:
```json
"dates": { "start": "2022-03", "end": null, "present": true }
```
| Field | Value |
| --- | --- |
| `start` | A year (`"2022"`) or a year and month (`"2022-03"`), or `null`. Single-date entries (awards, certifications, publications) use only `start`. |
| `end` | A year or year and month, or `null` while the entry is ongoing or for single dates. |
| `present` | `true` when the entry is ongoing. It prints as "Present" in the resume's language. |
| `raw` | Optional. Original text that couldn't be read exactly, such as "Summer 2016". It prints as written until the dates are edited. |
**Write `dates`, not the text.** Each entry also has a text field, `period` (ranges) or `date` (single dates). On every save, the server rewrites that text from `dates`, in the resume's language and date format (`/metadata/page/dateFormat`: `short`, `long`, `numeric` or `iso`). A patch that changes only `period` or `date` is overwritten, and the resume keeps its old dates.
To change an entry's dates, replace the whole object:
```json
{
"operations": [
{
"op": "replace",
"path": "/sections/experience/items/0/dates",
"value": { "start": "2021", "end": "2024-06", "present": false }
}
]
}
```
With the `long` date format, that entry's `period` becomes "2021 – June 2024". An entry sent without `dates` (for example from an older export) gets them read from its text.
## Avoid overwriting other edits
Someone might edit the resume in the browser between your read and your write. Two tools protect you:
**`expectedUpdatedAt`** rejects the whole patch if the resume changed after you read it. Send the `updatedAt` value from your last read:
```json
{
"expectedUpdatedAt": "2026-09-30T00:10:08.197Z",
"operations": [{ "op": "replace", "path": "/basics/headline", "value": "Lead Game Developer" }]
}
```
If the resume has moved on, you get `409` with the code `RESUME_VERSION_CONFLICT` and the current `updatedAt` in `data`. Read the resume again, rebuild your operations and retry.
**`test`** checks a value before the other operations run. If it doesn't match, nothing is applied:
```json
{
"operations": [
{ "op": "test", "path": "/basics/name", "value": "David Kowalski" },
{ "op": "replace", "path": "/basics/name", "value": "Dave Kowalski" }
]
}
```
## What happens when a patch is applied
- **All or nothing.** The operations run in order inside one transaction. If any operation fails, or the result doesn't match the resume schema, none of them are saved.
- **Validation.** The patched resume must pass the same validation as any other save. For example, `/metadata/template` must be one of the available templates. Rich-text fields such as `description` and `/summary/content` are HTML strings, so send HTML (`<p>…</p>`) rather than plain text or Markdown.
- **History.** Each successful patch saves a version in the resume's history. It appears as **AI edit**, described as "from the assistant or API", and you can restore an earlier version from the editor. See [Undoing changes and version history](/guides/undoing-changes-and-version-history).
- **Cover letters leave the resume.** If a patch adds a section of type `cover-letter`, the server saves its letter as a separate cover letter linked to the resume and removes the section. Manage letters with the `/cover-letters` endpoints instead.
- **Public resumes update at once.** If the resume is public, the change is visible on its public page straight away.
## Errors
| Status | Code | Cause |
| --- | --- | --- |
| `400` | `BAD_REQUEST` | The body is malformed, for example `operations` is empty or an operation lacks `value` or `from`. |
| `400` | `INVALID_PATCH_OPERATIONS` | An operation targets a path that doesn't exist, a `test` failed, or the result doesn't match the schema. `data` holds the failing `index`, the `operation` and a `code` such as `TEST_OPERATION_FAILED` or `OPERATION_PATH_UNRESOLVABLE`. |
| `401` | `UNAUTHORIZED` | The API key is missing, revoked or expired. |
| `404` | `NOT_FOUND` | The resume doesn't exist or belongs to someone else. |
| `409` | `RESUME_VERSION_CONFLICT` | The resume changed after `expectedUpdatedAt`. |
| — | `RESUME_LOCKED` | The resume is locked. Unlock it with `POST /resumes/{id}/lock` and `{ "isLocked": false }`, or in the app. |
<Note>
A locked resume currently answers with HTTP status `500` rather than a `4xx` status. Check the `code` field for `RESUME_LOCKED` instead of relying on the status.
</Note>
## Related guides
- [Using the API](/guides/using-the-api): keys, authentication and the other endpoints.
- [JSON resume schema](/guides/json-resume-schema): every path and value type you can patch.
- [Using the MCP server](/guides/using-the-mcp-server): let an AI client write these patches for you.