Skip to main content

scribe-client (Python)

Python bindings for the Scribe document conversion API. This package is a thin, synchronous wrapper (via PyO3) around the Rust scribe-client crate, so it behaves the same as the Rust client.

  • Synchronous by design. Every method blocks until the request completes; there's no asyncio API. Under the hood each call runs on a shared Tokio runtime with the GIL released, so other Python threads keep running while a request is in flight.
  • Auto-refreshing tokens. ScribeClient holds a TokenSet and refreshes it automatically when it's missing or about to expire, and again if a request unexpectedly comes back 401.

Installing

pip install scribe-client

Wheels are built for Linux, macOS and Windows, for Python 3.9 and later.

To build it from source instead, with maturin:

cd crates/scribe-client-py
uv venv                      # or: python -m venv .venv
source .venv/bin/activate
uv pip install maturin
maturin develop              # builds the extension and installs it into the venv

Authenticating

The server uses OAuth 2.0 Authorization Code + PKCE. There's no password or client-credentials grant, so a human has to approve access once via a browser; after that, ScribeClient handles refreshing the token for you.

from scribe_client import AuthClient, PkceChallenge, ScribeClient

auth = AuthClient(base_url, client_id)
pkce = PkceChallenge()

# Send the user to this URL. After they log in and approve, they're
# redirected to redirect_uri with a `code` query parameter.
url = auth.authorization_url(redirect_uri, pkce)

# Exchange the code (and the verifier from the *same* PkceChallenge) for a
# token set.
tokens = auth.exchange_code(redirect_uri, code, pkce.verifier)

client = ScribeClient(base_url, client_id, tokens)

tokens.access_token, tokens.refresh_token, and tokens.expires_at (Unix seconds, or None) are readable if you want to persist them between runs — reconstruct a TokenSet later with TokenSet(access_token, refresh_token, expires_at).

See examples/pkce_flow.py for a runnable end-to-end version of this, including creating a document and converting it.

Documents

# From a local file...
document_id = client.create_document_from_file("report.docx", data)
# ...or have the server fetch it from a URL.
document_id = client.create_document_from_url("https://example.com/report.pdf")
# Both take an optional password, for a file you already know is protected.
document_id = client.create_document_from_file("locked.pdf", data, "hunter2")

Creating a document automatically starts an html_stream conversion (a fast preview), so the caller has something to show immediately even if the account is out of page credits for a full conversion.

result = client.list_documents()
print(result.pages_remaining)  # None if the account isn't page-metered
for doc in result.documents:
    # doc.title and doc.page_count are None until the server has
    # determined them (e.g. briefly, for a URL-sourced document).
    print(doc.id, doc.title, doc.page_count, doc.inserted_at)
    for output in doc.outputs:
        print(" ", output.format, output.stage, output.progress)

client.delete_document(document_id)

list_outputs(document_id) returns an OutputList for one document — .outputs, the same rows list_documents() embeds per-document without the document metadata, plus .is_password_needed; get_settings/update_settings read and partially update a document's conversion settings (language, TTS voice, Braille table, and so on — see Settings's attributes for the full set).

settings = client.get_settings(document_id)
client.update_settings(document_id, {"large_print": True})

update_settings takes a plain dict; only the keys you pass are changed server-side.

Converting to another format

Creating a document only starts the html_stream preview. Converting to any other format — pdf, epub, daisy, docx, brf, mp3, offline_html, mobi — happens over a real-time channel, not a REST call, so the server can guarantee it's subscribed to progress on whatever it just started converting.

channel = client.open_document_channel(document_id)
try:
    output_id = channel.start_conversion("pdf")

    while True:
        event = channel.next_event()

        if event["type"] == "status":
            print(f"{event['format']}: {event['stage']} {event['progress']:.0%}")
        elif event["type"] == "conversion_complete" and event["format"] == "pdf":
            data = client.download_output(document_id, "pdf")
            break
        elif event["type"] == "error":
            raise RuntimeError(event["reason"])
