Skip to main content

bookstack-client

bookstack-client

Python 3.14 CLI and library for the BookStack REST API

PyPI Version Python Versions License

GitHub Stars GitHub Issues Buy Me a Coffee


Overview

bookstack-client is a Python package for working with the BookStack REST API from scripts or the command line. It provides a small typed client, environment-based configuration, JSON output, and parallel batch reads.

BookStack authentication uses:

Authorization: Token <token_id>:<token_secret>

Key Features

Feature Description
CLI + Library Use as a command-line tool or Python package
Python 3.14 Built and tested for Python 3.14+
Environment Config Reads BOOKSTACK_URL, BOOKSTACK_TOKEN_ID, and BOOKSTACK_TOKEN_SECRET
.env Support Loads credentials from a local .env file when environment variables are not set
CRUD Helpers Convenience methods for list, get, create, update, and delete
Raw Requests Access any BookStack API endpoint with request()
Parallel Reads Fetch multiple resources concurrently with get_many() or batch-get

Supported Operations

List resources   books, shelves, pages, chapters, users, roles, attachments, images
List all pages   Auto-paginate any resource with list --all
Read item        GET /api/<resource>/<id>
Create item      POST /api/<resource>
Update item      PUT /api/<resource>/<id>
Delete item      DELETE /api/<resource>/<id>
Export item      GET /api/<resource>/<id>/export/<format>
Search           GET /api/search
Tags             GET /api/tags/names, /api/tags/values-for-name
Recycle bin      List, restore, or permanently delete deleted content
Permissions      Read or set content-level permissions
Raw request      Any BookStack API path
Batch reads      Parallel get by IDs

Installation

From PyPI

pip install bookstack-client

From Source

git clone https://github.com/seifreed/bookstack-cli.git
cd bookstack-cli
python3 -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install -e .

Configuration

Environment Variables

export BOOKSTACK_URL="https://bookstack.example.com"
export BOOKSTACK_TOKEN_ID="token-id"
export BOOKSTACK_TOKEN_SECRET="token-secret"

.env File

BOOKSTACK_URL=https://bookstack.example.com
BOOKSTACK_TOKEN_ID=token-id
BOOKSTACK_TOKEN_SECRET=token-secret

Environment variables override values loaded from .env.


Quick Start

# List books
bookstack list books --count 20 --sort +name

# Read a page
bookstack get pages 1

# Fetch pages in parallel
bookstack batch-get pages 1 2 3 --workers 3

Local BookStack Testing

This repository includes a Docker Compose setup for a disposable local BookStack instance:

scripts/bookstack-local.sh up

The script starts BookStack and MariaDB, creates an admin user, creates an API token, and writes a local .env file for the CLI.

Run the live CLI regression test with:

BOOKSTACK_LIVE_TESTS=1 uv run pytest -q tests/integration

Stop the stack with:

scripts/bookstack-local.sh down

Usage

Command Line Interface

# Create a page
bookstack create pages --data '{"book_id":1,"name":"API page","markdown":"Hello"}'

# Update a page
bookstack update pages 1 --data '{"name":"Renamed"}'

# Delete a page
bookstack delete pages 1

# Call a raw endpoint
bookstack request GET /api/system

# Multipart upload
bookstack request POST /api/image-gallery \
  --field type=gallery \
  --field uploaded_to=1 \
  --file image=photo.png

# Search content
bookstack search "deprecated runbook"

# List every tag name, or values for one tag
bookstack tags
bookstack tags --name status

# Manage the recycle bin
bookstack recycle-bin list --count 20 --offset 0
bookstack recycle-bin restore 4
bookstack recycle-bin destroy 4

# Read or set content-level permissions
bookstack permissions get bookshelf 1
bookstack permissions set book 1 --data '{"fallback_permissions":{"inheriting":false}}'

# Download an export directly
bookstack export pages 1 pdf -o page.pdf

# Fetch every page of a resource automatically
bookstack list books --all

Global Options

These apply to every command and must come before the subcommand name:

Option Description
--env-file <path> dotenv file to read; environment variables still override it (default .env)
--timeout <seconds> HTTP timeout in seconds (default 30)
--json Print compact JSON instead of indented
--version Print the installed version and exit
bookstack --env-file prod.env --timeout 60 --json list books

Available Commands

