ProfitPulse

FinTechIntermediateJan 13, 2026

ProfitPulse

Unify your indie product revenue. See all your income streams in one dashboard.

The Problem

Indie hackers, solo founders, and small teams often juggle multiple income sources from various platforms like Stripe, Gumroad, Lemon Squeezy, App Store Connect, and PayPal. Manually tracking and consolidating these disparate revenue streams into a single, cohesive view is a significant, time-consuming pain point. They waste hours each month exporting CSVs, battling inconsistent data formats, and building complex spreadsheets just to understand their overall financial health. This fragmentation leads to missed insights into product performance, difficulties in financial planning, and increased stress during tax season. Existing comprehensive accounting software is typically overkill and prohibitively expensive for their scale, leaving the budget-conscious indie creator underserved and struggling with basic revenue aggregation.

The Solution

ProfitPulse provides a simple, elegant solution to consolidate all your digital product revenue streams into one intuitive dashboard. Users securely connect their various payment platforms (Stripe, Gumroad, Lemon Squeezy, etc.) via API keys or OAuth. ProfitPulse then automatically pulls transaction data, normalizes it, and presents a clear, real-time overview showing total revenue, revenue by platform, and monthly trends. Core features include a centralized, filterable transaction feed, customizable reporting for specific date ranges, and high-level net income summaries. Its unique value lies in its laser focus on revenue aggregation for indie builders, offering a simpler, more affordable, and less overwhelming alternative to complex accounting suites.

Tech Stack

Frontend
Next.js 14ReactTailwind CSSShadcn/UIRecharts
Backend
Next.js API RoutesServer Actions
Database
PostgreSQL (Supabase)
APIs
Stripe APIGumroad APILemon Squeezy APIClerk.com APIResend API

System Architecture

Database Schema

-- Users table for authentication and profile management
CREATE TABLE public.users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  email TEXT UNIQUE NOT NULL,
  name TEXT,
  avatar_url TEXT,
  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);

-- Accounts table to store connections to external platforms
CREATE TYPE platform_enum AS ENUM ('stripe', 'gumroad', 'lemonsqueezy', 'paypal');
CREATE TABLE public.accounts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
  platform platform_enum NOT NULL,
  -- Sensitive credentials should be encrypted at the application level before storing
  access_token TEXT NOT NULL, 
  refresh_token TEXT, -- Optional, for OAuth flows
  credentials_json JSONB, -- For platform-specific keys or settings
  last_synced_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_accounts_user_id ON public.accounts(user_id);

-- Transactions table to store normalized transaction data from all platforms
CREATE TYPE transaction_type_enum AS ENUM ('sale', 'refund', 'chargeback');
CREATE TYPE transaction_status_enum AS ENUM ('completed', 'pending', 'failed');
CREATE TABLE public.transactions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
  account_id UUID NOT NULL REFERENCES public.accounts(id) ON DELETE CASCADE,
  platform platform_enum NOT NULL,
  external_transaction_id TEXT NOT NULL, -- Original transaction ID from the platform
  amount NUMERIC(12, 2) NOT NULL, -- Stored as cents or base unit, e.g., 1000 for $10.00
  currency CHAR(3) NOT NULL, -- ISO 4217 currency code, e.g., 'USD'
  type transaction_type_enum NOT NULL,
  status transaction_status_enum NOT NULL,
  description TEXT,
  transaction_date TIMESTAMPTZ NOT NULL,
  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now(),
  UNIQUE(account_id, external_transaction_id) -- Ensure no duplicate transactions per account
);
CREATE INDEX idx_transactions_user_id ON public.transactions(user_id);
CREATE INDEX idx_transactions_account_id ON public.transactions(account_id);
CREATE INDEX idx_transactions_date ON public.transactions(transaction_date DESC);

-- Reports table (optional, for caching or saving specific report configurations)
CREATE TABLE public.reports (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
  name TEXT NOT NULL,
  config_json JSONB, -- Stores parameters used to generate the report
  generated_at TIMESTAMPTZ DEFAULT now()
);

API Endpoints

POST/api/auth/callbackHandles authentication callbacks from Clerk.com after a user signs in/up.
GET/api/userRetrieves the authenticated user's profile information.
GET/api/accountsLists all connected payment accounts for the current user.
POST/api/accountsInitiates the connection process for a new payment platform (e.g., OAuth for Stripe, save API key for Gumroad).
DELETE/api/accounts/{id}Disconnects a specific payment account by its ID.
GET/api/transactionsFetches a paginated list of all aggregated transactions, with optional filters for platform, date range, and transaction type.
POST/api/transactions/syncTriggers a manual synchronization of transaction data from all connected accounts or a specific account.
GET/api/dashboard/summaryProvides aggregated financial metrics for the dashboard, including total revenue, monthly trends, and revenue breakdown by platform.
GET/api/reportsLists previously generated or saved reports (if applicable).
POST/api/reports/export-csvGenerates and returns a CSV export of filtered transaction data.
šŸ¤–

Start Building with AI

Copy this prompt for Cursor, v0, Bolt, or any AI coding assistant

šŸ‘·

...

builders copied today

Found this useful? Share it with your builder friends!

BD

BuilderDaily Team

Verified

Indie hackers and full-stack engineers creating validated Micro-SaaS blueprints with production-ready tech stacks.

FinTech
Code TestedSchema ValidatedProduction Ready
Coming Soon in Beta

Gap Alert

Today's gap expires in ~14 hours

Get tomorrow's blueprint delivered to your inbox so you never miss a profitable idea.

(Email delivery launching soon — sign up to be first!)

No spam, ever•Unsubscribe anytime