Skip to main content

PyPI version License Python versions

pagekit-core

Python client for the PageKit content API.
Sync and async support, fully typed, and production-ready.


Installation

pip install pagekit-core
# or
poetry add pagekit-core
# or
uv pip install pagekit-core

Requires: Python >= 3.10


Quick Start

from pagekit import Pagekit

client = Pagekit(api_key="pk_live_...")

# List posts
page = client.posts.list(status="published", limit=10)
for post in page.data:
    print(post.title)

# Get a post by slug
post = client.posts.get_by_slug("hello-world")

# Create a post
post = client.posts.create(
    title="Hello world",
    content="<p>First post</p>",
    status="published",
)

# Update a post
updated = client.posts.update("post-id", title="Updated title")

# Delete a post
client.posts.delete("post-id")

Async Support

The client provides full async support with AsyncPagekit:

from pagekit import AsyncPagekit

client = AsyncPagekit(api_key="pk_live_...")

# List posts
page = await client.posts.list(status="published")

# Get by slug
post = await client.posts.get_by_slug("hello-world")

# Create a post
post = await client.posts.create(
    title="Hello world",
    content="<p>First post</p>",
)

# Update
updated = await client.posts.update("post-id", title="Updated")

# Delete
await client.posts.delete("post-id")

Configuration

from pagekit import Pagekit

client = Pagekit(
    api_key="pk_live_...",                          # Required
    base_url="https://api.pagekit.cc/v1",           # Optional, default shown
    timeout=30,                                      # Optional, seconds
    headers={"X-Custom-Header": "value"},           # Optional
)

Configuration Options

Option Type Required Default Description
api_key str Yes Your PageKit API key
base_url str No https://api.pagekit.cc/v1 API base URL
timeout float No 30 Request timeout in seconds
headers dict No {} Additional headers for all requests

API Reference

Posts

client.posts.list(params?)

List posts with pagination and filtering.

page = client.posts.list(
    status="published",        # "published" | "draft"
    sort="-published_at",      # Sort by field, prefix with "-" for descending
    page=1,                    # Page number
    limit=20,                  # Items per page
    author="author-id",        # Filter by author
    tag="engineering",         # Filter by tag
    category="tutorials",      # Filter by category
    search="nextjs",           # Full-text search
)

for post in page.data:
    print(post.title)

Returns: Paginated[Post]


client.posts.get(post_id)

Get a single post by ID.

post = client.posts.get("post-id")
print(post.title, post.content)

Returns: Post


client.posts.get_by_slug(slug)

Get a single post by slug.

post = client.posts.get_by_slug("my-first-post")

Returns: Post


client.posts.create(input)

Create a new post.

post = client.posts.create(
    title="My Post",
    content="# Title\n\nContent...",
    status="published",
    excerpt="A short summary",
    slug="my-post",
    author="author-id",
    tags=["tag-id-1", "tag-id-2"],
    categories=["category-id"],
    seo={
        "title": "Custom SEO Title",
        "description": "Custom description",
    },
)

Returns: Post


client.posts.update(post_id, input)

Update an existing post. Only include fields you want to change.

updated = client.posts.update(
    "post-id",
    title="Updated Title",
    status="draft",
)

Returns: Post


client.posts.delete(post_id)

Delete a post permanently.

client.posts.delete("post-id")

Returns: None


Authors

client.authors.list(params?)

List all authors.

page = client.authors.list()
for author in page.data:
    print(author.name)

Returns: Paginated[Author]


client.authors.get(author_id)

Get a single author by ID.

author = client.authors.get("author-id")

Returns: Author


Categories

client.categories.list(params?)

List all categories.

page = client.categories.list()
for category in page.data:
    print(category.name)

Returns: Paginated[Category]


client.categories.get_by_slug(slug)

Get a single category by slug.

category = client.categories.get_by_slug("engineering")

Returns: Category


Tags

client.tags.list(params?)

List all tags.

page = client.tags.list()
for tag in page.data:
    print(tag.name)

Returns: Paginated[Tag]


Media

client.media.list(params?)

List all media assets.

page = client.media.list()
for asset in page.data:
    print(asset.filename, asset.url)

