> ## Documentation Index
> Fetch the complete documentation index at: https://docs.paywise.de/llms.txt
> Use this file to discover all available pages before exploring further.

# Documents and communication

> Attach files to the right resource, follow document processing, and exchange messages and answers with paywise.

The Case Management API lets you attach evidence, send messages to paywise,
and answer questions raised during case processing. Each document belongs to
the resource it supports: a claim, rental agreement, enforceable title,
message, or request-to-client answer.

Claim documents use the stable claim path
`/v2/claims/{claim_id}/documents/`; review movement never changes that URL.

Your integration sends the file contents to paywise. A successful upload
creates the document and attaches it to its parent in one transaction;
malware scanning and page processing continue asynchronously.

## Uploading documents

Choose the format that fits the operation:

| Where you upload | Request format | Document fields |
| - | - | - |
| A parent's `/documents/` endpoint | `multipart/form-data` | `type`, one `file` part, and optional `filename` |
| A parent's `/documents/` endpoint | `application/json` | `type`, `base64`, and optional `filename` |
| Inline `documents[]` when creating a claim, rental agreement, title, message, or answer | `application/json` | Each entry contains `type`, `base64`, and optional `filename` |

Supply exactly one content source per document. Multipart files are accepted
only by the dedicated document endpoints; inline documents use base64.
Base64 content may be line-wrapped.

There is no upload-by-URL option: a `url` field returns `400` as an unknown
field. If your source system provides a download link, retrieve the file in
your integration and upload its bytes. Existing document IDs cannot be used
as upload input, and there is no standalone upload to attach later.

Use an `Idempotency-Key` for each create command. A dedicated document upload
returns `201` with the document resource and a `Location` header. Keep its
`id` so you can read its processing status. For request examples, see
[Manage documents](/api-docs/case-management-api/workflows/manage-documents).

### File validation and limits

| Limit | Accepted value |
| - | - |
| File formats | PDF, JPEG, PNG; detected from the bytes |
| File size | At most 10 MiB per file |
| PDF length | At most 100 pages; password-protected PDFs are rejected |
| Documents per command | At most 20, including documents nested in the same command |
| Combined inline content | At most 50 MiB of decoded file data per command |

The API validates content before creating the document. Invalid content
returns `400` on `file` or `base64`, or on `documents[i].base64` for an inline
attachment. Content errors include `unsupported`, `corrupt`, `encrypted`,
and `page_limit_exceeded`; invalid base64 and oversized files also fail
during upload. Correct the input before submitting a new command.

The split between synchronous and asynchronous checks is fixed: the byte
sniff (`unsupported`, `corrupt`), the PDF structure checks (`encrypted`,
`page_limit_exceeded`), size, and base64 decoding run synchronously and
answer `400` — no document is created. Only the malware scan and page
processing run asynchronously after the `201`, and they surface as the
document's `rejected` or `failed` status. The bytes are stored before the
response: if document storage is briefly unavailable, the upload — or the
command that carries inline `documents` — answers `503 service_unavailable`
with `Retry-After: 1`, creates nothing, and releases its `Idempotency-Key`;
retry the same command with the same key. A command carries at most 20
documents; the 21st is refused before any document is decoded.

A multipart upload sends each part once: a repeated `type`, `filename`,
`base64`, or `file` part is `400` on that part name with code
`duplicate_part`. A multipart body that ends before the file part is
complete reads as a missing `file` and is `400` on `file`.

The supplied filename and media type do not determine the file format.
paywise removes path components and control characters from `filename` and
adjusts its extension to match the detected content, so the returned name
can differ from the one you sent.

## Processing and downloads

An accepted upload starts as `pending`. Its `status` describes whether the
file is safe and available to use:

| Status | Meaning | What to do |
| - | - | - |
| `pending` | Malware scanning or page processing is still in progress; the bytes are already stored. | Poll the document list or detail with backoff. |
| `ready` | Scanning and page processing succeeded. | Download using `download_url`. |
| `rejected` | Malware scanning rejected the file. The stored bytes are dropped. | Remove the attachment and upload a safe replacement while its parent is editable. |
| `failed` | Scanning or processing failed (including a scanner that could not run). The stored bytes are dropped. | Read `failure_reason`, then replace the attachment while its parent is editable. |