finally:
    channel.close()

start_conversion is idempotent — calling it again for a format that's already converting or complete just returns that output's existing id without starting a duplicate conversion.

next_event() blocks until the next event arrives and returns it as a dict tagged by event["type"]:

type other keys meaning
"status" format, stage, progress a conversion's stage or progress changed
"chunk" content a chunk of streamed HTML (html_stream only)
"conversion_complete" format, output_id a format finished converting
"error" reason an out-of-band error unrelated to a specific call
"password_required" — the document is protected and hasn't been unlocked

stage is one of "queue", "start", "convert", "add_image_descriptions", or "complete".

Joining the channel also delivers events for any formats that were already converting (or complete) when you joined — including incomplete parent formats. (Most formats are rendered from the html output, and daisy is additionally assembled from mp3; the server subscribes you to those automatically when they're not finished yet.) Filter on event["format"] if you only care about one format at a time, as in the example above.

Password-protected documents

A protected PDF can't be converted until its password is supplied. The server reports this in three places: password_required is pushed as soon as you join the channel, start_conversion raises PasswordRequiredError rather than queueing work that can only fail, and is_password_needed is set on the document in list_documents() and list_outputs().

Pass the password to start_conversion to unlock and convert in one call. It's stored against the document, so converting it to further formats later doesn't need it again.

try:
    output_id = channel.start_conversion("pdf")
except PasswordRequiredError:
    output_id = channel.start_conversion("pdf", prompt_for_password())

A wrong password isn't rejected here — the server accepts it, the converter fails on it, and an "error" event with reason "invalid_password" arrives from next_event(). Prompt again and call start_conversion again. A locked document has no outputs at all, so there's nothing to clean up between attempts.

Always close() the channel when you're done with it (a try/finally is the easiest way, as above) — it holds an open WebSocket connection.

Errors

All exceptions are subclasses of ScribeApiError:

Exception Raised when
NotFoundError the document (or channel) doesn't exist
ForbiddenError the document exists but isn't owned by the current user
ConversionNotCompleteError download_output was called before that format finished converting
ConversionInProgressError start_conversion was called while a different conversion is already running
RateLimitedError start_conversion was called too many times too quickly
PasswordRequiredError the document is a protected file and no password has been supplied
NeedsPurchaseError the account doesn't have enough page credits for the requested conversion
InvalidGrantError an OAuth code, refresh token, or PKCE verifier didn't check out
ScribeApiError (base) anything else the server rejected, or a connection-level failure
from scribe_client import NotFoundError

try:
    client.delete_document(document_id)
except NotFoundError:
    print("already gone")

Running the tests

cd crates/scribe-client-py
maturin develop
pytest

Tests don't hit a real server: tests/conftest.py runs a small dependency-free HTTP server (stdlib http.server) for REST calls, and a hand-rolled WebSocket server (stdlib socket, doing the RFC 6455 handshake itself) for exercising DocumentChannel.

Metadata

Release files for scribe-client 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for scribe-client 0.1.0
File Size Uploaded Provenance Actions
scribe_client-0.1.0.tar.gz 81.3 kB With provenance Details for scribe_client-0.1.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for scribe-client 0.1.0
File Actions
scribe_client-0.1.0-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details for scribe_client-0.1.0-cp39-abi3-win_amd64.whl
scribe_client-0.1.0-cp39-abi3-musllinux_1_2_x86_64.whl CPython 3.9 abi3 Linux musl 1.2+ x86-64 Details for scribe_client-0.1.0-cp39-abi3-musllinux_1_2_x86_64.whl
scribe_client-0.1.0-cp39-abi3-musllinux_1_2_aarch64.whl CPython 3.9 abi3 Linux musl 1.2+ ARM64 Details for scribe_client-0.1.0-cp39-abi3-musllinux_1_2_aarch64.whl
scribe_client-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.9 abi3 Linux glibc 2.17+ x86-64 Details for scribe_client-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
scribe_client-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.9 abi3 Linux glibc 2.17+ ARM64 Details for scribe_client-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
scribe_client-0.1.0-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details for scribe_client-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
scribe_client-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details for scribe_client-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl

Total release size: 22.8 MB

Release files / scribe_client-0.1.0.tar.gz

Download URL scribe_client-0.1.0.tar.gz
Size 81.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d5c0d0e117c5692eb1f655facd6b3bd397c26d6c575f42be7f6a87ffd8021b00
BLAKE2b-256 checksum
How to use checksums
4cf5bb2bf1518675713984186b97a8887bef5ab5b8add69e7f702dbf1047ff4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / scribe_client-0.1.0-cp39-abi3-win_amd64.whl

Download URL scribe_client-0.1.0-cp39-abi3-win_amd64.whl
Size 2.7 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
968aab23656b4723a9a47a83e67a73e319004a47cb143e11909cc56b745671ef
BLAKE2b-256 checksum
How to use checksums
484d9cc0beeb68bb2d692a802751f9842b9707e816b37f3e07965d6cb627b5fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / scribe_client-0.1.0-cp39-abi3-musllinux_1_2_x86_64.whl

Download URL scribe_client-0.1.0-cp39-abi3-musllinux_1_2_x86_64.whl
Size 3.6 MB
Tags CPython 3.9 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
fbb2599905ea48d49cd7a98522542c017f159717954de43cba997fc6cb78a83a
BLAKE2b-256 checksum
How to use checksums
0769c6d425dc97036e4d511e2ae712f22db520a9979280ec9fb4cf604ce8fd7c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / scribe_client-0.1.0-cp39-abi3-musllinux_1_2_aarch64.whl

Download URL scribe_client-0.1.0-cp39-abi3-musllinux_1_2_aarch64.whl
Size 3.5 MB
Tags CPython 3.9 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
d0c44ae309c5bf7644e3721cbdf04de4982e0455592a969f4a35335107c09c17
BLAKE2b-256 checksum
How to use checksums
09debdb04a2bd221ee6512068d2184dac6374c39302341dc608ed392c71aa5ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / scribe_client-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL scribe_client-0.1.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 3.4 MB
Tags CPython 3.9 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
185aa40c5a0a7afbc23fb89ddbefdfd836efa29f7edcad530d94f2a572bed672
BLAKE2b-256 checksum
How to use checksums
109493773364ee7631846083c938126e7aae23aa2db24836b79cf46d2b1bbc97
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / scribe_client-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL scribe_client-0.1.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 3.3 MB
Tags CPython 3.9 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
03cfbbce136a482de4b304fdf2af8a116f9f653dcc39eea3f47b314a6149b7a0
BLAKE2b-256 checksum
How to use checksums
4c22f279fe4c6b3b244096999869512b413ba66e15cb7335efbb6e425015286f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / scribe_client-0.1.0-cp39-abi3-macosx_11_0_arm64.whl

Download URL scribe_client-0.1.0-cp39-abi3-macosx_11_0_arm64.whl
Size 3.0 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
3b18be9d85cb35e7111683800f8bbe92f59f6e67bdec8eb81af772a5e77d7c07
BLAKE2b-256 checksum
How to use checksums
d8e61bb7764236047ae8f526c386ef2b9a9b8ec31095bf0676e8a8032e046fea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Release files / scribe_client-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl

Download URL scribe_client-0.1.0-cp39-abi3-macosx_10_12_x86_64.whl
Size 3.2 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
46b608e9e593f3cc2aa52e1c5ac87ff53d84f23562e0d29cd1f80595301cbfa5
BLAKE2b-256 checksum
How to use checksums
a742526f6ad0558a655048ba073590a399bf66f1afdf732a20bdf07ebeafdd06
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

Security for scribe-client 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 8 files in this release have been uploaded with provenance metadata.

Select from 8 files

Attestation for scribe_client-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 16, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

8 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page