> 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.

# Files

`/v1/files` is the reusable document corpus behind the [capability endpoints](/paperwork/capabilities/extract). Register a file once. Every later run then takes `{"file": {"id": "…"}}`. The platform does not fetch the document again and does not parse it again.

## Files you register vs files a run creates

Both kinds are files, and an id addresses both. But they follow different rules:

|            | Registered with `POST /v1/files`                 | Created inline by a run                                     |
| ---------- | ------------------------------------------------ | ----------------------------------------------------------- |
| Created by | You                                              | `{"file": {"url": …}}` on a verb, or a run's output         |
| Lifetime   | **Persistent** — until you `DELETE` it           | Expires with the run's `ttl` (default 24 hours, max 7 days) |
| Reuse      | Across any number of runs                        | Only while the run that created it lives                    |
| Best for   | Documents you will run several capabilities over | One-shot processing                                         |

A run that creates a file inline still returns its id. The parse is reusable inside that run's TTL. If you plan to keep working with the document, register it first. Use [`keep`](/paperwork/developers/runs#keep-a-run) to extend the lifetime of a run's files after the fact.

## Register by URL

This is the production-default path. The platform fetches the bytes server-side over http(s).

```bash
curl -X POST https://api.cloudraker.com/v1/files \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://www.irs.gov/pub/irs-pdf/fw9.pdf",
    "name": "w9.pdf",
    "processing": "auto"
  }'
```

```json
{
  "object": "file",
  "id": "a04d6597-4e34-4a99-94ea-964c289a4c68",
  "name": "w9.pdf",
  "mimeType": "application/pdf",
  "status": "uploading",
  "createdAt": "2026-07-25T18:00:39.453Z"
}
```

With a `url`, the platform sniffs the MIME type from the response. It drops any `mimeType` you send with the `url`. Send `url` **or** `name` + `mimeType`, not both.

**Sources must serve a `Content-Length`.** The fetch streams directly into storage. An origin that answers with chunked transfer encoding, or with compressed content and no usable length, fails with `502 file_upload_failed`. Static file hosts work. HTML pages and gzip-encoded endpoints often do not. Upload those with a presigned PUT instead.

## Presigned upload

Use this for local files, large files, and files not reachable by URL. No multipart. Pure JSON.

#### Reserve the record

```bash
curl -X POST https://api.cloudraker.com/v1/files \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "recording.mp3", "mimeType": "audio/mpeg", "processing": "transcribe_diarize" }'
```

The response carries `uploadUrl` and `uploadExpiresAt`. The URL is valid for **15 minutes**.

#### PUT the bytes

```bash
curl -X PUT "<uploadUrl>" \
  -H "Content-Type: audio/mpeg" \
  --data-binary @./recording.mp3
```

The `Content-Type` header must equal the `mimeType` you registered **exactly**. Storage signs it into the URL and rejects a mismatch. This is the most common upload failure.

#### Poll until ready

`GET /v1/files/:id` until `status` is `ready`. Then read `urls`.

## Read a file

```bash
curl https://api.cloudraker.com/v1/files/a04d6597-4e34-4a99-94ea-964c289a4c68 \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY"
```

```json
{
  "object": "file",
  "id": "a04d6597-4e34-4a99-94ea-964c289a4c68",
  "name": "w9.pdf",
  "mimeType": "application/pdf",
  "status": "ready",
  "createdAt": "2026-07-25T18:00:39.453Z",
  "urls": {
    "content": "https://cdn.cloudraker.com/…/latest?token=…&fn=w9.pdf",
    "markdown": "https://cdn.cloudraker.com/…/processed.md?token=…&fn=w9.pdf",
    "json": "https://cdn.cloudraker.com/…/processed.json?token=…&fn=w9.pdf"
  }
}
```

| `status`     | Meaning                                    |
| ------------ | ------------------------------------------ |
| `uploading`  | Registered. The bytes have not landed yet. |
| `processing` | Bytes stored. The platform reads them.     |
| `ready`      | Done. `urls` is present.                   |
| `failed`     | See `error`.                               |

`urls.content` is the original bytes. `urls.markdown` and `urls.json` are the parse byproducts. They appear only after the document was parsed. All three URLs are signed and expire after about 1 hour. Fetch the content. Do not store the URL.

## Audio transcripts

Audio and video produce no markdown byproduct. `urls.markdown` stays absent for them. The transcript is `urls.json`.

Fetch that URL to read the transcript. The body is one object with a detected `language` and an ordered `segments` array.