`failure_reason` is populated only for `failed` documents. Its values are
`page_limit_exceeded`, `encrypted`, `corrupt`, `unsupported`, or
`processing_failed`; it is `null` for other statuses. Follow `status` and
`updated_at` through the document resources. Document processing does not
emit public webhooks.

`download_url` is `null` until the document is `ready`, and stays `null` for
`rejected` and `failed` documents because their bytes are no longer stored.
Once available, it points to an authenticated API download route: send your
Bearer credential just as you would for other reads. A download before
readiness, or of a `rejected`/`failed` document, returns `404`. The API
streams the file as an attachment with `nosniff` and no-store headers. Use
this route instead of constructing or saving a storage-provider URL.

Every download route — documents, mandate history attachments, request
attachments, and statement files — serves `Accept: */*`,
`application/octet-stream`, `application/pdf`, `image/*`, and
`application/json`; any other value such as `text/html` is
`406 not_acceptable`. An object that is missing in storage is
`404 not_found`; a storage fault is `503 service_unavailable` with
`Retry-After: 1`, so retry after the interval.

`DELETE` of an unknown claim, rental-agreement, or enforceable-title document
is a neutral `404`: the response does not reveal whether the document ever
existed under another parent.

### Replacing an attachment

Documents have no `PATCH` or ingestion retry operation. To replace a file,
delete it from its parent, then upload the replacement with a new idempotency
key. The replacement has its own document ID and processing status. Retrying
an upload whose HTTP response was lost is different: resend the same command
with the same key to recover its result.

The parent determines when documents can be added or deleted:

| Parent | Edit window |
| - | - |
| Claim, rental agreement, enforceable title | While the order is a draft. Finalization closes the upload and deletion window. |
| API-created message | While the message remains editable and staff review has not started. Check the message's `editable` field. |
| API-created request-to-client answer | While the answer's staff review task is still open. For order requests, the order must also remain eligible for review. |

Mutations outside these windows return `409`. Finalizing an order does not
wait for scanning; poll its evidence before finalization if you need to be
able to replace a file that fails processing. Reviewers can access the bytes
only after scanning and page processing succeed.

## Rental and title evidence

Use the document route for the resource the evidence describes:

| Parent | Accepted `type` values | Primary-file rule |
| - | - | - |
| Claim | `invoice`, `reminder`, `correspondence`, `bank_statement`, `payment_proof`, `claim_statement`, `other` | Supporting evidence for that claim. |
| Rental agreement | `rental_agreement`, `claim_statement`, `other` | One `rental_agreement`, one `claim_statement`, and multiple `other` files. |
| Enforceable title | `enforceable_title`, `other` | One `enforceable_title` and multiple `other` files. |

`rental_agreement` and `enforceable_title` are rejected with `invalid_choice`
on the generic claim document route. Creating a second file in an occupied
primary slot returns `409`; delete the old file before uploading its replacement.

Rental-agreement documents are optional at finalization. Keep each rental
month's statement on its claim; the receivable claim's subject-matter-or-document
readiness rule still applies. A titled claim requires its primary title
document at finalization, with status `pending` or `ready`.

## Messages

Send a message below `/v2/orders/{order_id}/messages/` or
`/v2/mandates/{mandate_id}/messages/` with `title`, `body`, and optional inline
`documents`. The `201` response contains the message resource, including its
`id`, `editable` flag, and attachments. Supported HTML in `body` is sanitized;
a `body` that is empty after sanitization is `400` on `body` with code
`blank`, on create and on `PATCH` alike. `body` follows the multi-line rule:
TAB, LF, and CR are accepted, other control characters are `400` with code
`control_characters`.

An API-created message belongs to the company's API principal, so rotating
the API key does not change ownership. While `editable` is `true`, you can
update its title or body and add or delete documents through the message's
document routes. Staff review closes that window; portal-authored messages
and paywise replies cannot be edited through the API. Withdrawn, rejected,
merged, and expired orders reject message changes with `409`
(`order_expired` for an expired draft). When messaging is disabled for a
mandate, creating or editing a message there and adding or deleting its
documents answer `409 conflict` (`Messages are disabled for this mandate.`).
Messages are written below an order or a main case: creating one below a
subcase answers `404` (`No mandate found for the given reference.`), while an
existing subcase thread stays readable.

