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.
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 gateway — https://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.
pip install -e .[dev]Python 3.9+.
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.
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.",
)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.createdOutput is JSONL for list commands and pretty JSON for single-object
commands, so you can pipe it straight into jq.
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.
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.
pip install -e .[dev]
pytestTests use respx to mock HTTP, so
no network access is required.
- Courses / classroom endpoints (SkoolAPI gap — currently only reachable via the direct client).
- Async client flavor (
SkoolAsyncClient) built onhttpx.AsyncClient. - Typed response models via
pydanticonce the gateway schemas stabilize.
MIT. See LICENSE.