```json
{
  "language": "en",
  "segments": [
    {
      "start": 0.53,
      "end": 4.12,
      "text": "Good morning, thanks for calling the clinic.",
      "speaker": "SPEAKER_00",
      "words": [
        { "word": "Good", "start": 0.53, "end": 0.71, "score": 0.94, "speaker": "SPEAKER_00" },
        { "word": "morning,", "start": 0.78, "end": 1.14, "score": 0.91, "speaker": "SPEAKER_00" }
      ]
    },
    {
      "start": 4.60,
      "end": 7.02,
      "text": "Hi, I would like to book a follow-up.",
      "speaker": "SPEAKER_01",
      "words": [
        { "word": "Hi,", "start": 4.60, "end": 4.79, "score": 0.88, "speaker": "SPEAKER_01" }
      ]
    }
  ]
}
```

| Field                | What it is                                                                                                                              |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `language`           | The detected language code, such as `en`.                                                                                               |
| `segments[]`         | The transcript in playback order. One entry per continuous run of speech.                                                               |
| `segments[].start`   | Seconds from the start of the recording. Seek here to play the segment.                                                                 |
| `segments[].end`     | Seconds at which the segment stops.                                                                                                     |
| `segments[].text`    | What the speaker said in that segment.                                                                                                  |
| `segments[].speaker` | The speaker label, such as `SPEAKER_00`. Present only with `transcribe_diarize`.                                                        |
| `segments[].words[]` | Word-level timings. Each word carries `word`, `start`, `end`, and an alignment `score`. Diarization also stamps `speaker` on each word. |

Join every `segments[].text` in order to rebuild the transcript as plain text.

`transcribe` and `transcribe_diarize` both return word-level timings. Only `transcribe_diarize` adds `speaker`. Choose `transcribe` when speaker labels do not matter.

Speaker labels are positional, not identities. `SPEAKER_00` is the first voice the platform separated. The same person can get a different label in another recording.

A word the aligner cannot place comes back without `start` and `end`. This is rare. Fall back to the segment timing for those words.

### Where the transcript arrives, per surface

The transcript is the same object everywhere. Only the delivery differs.

| Surface                                                                                                                        | How you get the transcript                                |
| ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- |
| `GET /v1/files/:id`                                                                                                            | Fetch `urls.json` yourself.                               |
| [`GET /process/:id`](/paperwork/developers/process-api#poll-for-status-and-results) with `include=results,content&format=json` | The API inlines it in `files[].content`. No second fetch. |
| [`POST /v1/parse`](/paperwork/capabilities/parse)                                                                              | Fetch `output.jsonUrl`.                                   |
| [`POST /v1/extract`](/paperwork/capabilities/extract) and the other capability verbs                                           | Not inlined. Read the file, then fetch its `urls.json`.   |

On `/process`, `format=markdown` returns `null` for audio content. Audio has no markdown byproduct. Always ask for `format=json` on a recording.

## List and delete

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

curl -X DELETE https://api.cloudraker.com/v1/files/a04d6597-4e34-4a99-94ea-964c289a4c68 \
  -H "Authorization: Bearer $CLOUDRAKER_API_KEY"
```

`?limit` caps the page (1–200, default 50), newest first. There is no cursor today. Paging is by `limit` only. `DELETE` returns `204` and removes the parse byproducts with the file. Runs that already used the file keep their results.

## Processing

`processing` selects how the platform reads the document. It applies when you register the file, and again in `file.processing` on any capability call.

| Value                | Use for                                                                   |
| -------------------- | ------------------------------------------------------------------------- |
| `auto`               | Default for documents. Selects per document and upgrades to OCR on scans. |
| `simple`             | Born-digital PDFs with a real text layer. Fastest.                        |
| `ocr`                | Scans and photographed pages.                                             |
| `transcribe`         | Audio where speaker separation does not matter.                           |
| `transcribe_diarize` | Default for audio and video. Separates speakers.                          |

Parsing is automatic. A capability parses what is not parsed and never re-parses what is. A [parse](/paperwork/capabilities/parse) call first is optional, not a prerequisite.

## Reuse a file

```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-4e34-4a99-94ea-964c289a4c68" },
    "schema": { "type": "object", "properties": { "business_name": { "type": ["string", "null"] } } }
  }'
```

Parse once, run many. Several narrow extractions, a redaction, and a fill can all read the same file id. None re-reads the document. Send up to 100 file refs in one run with `files: [...]`.

## Next steps

#### [Templates](/capabilities/templates)

The other resource: blank forms your organization fills repeatedly.

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

Statuses, outputs, TTL, and how to keep a result in the product.

#### [Files in spaces](/developers/files-and-uploads)

The product-side file surface, scoped to a space and indexed for search.

#### [Parse](/capabilities/parse)

Get Markdown and structured JSON out of any document.