Middleware that listens for pretix webhook notifications and posts formatted order summaries to a Discord channel via webhook.
When a new order is placed in pretix, this service:
- Receives the webhook POST from pretix
- Fetches the full order details from the pretix REST API
- Formats a Discord embed with order code, total, buyer email, and purchased products
- Sends the embed to a Discord channel via webhook
The pipeline is orchestrated by Temporal, which provides automatic retries and durable execution. If Discord is temporarily unavailable, the notification is delivered when it recovers.
flowchart LR
pretix -- "webhook POST" --> FastAPI
FastAPI -- "starts workflow" --> Temporal
Temporal --> fetch["Fetch order from pretix"]
fetch --> format["Format embed"]
format --> send["Send to Discord"]
Services (all run via Docker Compose):
| Service | Description |
|---|---|
caddy |
Reverse proxy, automatic HTTPS via Let's Encrypt |
temporal |
Temporal dev server with persistent SQLite |
worker |
Temporal worker executing activities |
web |
FastAPI app receiving pretix webhooks |
Source layout:
src/pretix_discord/
├── api.py # FastAPI app (POST /webhook, GET /health)
├── config.py # Settings loaded from environment variables
├── discord_activities.py # Format embed, send Discord webhook
├── main.py # FastAPI/uvicorn entrypoint
├── models.py # All dataclasses (orders, embeds, inputs)
├── pretix_activities.py # Fetch and parse pretix orders
├── worker.py # Temporal worker entrypoint
└── workflow.py # Workflow: fetch -> format -> send
- A server with Docker installed
- A domain name pointed at the server (for HTTPS)
- A pretix API token (docs)
- A Discord webhook URL (docs)
Copy the example environment file and fill in your values:
cp .env.example .env| Variable | Description |
|---|---|
PRETIX_API_TOKEN |
API token from your pretix organizer account |
DISCORD_WEBHOOK_URL |
Full Discord webhook URL for the target channel |
DOMAIN |
Public domain for this service (used by Caddy for TLS) |
| Variable | Default | Description |
|---|---|---|
PRETIX_BASE_URL |
https://pretix.eu/api/v1 |
pretix API base URL |
TEMPORAL_ADDRESS |
temporal:7233 |
Temporal server address |
TEMPORAL_NAMESPACE |
default |
Temporal namespace |
TEMPORAL_TASK_QUEUE |
pretix-discord |
Temporal task queue name |
Any VPS with Docker works. On a fresh Ubuntu/Debian server:
curl -fsSL https://get.docker.com | shgit clone https://github.com/PyTexas/pretix-discord.git
cd pretix-discord
cp .env.example .env
# Edit .env with your valuesCreate an A record for your domain pointing to the server's IP address. Caddy needs this to provision the TLS certificate.
docker compose up -dCaddy will automatically obtain a Let's Encrypt certificate on the first request. The services will restart automatically if the server reboots.
In your pretix organizer settings:
- Go to Settings > Webhooks
- Add a new webhook with the URL:
https://YOUR_DOMAIN/webhook - Select the Order placed event
- Save
Check that the service is running:
curl https://YOUR_DOMAIN/health
# {"status":"ok"}Check the Temporal UI at http://YOUR_SERVER_IP:8233 to monitor workflows.
uv syncjust checkThis runs formatting (ruff), tests (pytest), linting (ruff), and type checking (mypy strict).
just fmt # Format code
just test # Run tests
just lint # Lint code
just typecheck # Type check (mypy --strict)With Docker Compose running locally:
curl -X POST http://localhost:8000/webhook \
-H "Content-Type: application/json" \
-d '{
"notification_id": 99999,
"organizer": "your-organizer",
"event": "your-event",
"code": "XXXXX",
"action": "pretix.event.order.placed"
}'The workflow will appear in the Temporal UI. If the order code is valid and your tokens are configured, a Discord message will appear in the target channel.
- Health check:
GET /healthreturns{"status": "ok"} - Temporal UI: Port 8233 — view workflow history, retries, and failures
- Docker logs:
docker compose logs -f workerto watch activity execution
MIT