🚧 FastCMS is under active development — not ready for production use. APIs and features may change without notice.
FastCMS
SDKs

Python SDK

Official Python SDK for FastCMS with both synchronous and async clients, full CRUD, file uploads, real-time subscriptions, and OTP authentication.

Python SDK

The official Python SDK for FastCMS provides both synchronous and async clients built on httpx.

Installation

pip install fastcms-py

Quick Start

from fastcms import FastCMS

client = FastCMS(base_url="http://localhost:8000")

# Sign in
auth = client.auth.sign_in("admin@example.com", "password")

# Query records
posts = client.collection("posts").list(
    sort="-created",
    filter="published=true",
    per_page=20,
)
print(posts.items)

Async Client

from fastcms import AsyncFastCMS

async def main():
    client = AsyncFastCMS(base_url="http://localhost:8000")

    auth = await client.auth.sign_in("admin@example.com", "password")

    posts = await client.collection("posts").list()
    print(posts.items)

Authentication

# Register
user = client.auth.sign_up("user@example.com", "SecurePass123")

# Login
auth = client.auth.sign_in("user@example.com", "SecurePass123")

# Get current user
me = client.auth.me()

# Update profile
client.auth.update_me(name="Jane Doe")

# Change password
client.auth.change_password("oldPass", "newPass")

# Logout all devices
client.auth.logout_all()

OTP (Passwordless)

# Step 1: Request OTP
client.auth.request_otp("user@example.com")

# Step 2: Authenticate with code from email
auth = client.auth.auth_with_otp("user@example.com", "483921")

Email Management

# Request email change
client.auth.request_email_change("new@example.com", "current_password")

# Confirm with token from email
client.auth.confirm_email_change("verification-token")

# Verify email address
client.auth.verify_email("verification-token")

Session Management

# List active sessions
sessions = client.auth.get_sessions()  # returns list of session dicts

# Revoke a session
client.auth.revoke_session(session_id)

# Logout all devices
client.auth.logout_all()

Collections

col = client.collection("products")

# List records
result = col.list(
    page=1,
    per_page=30,
    sort="-created",
    filter="price>=100",
    search="laptop",
)
# result.items, result.total

# Get one record
product = col.get_one("record-id")

# Create
created = col.create({"name": "Laptop", "price": 999})

# Update
updated = col.update("record-id", {"price": 899})

# Delete
col.delete("record-id")

Files

# Upload
with open("image.png", "rb") as f:
    file = client.files.upload(
        f,
        collection_name="products",
        record_id="record-id",
        field_name="image",
    )

# Download URL
url = client.files.get_download_url(file.id)

# Thumbnail URL (WxH, with optional modifier)
# Modifiers: (none)=center-crop, f=fit, t=top-crop, b=bottom-crop
# Use 0xH or Wx0 for proportional resize
thumb_url = client.files.get_download_url(file.id, thumb="300x200")
fit_url   = client.files.get_download_url(file.id, thumb="300x200f")
prop_url  = client.files.get_download_url(file.id, thumb="0x150")

# Protected file token (2-minute access)
token_data = client.files.get_token(file.id)
protected_url = client.files.get_download_url(file.id, token=token_data.token)

# Mark as protected
client.files.set_protected(file.id, True)

# Delete
client.files.delete(file.id)

Real-time Subscriptions

The sync client runs SSE listeners in background daemon threads. Requires httpx-sse:

pip install httpx-sse
# Subscribe — returns an unsubscribe callable
unsubscribe = client.realtime.subscribe(
    "posts",
    callback=lambda event: print(event),
)

# With filter
unsubscribe = client.realtime.subscribe(
    "posts",
    callback=lambda event: print(event),
    filter="published=true",
)

# Stop the listener
unsubscribe()

# Stop all listeners
client.realtime.close_all()

Async Real-time

The async client exposes an async generator:

from fastcms import AsyncFastCMS
import asyncio

async def main():
    client = AsyncFastCMS(base_url="http://localhost:8000")
    await client.auth.sign_in("admin@example.com", "pass")

    async for event in client.realtime.subscribe("posts"):
        print(event)

asyncio.run(main())

Async Usage

Every method on AsyncFastCMS is the same as the sync client but awaitable:

from fastcms import AsyncFastCMS
import asyncio

async def main():
    client = AsyncFastCMS(base_url="http://localhost:8000")

    auth = await client.auth.sign_in("admin@example.com", "pass")

    # All the same methods, just awaited
    posts = await client.collection("posts").list(sort="-created")
    new_post = await client.collection("posts").create({"title": "Hello"})
    await client.collection("posts").delete(new_post.id)

asyncio.run(main())

Error Handling

from fastcms.exceptions import (
    FastCMSError,
    AuthenticationError,
    NotFoundError,
    ValidationError,
    RateLimitError,
)

try:
    post = client.collection("posts").get_one("nonexistent-id")
except NotFoundError:
    print("Post not found")
except AuthenticationError:
    print("Invalid or expired token")
except ValidationError as e:
    print(f"Validation failed: {e.errors}")
except RateLimitError:
    print("Too many requests, slow down")

API Keys

client = FastCMS(
    base_url="http://localhost:8000",
    api_key="fk_live_your_key_here",
)

Auto Token Refresh

Both sync and async clients automatically retry requests with a refreshed token on 401 responses. No manual handling required as long as the client was initialized with valid tokens via sign_in().

On this page