API Reference

Base URL: https://firmhound.com (or http://localhost:3877 for development)

Health & Status

GET /health
Basic health check. Returns 200 if the server is running.
{"status": "ok", "service": "firmhound-portfolio", "ts": 1776526873502}
GET /status
Operational overview: product count, active sources, alert count, last scrape, uptime.
{"status": "operational", "products": 14, "activeSources": 9, "totalAlerts": 226, ...}

Products

GET /products
List all 14 products with public fields (name, domain, tagline, pricing, accent color).
GET /products/:id
Get a single product by ID.

Alert Preview

GET /preview/:productId
5 most recent alert titles and summaries (200 chars) for a product. No auth required. Used by product landing pages.

Waitlist

POST /waitlist
Join the waitlist for a coming-soon product.
BodyTypeDescription
emailstringValid email address
productIdstringProduct ID (e.g., "senatortrades")

Authentication

POST /auth/signup
Create an account. Returns JWT token. Rate limited: 5 signups/hour per IP.
BodyTypeDescription
emailstringValid email address
passwordstring8+ characters
{"token": "eyJ...", "user": {"id": "...", "email": "user@example.com"}}
POST /auth/login
Login. Rate limited: 10 attempts/minute per IP.
GET /auth/me JWT
Get current user profile, subscriptions, and preferences.

Preferences

GET /auth/preferences JWT
Get notification preferences (digest_frequency, timezone).
PUT /auth/preferences JWT
Update notification preferences.
BodyTypeOptions
digest_frequencystring"immediate" | "daily" | "weekly"
timezonestringIANA timezone (e.g., "America/New_York")

Alerts

GET /alerts JWT
Get alerts for products the user subscribes to. Returns enriched content.
QueryTypeDescription
product_idstringFilter by product (optional)
limitnumberMax results, 1-100 (default 50)

Billing

POST /billing/checkout JWT
Create a Stripe checkout session for a product subscription.
BodyTypeDescription
productIdstringProduct ID to subscribe to
{"url": "https://checkout.stripe.com/...", "sessionId": "cs_..."}
POST /billing/cancel JWT
Cancel an active subscription.
GET /billing/subscriptions JWT
List all subscriptions for the authenticated user.

Scraping (Internal)

POST /scrape/:productId Internal Key
Trigger a single product scraper. Header: X-Internal-Key
POST /scrape/all Internal Key
Run all scrapers in parallel batches of 4. Returns aggregate results.

Digest (Internal)

POST /digest Internal Key
Send email digests of undelivered alerts to all subscribers.

Admin (Internal)

GET /admin/stats Internal Key
Dashboard statistics: alert counts, user counts, runs, per-product breakdown.
GET /scrape-runs Internal Key
Recent scrape run history (last 50).