Skip to content

Content export and backup

The MultiTaction Canvus REST API can export the content of your canvases: every widget as JSON, plus the original files behind images, videos, PDFs and other file widgets. Use it to archive finished projects, feed content into another system, or keep a readable copy of selected canvases.

This is not a server backup

An API export cannot be restored into Canvus Server. To back up and restore a whole server, including its database, users, permissions and every asset, use the Canvus Server command line (--backup and --restore). See Server backup and restore.

What an export can include

Content Call
The list of canvases GET /canvases (id, name, folder_id, mode, in_trash)
The folder tree GET /canvas-folders
Every widget on a canvas, with pen strokes GET /canvases/{id}/widgets?annotations=1
Items waiting in the canvas's uploads folder GET /canvases/{id}/uploads-folder
Original files GET /assets/{hash} with a canvas-id header, or the typed .../images/{id}/download, .../videos/{id}/download, .../pdfs/{id}/download
Canvas background settings GET /canvases/{id}/background
Who can access a canvas GET /canvases/{id}/permissions
Users and groups (administrators) GET /users, GET /groups, GET /groups/{id}/members
Audit trail (administrators) GET /audit-log/export-csv

The export runs as the account whose token you use, and includes only what that account can see. Use an administrator account, or an account with view on the canvases you want, as described in Authentication and service accounts.

GET /canvases/{id}/widgets returns connectors and the canvas background along with the regular widgets. Each file widget carries a hash and an original_filename. An empty hash means the file is not available on the server.

Export script

This script writes one folder per canvas, with widgets.json and the original files:

import json
import pathlib
import requests

API = "https://canvus.example.com/api/v1"
canvus = requests.Session()
canvus.headers["Private-Token"] = "EXPORT_ACCOUNT_TOKEN"
canvus.verify = True  # or the path to your server's CA certificate

out = pathlib.Path("canvus-export")


def save_json(path, data):
    path.write_text(json.dumps(data, indent=2, ensure_ascii=False))


def export_canvas(canvas):
    folder = out / canvas["id"]
    (folder / "files").mkdir(parents=True, exist_ok=True)
    save_json(folder / "canvas.json", canvas)

    widgets = canvus.get(f"{API}/canvases/{canvas['id']}/widgets",
                         params={"annotations": 1}).json()
    save_json(folder / "widgets.json", widgets)

    for w in widgets:
        if not w.get("hash"):
            continue
        name = f"{w['id']}-{w.get('original_filename') or 'file'}"
        r = canvus.get(f"{API}/assets/{w['hash']}",
                       headers={"canvas-id": canvas["id"]}, stream=True)
        if r.ok:
            with open(folder / "files" / name, "wb") as f:
                for chunk in r.iter_content(1 << 20):
                    f.write(chunk)
        else:
            print("skipped", w["id"], r.status_code)


out.mkdir(exist_ok=True)
canvases = canvus.get(f"{API}/canvases").json()
save_json(out / "canvases.json", canvases)
for c in canvases:
    if not c.get("in_trash"):
        export_canvas(c)

Run it on a schedule to keep a rolling archive. The background image, if any, has its own hash inside the image object of the background widget; add it to the loop if you need it.

What an export does not cover

  • There is no import endpoint. To bring exported content back, you recreate each widget with the normal create calls (POST .../notes, POST .../images and so on).
  • IDs change on re-creation. New widgets get new id values. Connectors and pen strokes refer to widgets by id, so recreate the widgets first, keep a map from old to new id, then recreate connectors and annotations against the new values.
  • Passwords and tokens are not exportable. User records do not include passwords, and token values are shown only once, when created.
  • No history. The export is the current state. Earlier versions of a canvas are not available through the API.

For moving a canvas within the same server, POST /canvases/{id}/copy duplicates it with all its widgets and files, in one call. See Canvases.