Message creation acknowledges receipt while attachments are still processing.
paywise takes the message into case processing right away, as it does a
message written in the paywise portal: it hands the attachments over as they
are at that moment and leaves out files already `failed` or `rejected`.
Replace such a file while the message remains editable if the evidence still
needs to be sent. Downloads through the API still require `ready`.

Published paywise replies appear in the message collection; internal notes
do not. The `order.message.created` and `mandate.message.created` events
acknowledge client-authored messages received by paywise, so they are not
notifications of a paywise reply. Read the thread to retrieve replies.

## Requests to client

A request to client is a published question from paywise that needs an answer.
Read it below `/v2/orders/{order_id}/requests-to-client/` during order review,
or `/v2/mandates/{mandate_id}/requests-to-client/` for a mandate. Use the
parent identified by the request; order and mandate UUIDs are not interchangeable.

The request includes `allowed_answer_types`, `question_attachments`, and its
current `answer`. Download question attachments through their authenticated
download links. Submit the answer once at the request's `/answer/` endpoint;
the `200` response is the updated request. A second answer with a different
idempotency key returns `409`. Sending an ordinary message does not answer
the request.

Build the payload for the advertised answer type:

| `allowed_answer_types` | Answer requirements |
| - | - |
| `yes-no` | `text`: `yes` or `no`. |
| `yes-no-dontknow` | `text`: `yes`, `no`, or `dontknow`. |
| `yes-no-freetext-on-no` | `text`: `yes` or `no`; `additional_comment` is required for `no`. |
| `yes-with-date-no-freetext-on-no` | `yes` requires `booking_date`; `no` requires `additional_comment` and forbids `booking_date`. |
| `freetext` | Non-empty `text`. |
| `fileupload` | Non-empty `text`, at least one inline document, or both. |

`booking_date` is forbidden for all other answer types. Inline `documents`
are accepted only on `fileupload`, `freetext`, `yes-no-freetext-on-no`, and
`yes-with-date-no-freetext-on-no` answers; on any other type they are `400`
on `documents` with code `not_allowed`. They use the same base64 format and
limits as other uploads. After answering, files can be added or deleted
through `/answer/documents/` while the answer remains editable.

`text` on the free-text types and `additional_comment` are plain text: markup
is removed and HTML entities are decoded before validation. A value that is
empty after stripping is `400` with code `blank`; markup that does not
converge to plain text is `400` with code `invalid`. Both fields follow the
multi-line rule (TAB, LF, and CR accepted; other control characters are
`control_characters`).

For **order requests**, answering creates a staff review task. Once all
published requests on the order are answered, claims waiting for a client
response return to review. This does not wait for attachment processing.
Closed orders reject new answers and answer-document changes with `409`.

For **mandate requests**, staff notification is scheduled immediately, while
downstream answer processing waits for all attached documents to be `ready`.
Any `failed` or `rejected` attachment blocks that processing. Delete it and
upload a corrected replacement while the review task is open. Files added
after the initial answer are subject to the same processing rule.

See [Messages and client requests](/api-docs/case-management-api/workflows/messages-and-client-requests)
for request examples. To follow the case as a whole, use
[mandate history](/api-docs/case-management-api/concepts/mandates): published
history entries can link messages, requests, emails, or single-mandate
statements in `related_resources`. An underlying record alone does not
create a history entry.

## Related reference

* [POST `/v2/claims/{claim_id}/documents/`](/api-docs/case-management-api/reference/documents/create-claim-document)
* [POST `/v2/orders/{order_id}/rental-agreement/documents/`](/api-docs/case-management-api/reference/orders/create-rental-agreement-document)
* [POST `/v2/claims/{claim_id}/enforceable-title/documents/`](/api-docs/case-management-api/reference/claims/create-enforceable-title-document)
* [POST `/v2/orders/{order_id}/messages/`](/api-docs/case-management-api/reference/orders/create-order-message)
* [POST `/v2/mandates/{mandate_id}/requests-to-client/{id}/answer/`](/api-docs/case-management-api/reference/mandates/answer-mandate-request-to-client)
* [POST `/v2/orders/{order_id}/requests-to-client/{id}/answer/`](/api-docs/case-management-api/reference/orders/answer-order-request-to-client)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.