Skip to main content

unofficial-mural-python-client

Unofficial, community-maintained project. Not affiliated with, endorsed by, or supported by MURAL. For official resources, see developers.mural.co.

A typed Python client for the MURAL Public API, covering all 76 endpoints of the OpenAPI 3.1 spec — murals, widgets (all 10 types), rooms, workspaces, templates, search, and user identity.

  • Spec-accurate: every request/response model is a pydantic v2 model hand-derived from the spec — camelCase wire format, snake_case Python attributes, enums as Literals.
  • Client-side validation: request bodies are validated before the HTTP call, so malformed input fails fast instead of via a 400.
  • OAuth2 built in: authorization-code flow, automatic token refresh on 401, and an interactive localhost helper for getting your first token.
  • Transparent pagination: every list endpoint has a raw single-page method and an iter_* generator that follows next cursors.
  • Typed errors: HTTP errors map to an exception hierarchy carrying the parsed MURAL error body.

Install

uv add unofficial-mural-python-client

Install the latest development version

To track main (or a specific tag) instead of the latest PyPI release:

uv add git+https://github.com/franpandol/unofficial-mural-python-client

Pin to a tag for reproducible installs, e.g. git+https://github.com/franpandol/unofficial-mural-python-client@v0.1.0.

Contributing / running from source

git clone https://github.com/franpandol/unofficial-mural-python-client
cd unofficial-mural-python-client
uv sync --extra dev

Set up a MURAL OAuth app

  1. Sign in at developers.mural.co and create a new app.
  2. Add the redirect URI http://localhost:8765/callback (used by the local OAuth helper).
  3. Select the scopes you need — least privilege is supported; e.g. a read-only integration only needs murals:read + identity:read.
  4. Copy .env.example to .env and fill in MURAL_CLIENT_ID, MURAL_CLIENT_SECRET, and MURAL_REDIRECT_URI.

If MURAL shows "The redirect URL is invalid", the app dashboard does not allow the exact MURAL_REDIRECT_URI being sent. For the quickstart, add http://localhost:8765/callback exactly: http (not https), localhost (not 127.0.0.1), port 8765, path /callback, and no trailing slash.

If MURAL shows "Required permission scopes not recognized", add every requested scope to that same app's permission-scope allowlist. The quickstart requests identity:read, murals:read, and murals:write; murals:write is required because the smoke test creates widgets and deletes the test mural.

Quickstart

from mural import MuralClient, MuralOAuth, run_local_oauth_flow
from mural.models import CreateMuralRequest, CreateStickyNoteWidget

oauth = MuralOAuth.from_env(scopes=["identity:read", "murals:read", "murals:write"])
token = run_local_oauth_flow(oauth)  # opens the browser, catches the redirect

with MuralClient(token, oauth=oauth) as client:
    me = client.users.me()

    mural = client.murals.create(CreateMuralRequest(room_id=1234567890, title="Retro"))

    client.widgets.create_sticky_notes(
        mural.id,
        [CreateStickyNoteWidget(shape="rectangle", x=100, y=100, text="Went well ✅")],
    )

    for widget in client.widgets.iter_list(mural.id):
        print(widget.type, widget.id)

Or run the end-to-end smoke test (creates and deletes a real mural):

python examples/quickstart.py --room-id <numeric-room-id>

See examples/README.md for the full set of runnable examples and a suggested reading order.

CLI

The package installs a Typer-powered mural command:

uv sync --extra dev
uv run mural --help

Authenticate once with the same OAuth environment variables used by the SDK:

uv run mural auth login \
  --scope identity:read \
  --scope murals:read \
  --scope murals:write

uv run mural auth whoami

Common commands print JSON and reuse the SDK's typed request/response models:

uv run mural workspaces list --limit 10
uv run mural workspaces rooms <workspace-id>
uv run mural rooms create --workspace-id <workspace-id> --name "Project room" --type private
uv run mural murals create --room-id <numeric-room-id> --title "Retro"
uv run mural widgets create-sticky-note <mural-id> --text "Went well" --x 100 --y 100
uv run mural search murals <workspace-id> --query "retro"

By default, OAuth tokens are stored at ~/.config/mural/token.json with private file permissions. Use --token-path <path> on auth and API commands to override it.

Token persistence and auto-refresh

MuralClient refreshes the access token once on a 401 when built with an oauth and a token that has a refresh_token. Persist rotated tokens via the callback:

client = MuralClient(token, oauth=oauth, on_token_refresh=save_token_somewhere)

Pagination

page = client.workspaces.list(limit=25)          # one page: page.value, page.next
for ws in client.workspaces.iter_list():          # all pages, transparently
    print(ws.name)

Errors

from mural import MuralNotFoundError

try:
    client.murals.get("workspace1234.000")
except MuralNotFoundError as error:
    print(error.status_code, error.error.code, error.error.message)

MuralBadRequestError (400), MuralAuthError (401), MuralPermissionError (403), MuralNotFoundError (404), MuralRateLimitError (429), MuralServerError (5xx) — all subclasses of MuralAPIError.

Resource map

Attribute Endpoints
client.murals CRUD, duplicate, export, access info, assets, private mode, chat, tags, timer, users/permissions, visitor settings, voting sessions
client.widgets list/get/delete + typed create/update per type: sticky note*, shape*, textbox*, title*, area, arrow, comment, file, image, table
client.rooms CRUD, folders, murals listing, members, invite/remove
client.workspaces list/get, murals, rooms, templates, invite
client.templates default templates, create-from-mural, delete, create-mural-from-template
client.search murals, rooms, templates within a workspace
client.users /users/me

* bulk endpoints — take a list of bodies, return a list of created widgets, matching the API.

Tests

pytest --cov          # mocked with respx; no network, 98 tests, 99% coverage

Release files for unofficial-mural-python-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 unofficial-mural-python-client 0.1.0
File Size Uploaded
unofficial_mural_python_client-0.1.0.tar.gz 84.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for unofficial-mural-python-client 0.1.0
File Interpreter ABI Platform
unofficial_mural_python_client-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 125.8 kB

Release files / unofficial_mural_python_client-0.1.0.tar.gz

Download URL unofficial_mural_python_client-0.1.0.tar.gz
Size 84.4 kB
Tags Source
SHA-256 checksum
How to use checksums
5cc6040ac04dd7ed89ed8aae4a46e4ec4a04f60287311a362d31783959ed3fd4
BLAKE2b-256 checksum
How to use checksums
50c62f2dde170b25f8be32edf08d34f00edecbe1de00f7eeaed792cbb781ee78
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.27 {"installer":{"name":"uv","version":"0.11.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / unofficial_mural_python_client-0.1.0-py3-none-any.whl

Download URL unofficial_mural_python_client-0.1.0-py3-none-any.whl
Size 41.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c6b7f4713c244b691e93409662c59faef755e7d2c24f7c056492cd419f7055c5
BLAKE2b-256 checksum
How to use checksums
6242795baa60f7c1919bd630cd1cc44655c655bfc88ef113f916ac468eeb2254
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.27 {"installer":{"name":"uv","version":"0.11.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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