PDFs
PDFs are file-based widgets that display PDF documents on a Canvus canvas. Each PDF widget shows a single page at a time, controlled by the index property. Use PDFs for reference documents, reports, presentations, or any paginated content you want to share on the canvas.
PDF files are uploaded via multipart form data and can be downloaded through a dedicated endpoint. Changing the widget's size triggers a re-render of the PDF page at the new resolution, so the content always displays at full fidelity.
Authentication
All endpoints require authentication via the Private-Token header or a CanvusSession cookie, unless the canvas has link sharing enabled (View or Edit permission). Write operations (POST, PATCH, DELETE) require edit access. View-only users receive 403 Forbidden on any write attempt.
Common widget properties
Every PDF widget shares these properties with all other canvas widget types.
id-- string (uuid, read-only). Unique identifier assigned by the server on creation.widget_type-- string (read-only). Always"Pdf"for this endpoint.location-- object (patchable). Position relative to the parent widget, withxandyfloat fields.size-- object (patchable). Dimensions in canvas units, withwidthandheightfloat fields. Changing the size triggers a re-render of the PDF at the new resolution.depth-- float (patchable). Z-order among sibling widgets. Higher values render on top. Must be >= 1.0 -- the server returns 400 Bad Request if you set depth below 1.0.scale-- float (patchable). Uniform scale factor applied to the widget. Default:1.pinned-- boolean (patchable). Whentrue, the widget cannot be moved or resized through touch interaction. API changes still apply. Default:false.state-- string (read-only). Widget state, typically"normal".parent_id-- string (uuid, patchable). ID of the parent widget. Changing this reparents the widget. Note thatlocationcoordinates are always relative to the parent -- changingparent_idwithout updatinglocationwill reinterpret the same x/y values in the new parent's coordinate space.auto_raise-- boolean (patchable, PATCH only). Whentrue, the server sets the widget's depth to the highest sibling depth + 1.0, bringing it to the front. Not persisted -- this is a one-shot parameter. Default:false.
PDF-specific properties
title-- string (patchable). Display title for the PDF widget. Default:"".original_filename-- string (patchable). The original filename of the uploaded PDF file. Default:"".hash-- string (read-only). Server-generated content hash of the PDF file. Empty string immediately after creation while the file is being processed.index-- integer (patchable). Zero-based page index of the currently displayed page.0is the first page. Must be >= 0 -- the server returns 400 Bad Request if you set a negative value. Default:0.
Streaming
All GET endpoints support real-time updates via the ?subscribe query parameter. When present, the server holds the connection open and sends newline-delimited JSON whenever the resource changes. The server sends periodic keepalive pings to maintain the connection.
List PDFs
Retrieves all PDF widgets on a canvas.
GET /api/v1/canvases/:canvas_id/pdfs
Path parameters:
canvas_id(uuid, required) -- ID of the canvas
Query parameters:
subscribe(flag, optional) -- Enable streaming updates. The parameter takes no value; its presence alone turns streaming on, so?subscribe=falsealso streams.
Example request:
curl -H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs
Example response:
[
{
"depth": 2.0,
"hash": "347b3c308971",
"id": "d2c53c80-fc5f-4e10-9c8b-28f4a7f06232",
"index": 0,
"location": {
"x": 4629.51,
"y": 2105.47
},
"original_filename": "quarterly-report.pdf",
"parent_id": "0aad755b-c78f-4392-88fb-6efb31d35290",
"pinned": false,
"scale": 1,
"size": {
"height": 842,
"width": 595
},
"state": "normal",
"title": "Q3 Report",
"widget_type": "Pdf"
}
]
Get single PDF
Retrieves a single PDF widget by ID.
GET /api/v1/canvases/:canvas_id/pdfs/:pdf_id
Path parameters:
canvas_id(uuid, required) -- ID of the canvaspdf_id(uuid, required) -- ID of the PDF
Query parameters:
subscribe(flag, optional) -- Enable streaming updates. The parameter takes no value; its presence alone turns streaming on, so?subscribe=falsealso streams.
Example request:
curl -H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs/d2c53c80-fc5f-4e10-9c8b-28f4a7f06232
Example response:
{
"depth": 2.0,
"hash": "347b3c308971",
"id": "d2c53c80-fc5f-4e10-9c8b-28f4a7f06232",
"index": 0,
"location": {
"x": 4629.51,
"y": 2105.47
},
"original_filename": "quarterly-report.pdf",
"parent_id": "0aad755b-c78f-4392-88fb-6efb31d35290",
"pinned": false,
"scale": 1,
"size": {
"height": 842,
"width": 595
},
"state": "normal",
"title": "Q3 Report",
"widget_type": "Pdf"
}
Create PDF
Creates a new PDF widget by uploading a file. The request must be multipart/form-data with a mandatory data part (the PDF file) and an optional json part (widget metadata).
POST /api/v1/canvases/:canvas_id/pdfs
Path parameters:
canvas_id(uuid, required) -- ID of the canvas
Multipart form parts:
data(file, required) -- The PDF file to uploadjson(string, optional) -- JSON string with widget properties
JSON properties (all optional):
title-- stringoriginal_filename-- stringindex-- integer (must be >= 0)location-- object withxandyfloatssize-- object withwidthandheightfloatsdepth-- float (must be >= 1.0)scale-- floatpinned-- booleanparent_id-- string (uuid)
Example request:
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
-F 'json={"title": "Q3 Report", "index": 0}' \
-F 'data=@quarterly-report.pdf' \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs
Example request -- upload with no metadata:
curl -X POST \
-H "Private-Token: YOUR_TOKEN" \
-F 'data=@handbook.pdf' \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs
Example response:
{
"depth": 1.0,
"hash": "",
"id": "7456c122-cb58-4493-b66e-2efb706e213a",
"index": 0,
"location": {
"x": 3624.75,
"y": 2387.44
},
"original_filename": "quarterly-report.pdf",
"parent_id": "0aad755b-c78f-4392-88fb-6efb31d35290",
"pinned": false,
"scale": 1,
"size": {
"height": 842,
"width": 595
},
"state": "normal",
"title": "Q3 Report",
"widget_type": "Pdf"
}
The hash field is empty immediately after creation. It will be populated once the server finishes processing the file.
Update PDF
Updates one or more properties of an existing PDF widget. Only the fields included in the request body are changed -- all other properties remain untouched.
PATCH /api/v1/canvases/:canvas_id/pdfs/:pdf_id
Path parameters:
canvas_id(uuid, required) -- ID of the canvaspdf_id(uuid, required) -- ID of the PDF to update
Request body (JSON):
Any combination of patchable properties: title, original_filename, index, location, size, depth, scale, pinned, parent_id, auto_raise.
Example request -- navigate to page 3:
curl -X PATCH \
-H "Private-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"index": 2}' \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs/d2c53c80-fc5f-4e10-9c8b-28f4a7f06232
Example request -- resize:
curl -X PATCH \
-H "Private-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"size": {"width": 1190, "height": 1684}}' \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs/d2c53c80-fc5f-4e10-9c8b-28f4a7f06232
The server stores the requested size as given. Unlike images and videos, PDF widgets do not have their aspect ratio enforced.
Example request -- move and bring to front:
curl -X PATCH \
-H "Private-Token: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"location": {"x": 3000, "y": 1500}, "auto_raise": true}' \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs/d2c53c80-fc5f-4e10-9c8b-28f4a7f06232
Example response:
{
"depth": 12.0,
"hash": "347b3c308971",
"id": "d2c53c80-fc5f-4e10-9c8b-28f4a7f06232",
"index": 2,
"location": {
"x": 3000,
"y": 1500
},
"original_filename": "quarterly-report.pdf",
"parent_id": "0aad755b-c78f-4392-88fb-6efb31d35290",
"pinned": false,
"scale": 1,
"size": {
"height": 1684,
"width": 1190
},
"state": "normal",
"title": "Q3 Report",
"widget_type": "Pdf"
}
Validation errors:
- Setting
depthbelow 1.0 returns 400 Bad Request:Depth must be >= 1, got <value> - Setting
indexto a negative value returns 400 Bad Request:PDF index must be >= 0, got <value> - Setting
sizewith zero or negative dimensions is rejected
Download PDF
Downloads the original PDF file as a binary attachment.
GET /api/v1/canvases/:canvas_id/pdfs/:pdf_id/download
Path parameters:
canvas_id(uuid, required) -- ID of the canvaspdf_id(uuid, required) -- ID of the PDF to download
Example request:
curl -H "Private-Token: YOUR_TOKEN" \
-o downloaded-report.pdf \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs/d2c53c80-fc5f-4e10-9c8b-28f4a7f06232/download
The response includes a content-disposition: attachment header with the original filename.
Current behavior
The filename comes from the widget's original_filename. The server does not yet take it from the uploaded file's name, so send original_filename when you create the widget; otherwise the download uses an internal name. This is being corrected.
Delete PDF
Permanently removes a PDF widget from the canvas. The underlying file is deleted from server storage later, once no canvas references it.
DELETE /api/v1/canvases/:canvas_id/pdfs/:pdf_id
Path parameters:
canvas_id(uuid, required) -- ID of the canvaspdf_id(uuid, required) -- ID of the PDF to delete
Example request:
curl -X DELETE \
-H "Private-Token: YOUR_TOKEN" \
https://canvus.example.com/api/v1/canvases/a528ddb9-ee56-47f2-a419-0c3a9227996e/pdfs/d2c53c80-fc5f-4e10-9c8b-28f4a7f06232
A successful deletion returns an empty response with status 200 OK.
Error responses
All endpoints return errors as JSON with a msg field.
- 400 Bad Request -- Invalid input (e.g. depth below 1.0, negative page index, missing file in upload)
- 401 Unauthorized -- Missing or invalid authentication token
- 403 Forbidden -- View-only user attempted a write operation
- 404 Not Found -- Canvas or PDF does not exist
Current behavior
- An invalid or expired token returns
403 Forbidden, not401. See Current behavior. - Create does not yet enforce the
depthlimit. A widget created withoutdepthgets0, and a value below 1.0 is accepted. Only update rejects it. - Create does not yet validate
index: it defaults to1rather than0, and negative or fractional values are accepted. Update rejects negative values but accepts fractions. - A zero or negative
sizeis not rejected. Create stores it; update ignores it and still returns200 OK. - An update rejected with
400 Bad Requestcan still apply other fields sent in the same request.
These are being corrected.
Example error responses:
{"msg": "Depth must be >= 1, got 0.5"}
{"msg": "PDF index must be >= 0, got -1"}