PolicyJar CRM
Full-featured insurance CRM and call center dialer, now being productized as a self-serve SaaS targeting Medicare/ACA insurance agencies.
Tech Stack
- Framework: Next.js 16, TypeScript, Tailwind CSS 4, shadcn/ui
- Database: Supabase (Postgres + Auth)
- Voice/SMS: Telnyx (WebRTC softphone, call control API, SMS, IVR)
- Billing: Stripe (subscriptions + metered minutes)
- Hosting: Vercel (production) — stays on Vercel, NOT migrating to Cloudflare
URLs & Repos
- Production: crm.policyjar.com
- Sales page: policyjar-site.pages.dev (Cloudflare Pages)
- Repo: coydevs/policyjar (GitHub, private, branch protection, PR workflow)
- Supabase Production: ovhaygdwyitwodbweobi
SaaS Pricing
| Plan | Price | Minutes |
|---|---|---|
| Starter | $29/agent/mo | $0.018/min |
| Growth | $49/agent/mo | $0.015/min |
| Agency | $79/agent/mo | $0.012/min |
Key Features
- Softphone — Telnyx WebRTC with real-time call control
- IVR builder — Visual IVR flow editor
- Lead CRM — Assignment, routing, tracking, dispositions
- Queues — Call queue management, skill-based routing
- Live wallboard — Real-time agent/queue metrics
- Voicemail — Voicemail inbox, playback, voicemail drop
- Call recording — Automatic recording + transcription-ready
- Compliance — DNC list, calling hours, holiday scheduling
- Reports/Analytics — Call metrics, lead conversion, campaign performance
- Team management — Invites, roles, permissions
- Agent presence — Persistent agent status (30s heartbeat, 60s expiry)
- Stripe billing — Self-serve checkout, customer portal, metered usage
Architecture
- Next.js App Router with Supabase RLS for multi-tenant isolation
tenant_idon all tables — full data isolation per agency- Telnyx Call Control API (CCA) for call routing and bridging
- Webhook-based call event processing
is_internal = TRUEon the me@coy.gg tenant — bypasses all billing gates
Multi-Tenant Schema
tenantstable: plan, seats_purchased, status, stripe_customer_id, stripe_subscription_id, trial_ends_at, is_internal- All tables have
tenant_idforeign key - RLS policies enforce per-tenant isolation
Stripe Billing (PR #59)
Branch: feature/stripe-billing-saas
| File | Purpose |
|---|---|
src/lib/stripe.ts |
Stripe singleton (null if key not set) |
src/lib/seats.ts |
Seat availability check |
src/lib/usage.ts |
Metered minute reporting |
src/app/api/billing/checkout/route.ts |
Stripe Checkout session |
src/app/api/billing/portal/route.ts |
Stripe Customer Portal |
src/app/api/billing/webhook/route.ts |
Subscription lifecycle events |
src/app/(app)/settings/billing/page.tsx |
Billing UI |
supabase/migrations/015_stripe_billing.sql |
Stripe columns on tenants |
supabase/migrations/016_internal_account.sql |
is_internal flag |
Required env vars (add to Vercel before merging):
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_STARTER_PRICE_ID=price_...
STRIPE_GROWTH_PRICE_ID=price_...
STRIPE_AGENCY_PRICE_ID=price_...
Competitor: EnrollHere (enrollhere.com)
Enterprise-focused insurance dialer (150+ agencies, Medicare/senior market, sales-led, no public pricing). PolicyJar differentiates via: self-serve signup, transparent pricing, Quote & Enroll in-call.
SaaS Roadmap
| Phase | Features | Status |
|---|---|---|
| Phase 1 | org_id isolation ✅, Stripe billing (PR #59), self-serve signup, auto-provision Telnyx DID | In progress |
| Phase 2 | Outbound dialer, lead import, recording, reporting, voicemail drop | Planned |
| Phase 3 | Quote & Enroll (CMS Plan Finder + HealthSherpa API), commissions, TCPA compliance | Planned |
Cron Jobs
| Job | Schedule | Action |
|---|---|---|
| pr-auto-merge | Every 1h (Sonnet) | Auto-merges approved PRs |
| nightly backup | 3 AM EST | Database backup |
Deployment
Platform: Vercel (auto-deploy from GitHub master)
PR Workflow: branch → PR → Greptile review → auto-merge at 4/5+ → deploy
Known Issues / Tech Debt
- SMS callback not implemented
- Rate limiter is in-memory (needs Redis for scale)
- Stripe billing not merged to master yet (awaiting price ID setup)