> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.cloudraker.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.cloudraker.com/_mcp/server.

# Saved configs

Every capability takes its configuration inline. A **saved config** stores that same configuration under a name and a slug. A call then becomes `{"file": …, "action": "medical-intake"}`. Both paths drive the same engine. Inline config is the fastest way to start. Saved configs keep a team's configuration consistent over time.

Each capability owns its own config library:

| Library | Routes                |
| ------- | --------------------- |
| Extract | `/v1/extract/configs` |
| Redact  | `/v1/redact/configs`  |
| Fill    | `/v1/fill/configs`    |
| Compose | `/v1/compose/configs` |

These libraries replace the flat `/v1/actions` surface. That surface stays as a **deprecated alias** and keeps working. Both paths address the same stored objects. New integrations must use the per-capability routes. A config lives next to the verb that consumes it. A config from another capability answers `404` there.

[Parse](/paperwork/capabilities/parse) has nothing to configure. You compose a [pipeline](/paperwork/capabilities/pipeline) per call. Neither has a library. **Sign** also has no library. See the note at the end.

A [compose](/paperwork/capabilities/compose) config is different. It is not an alternative to inline fields. It is the template itself. Its `config` carries the data schema, the bundle files, and the entry point. `POST /v1/compose` takes no inline template. It also has bundle routes of its own. See [Compose](/paperwork/capabilities/compose).

## Save a config

```bash
curl -X POST https://api.cloudraker.com/v1/extract/configs \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Medical intake",
    "config": {
      "schema": {
        "type": "object",
        "properties": {
          "patient_name": { "type": ["string", "null"] },
          "visit_date": { "type": ["string", "null"] }
        }
      },
      "instructions": "Dates are DD/MM/YYYY.",
      "unit": "per_document"
    }
  }'
```

```json
{
  "object": "config",
  "id": "21f122a6-9f8b-4f2c-8a0f-6f3e1c9b2d44",
  "slug": "medical-intake",
  "name": "Medical intake",
  "capability": "extract",
  "config": { }
}
```

| Field      | What it is                                                                                                                                                                                                                                                                                                                             |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`     | **Required.** ≤ 200 characters. The API derives the slug from it. The slug is unique in your organization.                                                                                                                                                                                                                             |
| `config`   | The saved configuration. It holds the same fields the verb takes inline. An extract `config.schema` must satisfy the [schema dialect](/paperwork/capabilities/extract/schema). A fill `config` is validated strictly against the [fill vocabulary](/paperwork/capabilities/fill#configure-a-form-once) — an unknown key answers `400`. |
| `mimeType` | **`/v1/redact/configs` only.** Selects the variant: document or audio. The other libraries reject it as an unknown field with `400`.                                                                                                                                                                                                   |

`GET /v1/actions/catalog` describes the configurable shapes. It lists every capability, the slugs behind it, and the JSON Schema of each slug's `config`.

```bash
curl https://api.cloudraker.com/v1/actions/catalog \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY"
```

## Reference it

The **id and the slug are interchangeable** everywhere a call references a config. `action: "medical-intake"` and `action: "21f122a6-…"` do the same thing. Ids are opaque strings. Do not parse them.

```bash
curl -X POST https://api.cloudraker.com/v1/extract \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "file": { "id": "a04d6597-…" }, "action": "medical-intake" }'
```

The API **deep-merges** inline fields sent with `action` over the saved configuration. The inline fields win. A one-off change does not require a second config:

```json
{ "file": { "id": "a04d6597-…" }, "action": "medical-intake", "instructions": "This batch is in French." }
```

In a [pipeline](/paperwork/capabilities/pipeline), you can use a saved config two ways. A typed step with overrides: `{"extract": {"action": "medical-intake"}}`. Or a bare `{"action": "medical-intake"}` step, which runs it as-is.

Saved configs give you:

* **Reuse.** One schema or redaction policy serves every call, every pipeline step, and the product UI.
* **Governance.** You change the configuration in one place, not in every caller's source.
* **Record binding.** An extract config bound to a data object (`objectDefinitionId`) can import its results as records when you [keep](/paperwork/developers/runs#keep-a-run) the run.
* **Stable config under `keep`.** The run snapshots the configuration it ran with. A kept result stays explainable after the config changes.

## List, read, update, delete

```bash
curl "https://api.cloudraker.com/v1/extract/configs?limit=50" \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY"

curl https://api.cloudraker.com/v1/extract/configs/medical-intake \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY"

curl -X PATCH https://api.cloudraker.com/v1/extract/configs/medical-intake \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Medical intake v2" }'

curl -X DELETE https://api.cloudraker.com/v1/extract/configs/medical-intake \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY"
```

`PATCH` takes `name`, `config`, or both. Send at least one. A `config` you send **deep-merges** over the stored one: objects merge recursively, arrays and scalars replace. Patching one key never erases its siblings.

Page listings with `?limit` (1–100) and `?starting_after=<id>`. Keep paging while **`has_more`** is `true`. A page can hold fewer rows than `limit`, so the row count does not signal the end of the list.

Deleting a config does not affect runs that already used it. Each run snapshotted the configuration it ran with.

**Sign has no config library.** `POST /v1/actions` still accepts `"capability": "sign"`, but no `/v1` request path takes a reference to one. You configure [`POST /v1/sign`](/paperwork/capabilities/sign) and `{"sign": …}` pipeline steps inline only. If you pass a sign action as another verb's `action`, or as a bare `{"action": …}` step, the API returns `400 invalid_request`. Only the sign path keeps the run exempt from the TTL purge while an envelope is open.

## Next steps

#### [Extraction schema dialect](/capabilities/extract/schema)

The rules a saved extract `config.schema` must satisfy.

#### [Pipelines](/capabilities/pipeline)

Compose saved configs and inline steps over one file set.

#### [Runs](/developers/runs)

Keep a result in the product. Record binding applies there.

#### [Actions in the app](/actions/overview)

The same configurations, managed from the CloudRaker interface.