Skip to content

JasonCrowe/SkoolApp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SkoolApp

A Python client for automating a Skool.com account. It covers community, post, comment, member, and webhook management and ships a small CLI on top.

Why this exists

Skool does not publish a first-party REST API. The options available today are:

Surface Auth Coverage Stability
Zapier integration (built in to Skool) per-group API key triggers + a handful of actions stable
SkoolAPI gatewayhttps://docs.skoolapi.com (community-built) x-api-secret header communities, posts, comments, members, chats, webhooks; expanding stable, preferred
Direct skool.com endpoints (reverse-engineered, browser-style session) email + password ⇒ cookie / bearer token essentially everything the web UI does fragile — internal routes change without notice
Apify scrapers third-party read-only scraper-grade, fine for analytics

skoolapp wraps the middle two options so you can stay on the stable gateway for the 95% case and drop into the direct client only where coverage is missing.

Important: Any automation of a Skool account must comply with Skool's Terms of Service. Use credentials you own or have been given automation rights on, and do not use the direct client to scrape communities you don't belong to.

Installation

pip install -e .[dev]

Python 3.9+.

Quick start (gateway, recommended)

from skoolapp import SkoolClient

with SkoolClient(api_secret="sk_live_...") as client:
    community = client.communities.get("my-community")

    post = client.posts.create(
        group=community["id"],
        title="Release notes v3",
        body="New classroom features shipped today.",
    )

    for reply in client.comments.list(post["id"], limit=20):
        print(reply["author"]["name"], reply["body"])

    client.webhooks.create(
        group=community["id"],
        url="https://example.com/skool/webhook",
        events=["post.created", "comment.created", "member.joined"],
    )

The client reads SKOOLAPI_API_SECRET from the environment by default, so SkoolClient() with no args works once you've exported the secret.

Direct (fallback) client

from skoolapp import SkoolDirectClient

with SkoolDirectClient(email="you@example.com", password="...") as client:
    client.login()
    group = client.get_group("my-community")

    for item in client.feed("my-community", sort="new", limit=10):
        print(item["title"])

    client.create_post(
        group="my-community",
        title="Live from the direct client",
        body="Skool hasn't exposed this yet on the gateway.",
    )

CLI

Every resource is wired into skoolapp:

export SKOOLAPI_API_SECRET=sk_live_...

skoolapp communities list
skoolapp community show my-community
skoolapp posts list --group my-community --limit 5 --sort new
skoolapp post create --group my-community --title "Hi" --body "Hello"
skoolapp members list --group my-community --role admin
skoolapp webhook create \
    --group my-community \
    --url https://example.com/webhook \
    --event post.created --event comment.created

Output is JSONL for list commands and pretty JSON for single-object commands, so you can pipe it straight into jq.

Webhook verification

from skoolapp.webhooks import verify_signature

ok = verify_signature(
    payload=request.body,
    signature_header=request.headers["X-Skool-Signature"],
    secret="whsec_...",
)

The header looks like t=<unix>,v1=<hex> and the digest is HMAC-SHA256(secret, f"{t}.{body}"). Signatures older than five minutes are rejected to defang replay attacks.

Architecture

src/skoolapp/
├── __init__.py        # public re-exports
├── client.py          # SkoolClient (SkoolAPI gateway, x-api-secret)
├── direct.py          # SkoolDirectClient (skool.com session login)
├── transport.py       # httpx wrapper: retries, pagination, JSON decode
├── errors.py          # SkoolAPIError hierarchy
├── webhooks.py        # HMAC signature verification
├── cli.py             # `skoolapp` CLI entry point
└── resources/
    ├── sessions.py    # POST /v1/sessions/
    ├── communities.py # /v1/communities
    ├── posts.py       # /v1/posts
    ├── comments.py    # /v1/posts/{id}/comments  (comments are posts!)
    ├── members.py     # /v1/members
    └── webhooks.py    # /v1/webhooks/

Every resource module is independent — the only shared surface is the Transport, which handles retries (exponential backoff on 429/5xx and network errors), cursor pagination, and JSON decoding into typed exceptions.

Testing

pip install -e .[dev]
pytest

Tests use respx to mock HTTP, so no network access is required.

Roadmap

  • Courses / classroom endpoints (SkoolAPI gap — currently only reachable via the direct client).
  • Async client flavor (SkoolAsyncClient) built on httpx.AsyncClient.
  • Typed response models via pydantic once the gateway schemas stabilize.

License

MIT. See LICENSE.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages