Create document
| Method | Path |
|---|---|
POST | /document |
Authentication · Access policies · Files and documents
Creates a document and returns a signed form for uploading its file. Use it for every new file. The file does not pass through Ovok: you send it to file storage with the form this route returns.
Auth: Bearer token. Any signed-in user can call it, if the access policy allows Binary:create and DocumentReference:create.
Scope: The document is created in the caller's project (from the token). The caller's profile is recorded as the author.
Request
Body
| Name | Type | Required | Description |
|---|---|---|---|
fileName | string | Yes | Name of the file. Stored as the document title and used as the download name. At least 1 character. |
contentType | string | Yes | MIME type of the file. One of image/jpeg, image/jpg, image/png, image/gif, image/webp, application/pdf, application/json, application/xml, text/plain, text/csv, video/mp4, video/webm, audio/mpeg, audio/wav. Matched exactly, so text/plain; charset=utf-8 is rejected. |
isPublic | "true" | "false" | No | A string, not a JSON boolean. Default "false". "true" also gives the document a public token. |
Behaviour
- Creates an empty
Binaryfor the file, then aDocumentReferencewith statuscurrent,fileNameas the attachment title,contentTypeas the attachment type, and the caller's profile asauthor. The two are created one after the other, not in one transaction. If the second fails, an emptyBinarycan remain. - With
isPublicset to"true", a public token is added and returned aspublicToken. Anyone who has it can download the file withGET /document/public/:token. - The answer holds
uploadOptions: an uploadurland the formfields. Send amultipart/form-dataPOSTtouploadOptions.url. Add every entry ofuploadOptions.fieldsas a form field, exactly as returned, then add the file as the last part, namedfile. The set of fields can change, so do not hard-code it. - The form is valid for 10 minutes after it is issued and accepts files from 0 bytes up to 5 GB (5,368,709,120 bytes). File storage answers the upload, not Ovok. A
2xxanswer means the file is stored. If the form has expired, callPOST /document/:idto get a new one for the same document. - The form limits the size of the file only. It does not check that the file matches
contentType. - The document exists as soon as this call returns, even if you never upload the file. Delete it yourself if you abandon the upload.
- The route is rate limited per user, per client IP address, in a one-minute window. Admins can make 20 calls a minute. Practitioners, patients, related persons and client applications can make 10. Super admins are not limited on this route. Every call counts, including calls that fail validation.
Example
curl -X POST 'https://api.sandbox.ovok.com/document' \
-H "Authorization: Bearer ${OVOK_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{
"fileName": "cat.png",
"contentType": "image/png",
"isPublic": "false"
}'
Then upload the file with the returned form. Send every field from uploadOptions.fields, and file last:
curl -X POST 'https://storage.example.com/ovok-files' \
-F 'key=binary/5d2a9c64-7e1b-4830-b6f5-9a3c1e8d7b02/8c5e7a21-4b9d-4f36-a1c8-0d2e6b9f3a54' \
-F '<next field name>=<its value>' \
-F '<last field name>=<its value>' \
-F 'file=@cat.png;type=image/png'
Successful response
201 — The new document with its upload URL and form fields.
{
"id": "3f1c2b7e-8d4a-4c1e-9b2f-6a7d5e4c3b21",
"meta": { "lastUpdated": "2026-10-09T09:12:44.318Z" },
"author": {
"reference": "Practitioner/8c5e7a21-4b9d-4f36-a1c8-0d2e6b9f3a54",
"display": "Alex Lee"
},
"fileName": "cat.png",
"contentType": "image/png",
"uploadOptions": {
"url": "https://storage.example.com/ovok-files",
"fields": {
"key": "binary/5d2a9c64-7e1b-4830-b6f5-9a3c1e8d7b02/8c5e7a21-4b9d-4f36-a1c8-0d2e6b9f3a54",
"<next field name>": "<its value>",
"<last field name>": "<its value>"
}
}
}
| Field | Type | Description |
|---|---|---|
id | string (uuid) | Document id. Use it in the other routes. |
meta.lastUpdated | string | When the document last changed. ISO 8601. |
author | object | The caller's profile. Left out when the caller has none. |
author.reference | string | Profile reference, for example Practitioner/<id>. |
author.display | string | Display name of the caller. |
fileName | string | The file name you sent. |
contentType | string | The content type you sent. |
publicToken | string | Public token. Present only when isPublic was "true". |
uploadOptions.url | string | URL to send the upload form to. |
uploadOptions.fields | object | Form fields to send with the file. Each value is a string. Send every name and value unchanged. The names and the number of fields are not fixed, so the example shows placeholders for all but key. |
Errors
| Status | Meaning |
|---|---|
400 | The body fails validation: fileName is missing or empty, contentType is missing or not an allowed type, or isPublic is not the string "true" or "false". message lists each problem as path: message. |
401 | Bearer token is missing, invalid or revoked. |
403 | Your access policy does not allow creating the Binary or the DocumentReference. |
404 | The new file has no storage location. |
429 | You made more calls in the last minute than your user type allows. |