An unofficial REST API for announcements published by APJ Abdul Kalam Technological University (KTU). Built with FastAPI, Camoufox, and GitHub Actions.
Disclaimer: This is an independent, community-maintained project and is not affiliated with, endorsed by, or connected to APJ Abdul Kalam Technological University.
- Base URL: https://ktu-announcements-api-wxk8.onrender.com
- Interactive Documentation: https://ktu-announcements-api-wxk8.onrender.com/docs
| Endpoint | Method | Description |
|---|---|---|
/announcements |
GET | List all cached announcements |
/announcements?limit=5 |
GET | Limit response to the latest N records |
/announcements?new_only=true |
GET | Filter records flagged as new |
/announcements?scheme=2019 |
GET | Filter records by scheme (2015, 2019, 2024, or General) |
/announcements/{id} |
GET | Retrieve a single announcement by ID |
/download/{encrypt_id} |
GET | Download an announcement attachment (pre-cached PDF) |
/health |
GET | Service status and cache timestamp |
/refresh |
GET | Dispatch on-demand scraper run (requires secret, 10m cooldown) |
/api/sync |
POST | Webhook for scraper data ingestion (requires X-Sync-Secret) |
/docs |
GET | OpenAPI / Swagger UI documentation |
The service uses a decoupled architecture to operate reliably within constrained container environments (such as Render's 512 MB free tier):
+---------------------------------------+
| GitHub Actions Runner |
| - Runs every 30m / on-demand |
| - Headless Camoufox browser |
| - Solves Cloudflare Turnstile |
| - Intercepts API response & token |
| - Pre-fetches PDF attachments |
+-------------------+-------------------+
|
| POST /api/sync (X-Sync-Secret)
v
+---------------------------------------+
| FastAPI Application |
| - Render web service (~38 MB RAM) |
| - In-memory data & PDF cache |
| - Sub-20ms response times |
| - Rate-limited /refresh endpoint |
+---------------------------------------+
- Scraping: GitHub Actions executes Camoufox in a headless environment every 30 minutes, completing the Turnstile verification and capturing KTU's announcements payload and auth token.
- Attachment Pre-caching: While the Turnstile token is valid, the runner downloads all attached documents, encodes them in base64, and syncs the entire payload to the API server via
/api/sync. - API Serving: The FastAPI application holds the latest announcements and attachments in memory, serving requests in milliseconds without executing a browser process or triggering remote calls on download.
- On-Demand Refresh: The
/refreshendpoint dispatches the GitHub Actions scraper workflow via the GitHub API. Access is protected by a shared secret and enforced by a mandatory 10-minute cooldown window.
Get all announcements:
curl https://ktu-announcements-api-wxk8.onrender.com/announcementsFilter by scheme:
curl "https://ktu-announcements-api-wxk8.onrender.com/announcements?scheme=2019"Filter new announcements:
curl "https://ktu-announcements-api-wxk8.onrender.com/announcements?new_only=true"Fetch a single announcement:
curl https://ktu-announcements-api-wxk8.onrender.com/announcements/1234Download an attachment (saves with the original filename):
curl -O -J https://ktu-announcements-api-wxk8.onrender.com/download/{encrypt_id}Trigger an on-demand refresh:
curl -H "Authorization: Bearer YOUR_SYNC_SECRET" \
https://ktu-announcements-api-wxk8.onrender.com/refreshCheck service health:
curl https://ktu-announcements-api-wxk8.onrender.com/healthRuns the FastAPI service without browser dependencies:
git clone https://github.com/ratherpixelate/ktu-announcements-api.git
cd ktu-announcements-api
# Install dependencies
uv sync
# or: pip install -r requirements.txt
# Start API server
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000To populate the local cache, run the scraper script against localhost:
RENDER_API_URL="http://localhost:8000" SYNC_SECRET="local_dev" uv run python scripts/sync_to_render.pyRuns both the API and scheduled Camoufox scraping within the same process via APScheduler:
ENABLE_IN_CONTAINER_SCRAPER=true uv run uvicorn app.main:app --port 8000docker build -t ktu-announcements-api .
docker run -p 8000:8000 -e PORT=8000 ktu-announcements-api| Variable | Description | Required For |
|---|---|---|
SYNC_SECRET |
Shared secret to authorize /api/sync and /refresh |
Production deployment |
GITHUB_PAT |
GitHub Personal Access Token (repo scope) |
On-demand /refresh dispatch |
GITHUB_REPO |
Target repository in owner/repo format |
On-demand /refresh dispatch |
RENDER_API_URL |
Destination API URL for the sync payload | GitHub Actions scraper |
ENABLE_IN_CONTAINER_SCRAPER |
Enables internal APScheduler background scraping | Standalone mode |
PORT |
HTTP server port (defaults to 8000) |
Container deployment |
This project is licensed under the MIT License.