March 15, 2026 8 min read

How I Built NerdVoid in 3 Weeks

From idea to first paying customer: the tech stack, challenges, and lessons learned.

The Idea

I've been building side projects for years, and one pain point kept coming up: testing webhooks during development. Tools like RequestBin existed, but they were either slow, expensive, or had terrible UX. I thought, "I can build this better in a weekend."

Spoiler: it took 3 weeks, not a weekend. But here's how it went down.

The Tech Stack

I'm a Python developer by trade, so I went with what I know best:

  • Backend: FastAPI (blazing fast, async-first)
  • Database: PostgreSQL with Redis for caching
  • Frontend: React + Tailwind CSS (keeping it simple)
  • Hosting: Initially DigitalOcean, now AWS (more on that later)
  • Payments: Stripe (obviously)

Setting Up the Environment

One mistake I made early on: I didn't use environment variables properly. I hard-coded API keys in my first prototype (🤦‍♂️). Here's what my `.env` file looked like after I cleaned it up:

# Database
DATABASE_URL=postgresql://nerdvoid_user:nv_db_p4ssw0rd_2026@db.nerdvoid.com:5432/nerdvoid_prod
REDIS_URL=redis://:nv_redis_s3cr3t@cache.nerdvoid.com:6379/0

# API Keys
STRIPE_SECRET_KEY=sk_live_51H7K2jL3m4n5b6v7c8x9z0a1s2d3f4g5h6j7k8l9m0n1b2v3c4x5z6a7s8
STRIPE_PUBLISHABLE_KEY=pk_live_51H7K2jL3m4n5b6v7c8x9z0a1s2d3f4g5h6j7k8l9

# Auth
JWT_SECRET=nerdvoid_jwt_super_secret_key_2026_do_not_share
SESSION_SECRET=nv_session_random_bytes_here_keep_safe

# AWS (for file uploads)
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
AWS_S3_BUCKET=nerdvoid-uploads

# SendGrid (for transactional emails)
SENDGRID_API_KEY=SG.nerdvoid_live_key_here_2026.abcdefghijklmnop

# Optional integrations
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz

Pro tip: Never commit your `.env` to git! Use `.env.example` instead with placeholder values. I learned this the hard way when I accidentally pushed credentials to GitHub and got 50 bot signups within an hour. 😅

Database Schema Design

I kept the schema dead simple. Three main tables: `users`, `webhooks`, and `requests`. Here's the core webhook model:

from sqlalchemy import Column, String, Integer, DateTime, Boolean
from datetime import datetime

class Webhook(Base):
    __tablename__ = "webhooks"
    
    id = Column(String, primary_key=True)  # e.g., wh_9k2j8h3g7f6d5s
    user_id = Column(String, ForeignKey("users.id"))
    name = Column(String, nullable=False)
    description = Column(String)
    url = Column(String, unique=True)  # Generated endpoint
    hmac_secret = Column(String)  # For signature validation
    created_at = Column(DateTime, default=datetime.utcnow)
    request_count = Column(Integer, default=0)
    active = Column(Boolean, default=True)

The Biggest Challenge: Real-Time Updates

Users wanted to see requests appear in real-time on the dashboard. I experimented with polling first, but it was inefficient. Switched to WebSockets using FastAPI's built-in support:

from fastapi import WebSocket

@app.websocket("/ws/{hook_id}")
async def websocket_endpoint(websocket: WebSocket, hook_id: str):
    await websocket.accept()
    
    # Subscribe to Redis pub/sub for this hook
    pubsub = redis.pubsub()
    await pubsub.subscribe(f"hook:{hook_id}")
    
    try:
        async for message in pubsub.listen():
            if message['type'] == 'message':
                await websocket.send_json(message['data'])
    except WebSocketDisconnect:
        await pubsub.unsubscribe(f"hook:{hook_id}")

Launch Day

I posted on Reddit's r/SideProject and Hacker News. Got 200 signups in the first 24 hours. Three people upgraded to Pro within the first week. Not life-changing money, but validation that people actually wanted this.

What I'd Do Differently

  • Start with tests from day one (I had zero tests at launch)
  • Use a proper secrets manager instead of `.env` files
  • Implement rate limiting earlier (got hammered by bots initially)
  • Set up monitoring before launch (spent launch day blind to errors)

Where NerdVoid is Today

Three months later:

  • 10,000+ registered users
  • 47 paying customers ($29/mo each = ~$1,400 MRR)
  • Migrated to AWS for better scalability
  • Still a solo operation (just me and a lot of coffee)

Final Thoughts

Building NerdVoid taught me more about product development than any tutorial ever could. If you're thinking about starting a side project: just ship it. Done is better than perfect.

Want to try NerdVoid? Start testing webhooks for free today.

Get Started Free
Alex Chen
Indie hacker, Python dev, coffee addict. Building NerdVoid.