Returns: Paginated[Media]


client.media.create(input)

Register a new media asset.

media = client.media.create(
    url="https://example.com/image.png",
    filename="image.png",
    mime_type="image/png",
    size=1024,
    alt="Descriptive alt text",
)

Returns: Media


client.media.delete(media_id)

Delete a media asset.

client.media.delete("media-id")

Returns: None


Types

The client uses Pydantic models for all data types:

from pagekit import Post, Author, Category, Tag, Media

# All models are accessible for type hints
def process_post(post: Post) -> None:
    print(post.title, post.status)

Error Handling

from pagekit import Pagekit, PagekitError

client = Pagekit(api_key="pk_live_...")

try:
    post = client.posts.get("nonexistent-id")
except PagekitError as e:
    print(e.status)         # 404
    print(e.code)           # "not_found"
    print(e.message)        # Human-readable message

    # Convenience properties
    if e.is_auth_error:
        print("Invalid API key (401/403)")
    if e.is_rate_limited:
        print("Rate limited — retry after delay (429)")
    if e.is_server_error:
        print("Server error — safe to retry (5xx)")

Error Properties

Property Type Description
status int HTTP status code
code str Machine-readable error code
message str Human-readable error message
is_auth_error bool True for 401/403 errors
is_rate_limited bool True for 429 errors
is_server_error bool True for 5xx errors

Framework Integrations

FastAPI

from fastapi import FastAPI, Depends
from pagekit import Pagekit, AsyncPagekit

app = FastAPI()

def get_pagekit():
    return AsyncPagekit(api_key="pk_live_...")

@app.get("/posts")
async def list_posts(pagekit: AsyncPagekit = Depends(get_pagekit)):
    posts = await pagekit.posts.list(status="published")
    return posts.data

@app.get("/posts/{slug}")
async def get_post(slug: str, pagekit: AsyncPagekit = Depends(get_pagekit)):
    post = await pagekit.posts.get_by_slug(slug)
    return post

Django

# views.py
from django.http import JsonResponse
from pagekit import Pagekit

client = Pagekit(api_key="pk_live_...")

def blog_list(request):
    page = client.posts.list(status="published")
    return JsonResponse({"posts": [p.model_dump() for p in page.data]})

Flask

from flask import Flask, jsonify
from pagekit import Pagekit

app = Flask(__name__)
client = Pagekit(api_key="pk_live_...")

@app.route("/api/posts")
def posts():
    page = client.posts.list(status="published")
    return jsonify([p.model_dump() for p in page.data])

Development

# Create virtual environment
python -m venv .venv
source .venv/bin/activate

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=src/pagekit

# Type check (requires mypy)
mypy src

# Format code (requires black)
black src tests

Supported Python Versions

  • Python 3.10
  • Python 3.11
  • Python 3.12
  • Python 3.13


License

MIT © Arovi Labs

Download files

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

Source Distribution

pagekit_core-0.1.1.tar.gz (9.3 kB view details)

Uploaded Source

Built Distribution

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

pagekit_core-0.1.1-py3-none-any.whl (11.6 kB view details)

Uploaded Python 3

File details

Details for the file pagekit_core-0.1.1.tar.gz.

File metadata

  • Download URL: pagekit_core-0.1.1.tar.gz
  • Upload date:
  • Size: 9.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pagekit_core-0.1.1.tar.gz
Algorithm Hash digest
SHA256 3cde92c7101bf485d32c0373ee12e342c9268b57c3b79d75c79e9a5b6dadac67
MD5 909f849bb5fee3cc3925a60db4a42685
BLAKE2b-256 fa847659fed1df977fba59ba0451cb5bd11c752650b57c4ac2ba3ebd8c79afcd

See more details on using hashes here.

File details

Details for the file pagekit_core-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pagekit_core-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 11.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pagekit_core-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0daad762f599121411e50b923046053d2aeb401b44e64060bdb66185161b9892
MD5 53d450d251d6099a93f074b1f6494a58
BLAKE2b-256 c6dd7a99d67307761884cc7d54bda7ad379fc47e423629f506a1f646efbf9ff9

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 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