Skip to content

Plugins

shaapi ships a small core and lets you pull in extra features only when you need them — the opposite of frameworks that load every module at startup.

A plugin is a self-contained blueprint. shaapi add <name> copies it into your project under backend/plugins/<name>/; from then on it's your code (read it, edit it). Its router is auto-discovered — nothing loads unless you add it, so your build only contains what you chose.

Commands

shaapi list-plugins          # see the catalog
shaapi add advanced_auth     # copy a plugin into backend/plugins/
shaapi remove advanced_auth  # remove it

add also injects any Python dependencies the plugin needs into your pyproject.toml and refreshes uv.lock, so it builds out of the box. After adding, reload the API (shaapi restart api) or rebuild.

In development the plugin's tables auto-create on startup. For production, generate a migration: shaapi db generate --message "add <plugin>".

Available plugins (v0.3.2)

Plugin What it does Endpoints (under /admin/api/v1)
webhooks Register subscriptions, emit HMAC-signed events to URLs /webhooks
advanced_audit Application audit trail (who did what, on what) /audit/logs
advanced_auth TOTP multi-factor auth on top of the built-in users /auth/mfa
user_analytics Track events, query aggregated stats /analytics
payment Payments via a pluggable provider (Stripe included) /payments

All endpoints are JWT-protected. Each plugin also exposes a service you can call from your own code (e.g. audit_service.record(...), webhook_service.emit(...)).

More coming

This is a starter set. Tell us which plugins you need next — the catalog grows based on what the community actually uses.

Writing your own plugin

A plugin is just a folder under backend/plugins/<name>/ that exposes a router in its router module — exactly like the feature you build in the tutorial:

backend/plugins/myplugin/
├── __init__.py        # from backend.plugins.myplugin.router import router
├── models.py          # SQLAlchemy models
├── schemas.py         # Pydantic schemas
├── service.py         # business logic
└── router.py          # APIRouter named `router`

That's all the auto-discovery needs. Once the folder is there, the API loads it on the next restart.