TierLock
TierLock
Developer-first API for effortless SaaS feature gating.
Solo developers and small SaaS teams often struggle to implement robust feature gating based on subscription plans. After integrating Stripe for payments, they're left to build complex, error-prone custom logic within their application to determine what features a user can access. This involves manual checks against Stripe webhooks, managing trial states, and mapping product features to different subscription tiers. This process is time-consuming, wasting an estimated 5-10 hours per feature change, and can lead to inconsistent user experiences or security vulnerabilities if not done perfectly. There's no single source of truth for feature entitlements, forcing developers to scatter access logic throughout their codebase. This directly impacts time-to-market for new features and makes pricing experiments cumbersome and risky, losing potential revenue from delayed launches.
TierLock provides a simple, developer-first API and dashboard to define your SaaS features and link them declaratively to subscription tiers. Instead of writing custom `if/else` logic everywhere, developers can make a single, authenticated `tierlock.hasAccess('feature_name', user_id)` API call. The intuitive dashboard allows defining features (e.g., 'Unlimited Projects', 'AI Integrations'), linking them to specific Stripe plan IDs, and managing trial periods or custom entitlements. It integrates seamlessly with existing authentication systems (e.g., NextAuth.js, Supabase Auth) and Stripe webhooks to keep entitlements in real-time sync. TierLock's unique differentiator is its laser focus purely on *feature access as a service*, abstracting away the boilerplate of subscription state management, rather than being a full billing system. This empowers solo developers to ship faster, experiment confidently with pricing, and maintain a clean, scalable codebase.
Tech Stack
System Architecture
+-----------------------+ +-----------------------+
| Client | | TierLock Dashboard |
| (Your SaaS Application)| | (Admin Web UI) |
+-----------+-----------+ +-----------+-----------+
| 1. Has Access API | 2. Feature/Plan Mgmt
| | 3. Customer Data
V V
+-----------+-----------------------------------+
| Next.js API Routes / Server Actions|
| (TierLock Backend) |
+-----------------------+-----------------------+
| â–² â–² | |
| | | | 4. Supabase Auth |
| | | | 5. Resend API Calls |
| | | | |
| | | V V
+--------+ | -------- +-------------------------------------+
| Supabase (PostgreSQL Database, Auth, Storage) |
+----------+-----------------------------------------------+
| â–²
| 6. Stripe API (Plan Details) | 7. Stripe Webhook (Subscription Events)
V |
+----------+-----------+ |
| Stripe | |
| (Payments & Subscriptions)------------------+
+-----------------------+Database Schema
-- For TierLock's own users/admins (using Supabase Auth)
-- CREATE TABLE auth.users ... (managed by Supabase)
-- Customers of the SaaS applications using TierLock
CREATE TABLE customers (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
external_user_id TEXT UNIQUE NOT NULL, -- The user ID from the client's own auth system (e.g., their own auth.users.id)
stripe_customer_id TEXT UNIQUE, -- Stripe Customer ID
email TEXT UNIQUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE customers IS 'Represents the end-users of SaaS applications using TierLock.';
COMMENT ON COLUMN customers.external_user_id IS 'The unique ID of the user from the client''s own authentication system.';
-- Defined features that can be gated
CREATE TABLE features (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name TEXT UNIQUE NOT NULL, -- e.g., 'unlimited_projects', 'ai_integration'
description TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_features_name ON features (name);
COMMENT ON TABLE features IS 'Defines all possible features that can be gated by TierLock.';
-- Subscription Plans (corresponding to Stripe Product/Price IDs)
CREATE TABLE plans (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
stripe_price_id TEXT UNIQUE NOT NULL, -- Stripe Price ID (recurring price)
stripe_product_id TEXT, -- Stripe Product ID
name TEXT NOT NULL, -- e.g., 'Free', 'Pro', 'Enterprise'
description TEXT,
tier_level INT DEFAULT 0, -- For ordering/hierarchy (e.g., 0=Free, 1=Pro, 2=Enterprise)
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_plans_stripe_price_id ON plans (stripe_price_id);
COMMENT ON TABLE plans IS 'Defines subscription plans, linked to Stripe Price IDs.';
-- Junction table for features and plans (which features are included in which plan)
CREATE TABLE plan_features (
plan_id UUID NOT NULL REFERENCES plans(id) ON DELETE CASCADE,
feature_id UUID NOT NULL REFERENCES features(id) ON DELETE CASCADE,
max_value INT, -- Optional: for features with limits (e.g., max_projects=10)
PRIMARY KEY (plan_id, feature_id)
);
COMMENT ON TABLE plan_features IS 'Links features to plans, defining which features each plan includes.';
-- Customer Subscriptions (linking customers to their active Stripe subscriptions)
CREATE TABLE customer_subscriptions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
customer_id UUID NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
plan_id UUID NOT NULL REFERENCES plans(id), -- The plan they are subscribed to
stripe_subscription_id TEXT UNIQUE NOT NULL, -- Stripe Subscription ID
status TEXT NOT NULL, -- e.g., 'active', 'trialing', 'canceled', 'past_due'
current_period_start TIMESTAMP WITH TIME ZONE,
current_period_end TIMESTAMP WITH TIME ZONE,
trial_start TIMESTAMP WITH TIME ZONE,
trial_end TIMESTAMP WITH TIME ZONE,
cancel_at_period_end BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE (customer_id, stripe_subscription_id) -- A customer might have multiple subscriptions if a complex use case
);
CREATE INDEX idx_customer_subscriptions_customer_id ON customer_subscriptions (customer_id);
CREATE INDEX idx_customer_subscriptions_stripe_subscription_id ON customer_subscriptions (stripe_subscription_id);
COMMENT ON TABLE customer_subscriptions IS 'Tracks active subscriptions for customers, linked to Stripe.';
COMMENT ON COLUMN customer_subscriptions.status IS 'Status of the subscription from Stripe (e.g., active, trialing, canceled).';
-- Webhook events for auditing/debugging
CREATE TABLE webhook_events (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
event_id TEXT UNIQUE NOT NULL, -- Stripe event ID
event_type TEXT NOT NULL, -- e.g., 'customer.subscription.updated'
payload JSONB NOT NULL,
processed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_webhook_events_event_id ON webhook_events (event_id);
COMMENT ON TABLE webhook_events IS 'Stores incoming Stripe webhook events for processing and auditing.';
-- Optional: Custom entitlements/overrides for specific customers
CREATE TABLE custom_entitlements (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
customer_id UUID NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
feature_id UUID NOT NULL REFERENCES features(id) ON DELETE CASCADE,
has_access BOOLEAN NOT NULL DEFAULT TRUE,
max_value INT, -- Override plan''s max_value
expires_at TIMESTAMP WITH TIME ZONE, -- Temporary access
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE (customer_id, feature_id)
);
COMMENT ON TABLE custom_entitlements IS 'Allows overriding plan-based feature access for individual customers.';API Endpoints
/api/auth/callbackHandles authentication callbacks from Supabase Auth./api/featuresRetrieves all defined features for the dashboard./api/featuresCreates a new feature in the system (for dashboard)./api/plansRetrieves all defined subscription plans for the dashboard./api/plansCreates a new plan, linking it to a Stripe Price ID (for dashboard)./api/plans/[planId]/featuresLinks a specific feature to a plan (for dashboard)./api/plans/[planId]/features/[featureId]Unlinks a feature from a plan (for dashboard)./api/customersCreates or updates a customer in TierLock, used by the client's SaaS to register users./api/customer/[externalUserId]/has-accessChecks if a specific user (identified by externalUserId) has access to a given feature. Core public API./api/customer/[externalUserId]/entitlementsRetrieves all features and their access status for a specific user. Public API./api/webhooks/stripeReceives and processes Stripe webhook events (e.g., subscription changes) to update customer entitlements.Start Building with AI
Copy this prompt for Cursor, v0, Bolt, or any AI coding assistant
BuilderDaily Team
VerifiedIndie hackers and full-stack engineers creating validated Micro-SaaS blueprints with production-ready tech stacks.
Related Blueprints
More Micro-SaaS ideas you might like to build
API CostPilot
Real-time API expense tracking, forecasting, and optimization for developers.
EcoContent Auditor
Analyze and reduce the digital carbon footprint of your website content.
ClientFlow Metrics
Custom client progress tracking for health & wellness practitioners.
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!)