Command Description
bookstack list <resource> List BookStack resources
bookstack get <resource> <id> Fetch one resource by ID
bookstack batch-get <resource> <ids...> Fetch several resources concurrently
bookstack create <resource> --data <json> Create a resource
bookstack update <resource> <id> --data <json> Update a resource
bookstack delete <resource> <id> Delete a resource
bookstack request <method> <path> Send a raw API request
bookstack search <query> Search content
bookstack tags List tag names, or values for --name
bookstack recycle-bin list|restore|destroy Manage deleted content
bookstack permissions get|set <type> <id> Read or set content-level permissions
bookstack export <resource> <id> <format> -o <path> Download a resource export

Listing Options

Option Description
--count <n> Limit result count, or page size when --all is used
--offset <n> Offset list results (not usable with --all)
--sort <field> Sort with BookStack syntax, such as +name
--filter FIELD=VALUE Add BookStack filter[...] query parameters
--all Fetch every page automatically

Raw Request Options

Option Description
--data <json> Send a JSON request body
--field NAME=VALUE Add a multipart form field
--file NAME=PATH Add a multipart file field
-o, --output <path> Write raw response bytes to a file

Task Recipes

These recipes use the current CLI commands and work against any configured BookStack instance.

Export All Books

Export every visible book as a ZIP archive:

mkdir -p exports/books

bookstack --json list books --all \
  | python3 -c 'import json,sys; [print(book["id"]) for book in json.load(sys.stdin)]' \
  | while read -r id; do
      bookstack export books "$id" zip -o "exports/books/${id}.zip"
    done

Use another export format by changing the last argument:

bookstack export books 1 pdf -o book-1.pdf
bookstack export books 1 markdown -o book-1.md
bookstack export books 1 html -o book-1.html
bookstack export books 1 plaintext -o book-1.txt

Create Pages From Markdown

Create a page from a local Markdown file:

python3 - <<'PY' > /tmp/page.json
import json
from pathlib import Path

print(json.dumps({
    "book_id": 1,
    "name": "Runbook",
    "markdown": Path("runbook.md").read_text(encoding="utf-8"),
}))
PY

bookstack create pages --data "$(cat /tmp/page.json)"

Create the page inside a chapter instead:

python3 - <<'PY' > /tmp/page.json
import json
from pathlib import Path

print(json.dumps({
    "chapter_id": 10,
    "name": "Incident Response",
    "markdown": Path("incident-response.md").read_text(encoding="utf-8"),
}))
PY

bookstack create pages --data "$(cat /tmp/page.json)"

Upload Images

Upload an image to a page and get reusable HTML/Markdown snippets in the response:

bookstack request POST /api/image-gallery \
  --field type=gallery \
  --field uploaded_to=1 \
  --field name=diagram.png \
  --file image=diagram.png

Download an uploaded image by ID:

bookstack request GET /api/image-gallery/42/data -o image.png

Migrate Content

Move content between BookStack instances using BookStack ZIP exports/imports.

On the source instance:

bookstack export books 1 zip -o book-1.zip

On the target instance, after switching .env or environment variables:

import_id="$(
  bookstack --json request POST /api/imports --file file=book-1.zip \
    | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])'
)"

bookstack request POST "/api/imports/${import_id}"

For chapter or page imports, provide the target parent:

bookstack request POST "/api/imports/${import_id}" \
  --data '{"parent_type":"book","parent_id":1}'

Partial Backup

Back up structure and selected binary exports without dumping the whole database:

mkdir -p backup/json backup/exports

for resource in books chapters pages shelves attachments users roles; do
  bookstack --json list "$resource" > "backup/json/${resource}.json"
done

bookstack --json request GET /api/system > backup/json/system.json
bookstack --json tags > backup/json/tag-names.json

bookstack --json list books --all \
  | python3 -c 'import json,sys; [print(book["id"]) for book in json.load(sys.stdin)]' \
  | while read -r id; do
      bookstack export books "$id" zip -o "backup/exports/book-${id}.zip"
    done

Find Old Content

Find old or stale pages using BookStack list filters:

bookstack list pages \
  --filter updated_at:lt=2025-01-01 \
  --sort -updated_at \
  --count 50

Search content by text:

bookstack search "deprecated" --count 20

Search by BookStack query syntax:

bookstack search "{updated_by:me} runbook" --page 1 --count 20

Automate Permissions

Read current content permissions for a book:

bookstack permissions get book 1

Set explicit fallback permissions while leaving role overrides unchanged:

