puckapi
v0.1.0
Published
The hockey data API. Stats, odds, and everything between. REST API + MCP server.
Maintainers
Readme
PuckAPI
The hockey data API. Stats, odds, and everything between. REST API + MCP server.
Architecture
Two services, one database:
- Next.js app (Vercel) -- public site, dashboard, auth, billing, playground
- MCP server (Railway) -- 12 data tools, API key auth, credit metering
- Neon Postgres -- shared database
Stack
- Next.js 15 (App Router) + Tailwind CSS
- Better Auth (email/password + email verification)
- Stripe (subscriptions + wallet deposits + customer portal)
- Resend (transactional email)
- Drizzle ORM + Neon Postgres
- MCP SDK (Streamable HTTP transport)
Local Development
# Install
npm install
# Set up environment
cp .env.example .env
# Fill in DATABASE_URL, BETTER_AUTH_SECRET, STRIPE_SECRET_KEY, etc.
# Run Next.js dev server
npm run dev:web
# Run MCP server (separate terminal)
npm run dev
# Build
npm run build:web # Next.js
npm run build # MCP server (tsc)
# Test
npm test # 88 integration tests
# Database
npm run db:generate # Generate Drizzle migrations
npm run db:migrate # Apply migrationsData Pipeline
npm run backfill:games # Games from NHL API
npm run backfill:odds # Odds from The Odds API
npm run backfill:rosters # Player rosters
npm run backfill:goalies # Goalie stats
npm run backfill:standings # Team standings
npm run daily-update # Daily refresh (also runs via GitHub Actions)MCP Endpoint
Production: https://mcp.puckapi.com/mcp
Requires API key via x-api-key header or Authorization: Bearer header.
12 Endpoints
| Credits | Endpoints |
|---------|-----------|
| 1 | list_teams |
| 2 | get_standings, get_schedule, search_players |
| 5 | get_games, get_team_stats, get_player_stats, get_goalie_stats |
| 10 | get_odds, get_game_detail, get_head_to_head |
| 25 | get_line_movement |
Billing
- Free tier: 500 credits on signup
- Subscriptions: Starter ($19/mo, 10K credits), Pro ($49/mo, 30K credits), Scale ($149/mo, 125K credits)
- Wallet deposits: $5 to $500, 400 credits per dollar, never expire
- Monthly credits reset each period and are consumed first. Wallet credits are permanent.
Metering
The MCP server supports METERING_MODE:
enforced-- charges credits, refunds on tool errors, serializable transactionsshadow-- records lifecycle data without chargingoff-- bypasses metering for local debugging
Idempotency: pass x-idempotency-key or x-request-id to make retries duplicate-safe.
Deployment
- Next.js: Auto-deploys to Vercel on push to main
- MCP server: Auto-deploys to Railway on push to main
- Database: Neon Postgres (migrations run automatically on Railway start)
Environment Variables
See .env.example for full list. Key ones:
| Variable | Required | Description |
|----------|----------|-------------|
| DATABASE_URL | Yes | Neon Postgres connection string |
| BETTER_AUTH_SECRET | Yes | Session signing secret |
| STRIPE_SECRET_KEY | Yes | Stripe API key |
| STRIPE_PRICE_STARTER/PRO/SCALE | Yes | Stripe recurring price IDs |
| RESEND_API_KEY | Yes | Transactional email |
| INTERNAL_API_SECRET | Prod | MCP server to Next.js auth |
| MCP_SERVER_URL | Prod | Playground proxy target |
| FRONTEND_URL | Prod | Credit alert callback URL |
