Upload a document
Files never go through the Public API itself: you ask for a presigned POST, send the file straight to object storage, then reference the upload by its id.
All Public API calls below need an office-scope token: see Public API authentication.
1. Request an upload
Section titled “1. Request an upload”Call FileObjectService.Create with an empty body (REST: POST /services.file_object.v1.FileObjectService/Create).
{ "upload": { "id": "019512f0-0000-7000-8000-000000000001", "url": "https://…", "fields": { "key": "…", "bucket": "…", "Policy": "…", "X-Amz-Algorithm": "AWS4-HMAC-SHA256", "X-Amz-Credential": "…", "X-Amz-Date": "…", "X-Amz-Signature": "…" }, "maxSizeInBytes": 52428800 }}| Field | Description |
|---|---|
id | The upload id, to reference the file later. |
url | Where to send the multipart/form-data POST. |
fields | Form fields to send unchanged. Treat them as opaque: their names may change. |
maxSizeInBytes | Largest file the upload accepts (50 MiB). |
2. Send the file
Section titled “2. Send the file”Send one multipart/form-data POST to url: every entry of fields first, unchanged, then the file as the last part, named file.
const form = new FormData();
for (const [name, value] of Object.entries(upload.fields)) { form.append(name, value);}
form.append('file', new Blob([pdfBytes], { type: 'application/pdf' }), 'minutes.pdf');
const response = await fetch(upload.url, { method: 'POST', body: form });
if (!response.ok) { throw new Error(`Upload failed: ${response.status} ${await response.text()}`);}Constraints:
- Size: from 1 byte to
maxSizeInBytes(50 MiB). Storage rejects anything else (EntityTooSmall/EntityTooLarge). - Validity: the presigned POST expires 5 minutes after it was issued. Request a new one if needed.
- Retention: an upload that is not attached is deleted after 24 hours.
- Format: PDF only — checked when you attach it (step 3).
- From your server: storage refuses cross-origin uploads from third-party web pages, so send the file from your backend.
3. Attach it to a register
Section titled “3. Attach it to a register”Call RegisterService.AddMeetingToRegister (REST: POST /services.register.v1.RegisterService/AddMeetingToRegister):
{ "registerKey": "…", "label": "Annual general meeting 2026", "date": "2026-06-30", "documents": [ { "name": "Minutes", "type": "REGISTER_ITEM_MINUTES", "uploadId": "019512f0-0000-7000-8000-000000000001" }, { "name": "Attendance sheet", "type": "REGISTER_ITEM_ANNEXE", "uploadId": "019512f0-0000-7000-8000-000000000002" } ]}date is optional. documents needs at least one entry, and type is REGISTER_ITEM_MINUTES or REGISTER_ITEM_ANNEXE.
Before attaching, the server checks each upload:
| Status | Message | Cause |
|---|---|---|
| 400 | Uploaded files not found: … | The file was never sent, has expired, or the id belongs to another Public API user. |
| 400 | Uploaded files must be PDF documents: … | The content is not a PDF (the file’s bytes are inspected, not its name or declared type). |
An uploadId is only usable by the Public API user that created it.