file or JSON base64, with an optional filename.
Remote document URLs are not accepted. Uploading again replaces the current
document, and is allowed only while the invoice is held. After release,
uploads return 409 already_released; a settled, archived, or
collection-transferred invoice answers 409 invoice_paid,
invoice_cancelled, invoice_written_off, invoice_archived, or
invoice_in_inkasso, a bookkeeping invoice 409 not_api_invoice — see the
precedence table.
The bytes are inspected synchronously before anything is stored. A file that
is not a PDF is 400 unsupported, a truncated PDF without its %%EOF marker
400 corrupt, a password-protected PDF 400 encrypted, and a PDF above 100
pages 400 page_limit_exceeded — the same codes the Case Management API
uses, reported on file or base64. A PDF whose markers are intact but
whose body cannot be parsed is accepted at upload, exactly as on the Case
Management API, and processed asynchronously like any other PDF. filename
(JSON) and the multipart file name are percent-decoded once and then
validated as a single line: control characters are 400 control_characters
on filename or file, invisible format characters are stripped, only the
base name is kept, and a name that decodes to empty, ., or .. is
400 invalid (Provide a valid file name.); omit filename to fall back
to document.pdf. If the document store refuses the write, the upload is
503 service_unavailable with Retry-After; nothing is stored and a
previous document stays in place.
Upload and keep the document id
cURL
201 Created returns the document, with its own id. The Location
response header points to its detail endpoint. Scanning runs asynchronously;
an accepted upload is not yet ready to enclose with a dunning notice.
Pending document
Wait for a terminal scanning result
PollGET /mahnservice/v1/invoices/{uuid}/documents/{document_uuid}/ using
the invoice id and the returned document id. You can also read
GET /mahnservice/v1/invoices/{uuid}/documents/: it returns an unpaginated
array containing zero or one document.
size and download_url are null until the document is ready and stay
null on a rejected or failed document — its bytes are discarded. On the
invoice, has_document becomes true only when the current document is
ready; document contains its id, status and download URL. A replacement
starts scanning again, so wait for the replacement’s result too. A document
whose scan completes after the invoice was paid, cancelled, written off, or
archived lands on rejected rather than ready: a settled invoice never
gains a document. The invoice’s updated marker advances when the document
reaches ready, rejected, or failed, not on internal scan retries.
There is no document retry endpoint. To replace a rejected or failed upload,
send the PDF bytes again to the same documents collection. Do not repost a
pending upload merely because a poll has not finished yet.
Release and download
An invoice can be released without an attachment. If you have uploaded a document, it must be ready before release:pending, rejected and
failed all cause 409 document_not_ready. A polling deadline expiring means
your integration should stop and check again later; it does not mean the scan
failed.
When ready, download_url names the authenticated download endpoint
GET /mahnservice/v1/invoices/{uuid}/documents/{document_uuid}/download/.
Send your Bearer credential when following it. Downloading before readiness
returns 404; an object missing from storage is 404 as well, and a storage
fault is 503 service_unavailable with Retry-After — retry the download.
HEAD on the documents collection mirrors GET and never uploads.
The quickstart’s complete Python workflow
uploads a local PDF and polls with a bounded wait before releasing.
