<!-- Carebit docs: File uploads and imports -->

# File uploads and imports

The `/v1/remote_file_import_batches/:id` endpoint returns the status of a
batch of files that Carebit is validating and attaching on your behalf.

You can provide a file in either of these ways:

- Inline Base64 bytes. Use this when the file is not available at a public URL.
- A public HTTPS URL. Carebit downloads the file without authentication.

Both sources use the same asynchronous validation, malware scanning, and
polling workflow.

## Upload Base64 bytes

Developer Platform request bodies are JSON, so encode raw file bytes as
Base64. Do not include a `data:` URI prefix. The decoded file can be at most
7 MB, and `filename` is required so Carebit can validate the file extension.

Letters and TestResults accept `file_base64` at the top level:

```json
{
  "patient_id": "00000000-0000-4000-8000-000000000001",
  "title": "Referral letter",
  "status": "complete",
  "file_base64": "JVBERi0xLjQKJ...",
  "filename": "referral-letter.pdf",
  "automatically_create_resource_permission_for_patient": true,
  "notify_patient_of_resource_permission": false
}
```

Lead and Note attachments accept `file_base64` inside each attachment:

```json
{
  "subject_type": "patient",
  "subject_id": "00000000-0000-4000-8000-000000000001",
  "content": "<p>Referral attached.</p>",
  "attachments": [
    {
      "file_base64": "JVBERi0xLjQKJ...",
      "filename": "referral-letter.pdf"
    }
  ]
}
```

For example, callers can encode a local file with:

<!-- code-tabs -->

### cURL

```bash
file_base64=$(base64 < referral-letter.pdf | tr -d '\n')
```

### JavaScript

```javascript
import { readFile } from "node:fs/promises";

const fileBase64 = (await readFile("referral-letter.pdf")).toString("base64");
```

### Python

```python
import base64
from pathlib import Path

file_base64 = base64.b64encode(Path("referral-letter.pdf").read_bytes()).decode()
```

### Ruby

```ruby
require "base64"

file_base64 = Base64.strict_encode64(File.binread("referral-letter.pdf"))
```

### PHP

```php
$fileBase64 = base64_encode(file_get_contents("referral-letter.pdf"));
```

<!-- /code-tabs -->

Never send both `file_base64` and the corresponding URL field for the same
file.

## Import from a URL

Use `file_url` for a Letter or TestResult, or `url` inside a Lead or Note
attachment:

```json
{
  "url": "https://files.example.com/referral-letter.pdf",
  "filename": "referral-letter.pdf"
}
```

The URL must use HTTPS, port 443, and be publicly reachable without
authentication. Redirects are not followed. URL imports can be up to 50 MB.

## Lifecycle

A batch progresses through these statuses:

- `pending` - the batch was created and Carebit has not started processing yet.
- `processing` - at least one file is being loaded, validated, or malware
  scanned.
- `completed` - every item reached a terminal state. Individual items can
  still have failed.

Each file in the batch has its own `status` and, on failure, a stable
`error.code` that identifies the reason. A successful item includes its
created Letter, Note, or TestResult. Pending and failed items do not
expose a created resource.

Every file passes through malware scanning before its item succeeds
or its download URL becomes available. A file that does not pass scanning
fails with `malware_scan_rejected`.

## Polling

Poll `GET /v1/remote_file_import_batches/:id` at a modest interval (for
example every 5 seconds) until the batch reaches `completed`.
Batches expire from active polling storage after they finish. The
canonical outcome is available on the resource the files were attached
to: a Letter, Note, or TestResult.

## Idempotency

The endpoint that creates a batch requires an `Idempotency-Key` the same
way every other create does. See [Idempotency and retries](/guides/idempotency-and-retries).