bookstack permissions set book 1 --data '{
    "fallback_permissions": {
      "inheriting": false,
      "view": true,
      "create": false,
      "update": false,
      "delete": false
    }
  }'

Apply a role override:

bookstack permissions set book 1 --data '{
    "role_permissions": [
      {
        "role_id": 2,
        "view": true,
        "create": true,
        "update": true,
        "delete": false
      }
    ]
  }'

Use page, book, chapter, or bookshelf as the content type — not shelf, which BookStack rejects.


Python Library

Basic Usage

from bookstack_cli import BookStackClient

client = BookStackClient.from_env()

books = client.list("books", count=20)
page = client.get("pages", 1)
pages = client.get_many("pages", [1, 2, 3], workers=3)

Create and Update

from bookstack_cli import BookStackClient

client = BookStackClient.from_env()

created = client.create("pages", {
    "book_id": 1,
    "name": "API page",
    "markdown": "Hello from Python",
})

updated = client.update("pages", created["id"], {"name": "Renamed page"})

Raw API Requests

from bookstack_cli import BookStackClient

client = BookStackClient.from_env()
system = client.request("GET", "/api/system")

Search, Tags, Recycle Bin, Permissions & Export

from bookstack_cli import BookStackClient

client = BookStackClient.from_env()

all_books = client.list_all("books")  # auto-paginates
results = client.search("runbook", count=20)
tag_names = client.tags()
tag_values = client.tags(name="status")

deleted = client.recycle_bin_list()
client.recycle_bin_restore(deleted["data"][0]["id"])
client.recycle_bin_destroy(4)

perms = client.get_content_permissions("bookshelf", 1)
client.set_content_permissions("book", 1, {"fallback_permissions": {"inheriting": False}})

pdf = client.export("pages", 1, "pdf")
open("page.pdf", "wb").write(pdf.body)

Architecture

Five small modules, each with one job and a strict, one-directional dependency chain:

cli.py        argparse wiring + dispatch only. Talks to BookStack only
              through BookStackClient's public methods.
    |
    v
client.py     One method per BookStack resource operation. Owns BookStack's
              URL and resource-shape conventions.
    |
    v
transport.py  HTTP encoding (JSON/multipart), headers, the raw urllib call,
              and mapping failures to BookStackAPIError.
    |
    v
config.py     Reads BOOKSTACK_* settings from the environment/.env file.
errors.py     The one error type API failures surface as.

config.py and errors.py have no internal dependencies. Nothing outside transport.py imports urllib directly, and nothing outside cli.py builds an argparse parser. cli.py never imports transport.py — it only ever sees BookStackClient.


Requirements

  • Python 3.14+
  • No runtime dependencies
  • See pyproject.toml for package metadata

Quality Gate

Run all local non-live checks with:

scripts/quality.sh

The gate runs black, ruff, mypy, bandit, pip-audit, and the non-integration pytest suite.


Contributing

Contributions are welcome.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support the Project

If this project is useful in your workflows, you can support development:

Buy Me A Coffee

License

This project is licensed under the MIT license. See pyproject.toml.

Attribution


Built for practical BookStack automation

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bookstack_client-0.1.0.tar.gz (57.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

bookstack_client-0.1.0-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file bookstack_client-0.1.0.tar.gz.

File metadata

  • Download URL: bookstack_client-0.1.0.tar.gz
  • Upload date:
  • Size: 57.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for bookstack_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 3c82f4ebcdcea480bf2b2c19c551b52b3ce7b212c994a04b80ef0001e10d6325
MD5 84052dbc45d1a274a0650f347b263365
BLAKE2b-256 7db74d8c9e104e486d97bea12b3178cccc93bfcbb6b7a12fba857c2b321f0785

See more details on using hashes here.

Provenance

The following attestation bundles were made for bookstack_client-0.1.0.tar.gz:

Publisher: release.yml on seifreed/bookstack-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file bookstack_client-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for bookstack_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3f490b03dce90780021b5e366c734926ace17dec178e523c43a5841b38f9a133
MD5 aab8d1b4bd72c686db8ce510fcc8f1bf
BLAKE2b-256 c80e0f23311f8542fe9560c0ebc0bcd84c7dcca72c2b3143cfdad7a79428b12f

See more details on using hashes here.

Provenance

The following attestation bundles were made for bookstack_client-0.1.0-py3-none-any.whl:

Publisher: release.yml on seifreed/bookstack-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page