ZippCRM
Technical Documentation
v1.0 · April 2026
🏠

ZippCRM Overview

The purpose-built compliance CRM for Indian financial regulators

ZippCRM is a comprehensive compliance-management platform designed specifically for Fintech firms, NBFCs, insurance brokers, mutual fund distributors, and other regulated entities operating under Indian financial regulators — RBI, SEBI, IRDAI, MCA, PFRDA, and IFSCA.

The system handles the full lifecycle of regulatory engagements: client onboarding with KYC/AML checks, regulatory return filing tracking, show-cause notices, penalty management, eSign workflows, and retainer billing — all within a maker-checker governance framework.

📋

Return Filing

Track every regulatory filing deadline across RBI, SEBI, IRDAI with auto-escalation on breach.

⚖️

Penalty Engine

Auto-calculate exposure, track SCN / appeal status, and manage mitigation with maker-checker approval.

✍️

eSign / DSC

Aadhaar eSign, DSC, and OTP-based signing via Leegality, Digio, Signdesk, and NSDL.

🔍

Maker-Checker

Four-eyes approval on high-risk actions: KYC changes, penalty submissions, and key document updates.

🌐

Client Portal

Secure white-labelled portal for clients to upload documents, track status, and view invoices.

🤖

Auto Workflows

Event-driven workflow engine triggers emails, tasks, and escalations automatically.

ℹ️
Architecture at a glance Python 3.12 monolith backend · PostgreSQL 16 · Vanilla JS frontend · Docker Compose · Background scheduler (15-minute cycle)
⚙️

System Requirements

Minimum and recommended hardware and software specifications

Hardware (Self-Hosted)

Component Minimum Recommended (Production)
CPU2 vCPU4 vCPU (or 8 for >50 concurrent users)
RAM4 GB8 GB
Storage40 GB SSD200 GB SSD (NVMe preferred)
Network100 Mbps1 Gbps with static IP
OSUbuntu 22.04 LTS / Debian 12 / RHEL 9

Software Dependencies

PackageVersionPurpose
Python3.12+Backend runtime
PostgreSQL16+Primary database
Docker Engine24+Containerised deployment
Docker Composev2.20+Multi-container orchestration
Nginx1.24+Reverse proxy / TLS termination
Node.js18+ (build only)Frontend asset bundling (optional)
⚠️
PostgreSQL 15 or older is not supported. ZippCRM uses GENERATED ALWAYS AS IDENTITY columns and JSON path operators introduced in PostgreSQL 16.
🚀

Quick Start

Get ZippCRM running in under 10 minutes using Docker

1

Clone the repository

bash
git clone https://github.com/your-org/zippcrm.git
cd zippcrm
2

Start the stack

bash
docker compose up -d

This starts zippcrm-backend, zippcrm-db, and zippcrm-nginx. On the very first boot, the backend detects no .setup_complete flag and waits for the Setup Wizard — no manual .env editing required.

3

Run the Setup Wizard

Open your browser and navigate to http://localhost:3002/setup.html. The 7-step wizard guides you through all configuration — database, SMTP, license, and admin user — and writes the .env file for you. The wizard self-destructs after completion and can never be accessed again.

4

Launch the application

After the wizard completes, click Launch ZippCRM or navigate to http://localhost:3002. Log in with the admin credentials you created in the wizard.

5

Optional: Manual .env setup (advanced)

If you prefer to configure ZippCRM without the wizard — for automated deployments or CI/CD — copy the example env file and set variables directly. The wizard is skipped when DATABASE_URL is already set and a valid .setup_complete flag file exists.

bash
cp .env.example .env
# Edit .env with DATABASE_URL, SECRET_KEY, SMTP_HOST, etc.
touch backend/.setup_complete   # skip wizard on next boot
🧙

First-Run Setup Wizard

Interactive 7-step installer that configures ZippCRM without touching any files manually

On first boot, ZippCRM detects the absence of a backend/.setup_complete flag file and automatically redirects any request to frontend/setup.html. This wizard handles all configuration end-to-end — no SSH, no text editor, no manual environment variable management.

The wizard communicates via a set of unauthenticated /api/setup/* routes that are intercepted before the database connection is established, allowing them to function even when no database is configured yet.

StepNameWhat It DoesSkippable?
1Pre-flight CheckRuns 7 system checks: Python ≥ 3.12, psycopg3 importable, disk ≥ 500 MB, directories writable, DATABASE_URL preset, SECRET_KEY length ≥ 32, SMTP host configured. Fails with actionable notes per check.No (must pass critical checks)
2DatabaseSupports 8 deployment types: Docker Compose, Same Server, Remote Server, AWS RDS, Google Cloud SQL, Azure PostgreSQL, Neon/Supabase, and raw Connection URL (DSN). Tests the connection live before saving. Writes DATABASE_URL to .env.No
3ApplicationSets PORTAL_URL, auto-generates a cryptographically random SECRET_KEY (48-char), and ENVIRONMENT.No
4Email / SMTPConfigures SMTP host, port, username, password, from address. Tests TCP reachability before saving.Yes — configurable later in Admin → Email Config
5License KeyValidates and activates a ZCRM-XXXX-XXXX-XXXX-XXXX license key. Without a key the Starter plan (3 seats) is used.Yes — activatable later in Admin → License
6Admin UserCreates the first administrator account. Password strength is enforced. Cannot be skipped — at least one admin is required to complete setup.No
7CompleteWrites backend/.setup_complete flag and permanently deletes frontend/setup.html. All /api/setup/* routes return 410 Gone from this point forward.

Self-Destruct Mechanism

After the admin user is created and the wizard's Complete step finalizes:

python
# backend/setup_wizard.py — finalize_setup()
_SETUP_FLAG.touch()                         # creates backend/.setup_complete
(FRONTEND_DIR / "setup.html").unlink()      # permanently deletes setup.html

Nginx's try_files $uri /index.html handles the deleted setup.html gracefully — it falls back to index.html, which checks /api/setup/status, receives a 410 Gone, and boots the main app normally. The wizard can never be re-opened after this point, even if someone navigates to the URL.

Security Notes

All /api/setup/* routes require no authentication — by design, since no admin user exists yet. They are intercepted before the standard auth middleware in do_GET / do_POST. Once .setup_complete exists, every /api/setup/* request returns 410 Gone immediately, ensuring the unauthenticated surface disappears forever after first boot.

Database Deployment Types

Step 2 supports two input modes — Field Form (individual host / port / name / user / password / SSL mode fields) and Connection URL (paste a full postgresql:// DSN). The 8 preset types auto-fill sensible defaults, hints, and SSL requirements per provider:

TypeDefault Host ExampleSSL DefaultNotes
🐳 Docker Composepostgres or dbDisabledService name from docker-compose.yml
💻 Same ServerlocalhostDisabledPostgreSQL on the same machine as ZippCRM
🖥️ Remote Server10.0.1.50RequireSeparate VM or bare-metal; port 5432 must be reachable
☁️ AWS RDSmydb.xxxx.ap-south-1.rds.amazonaws.comRequireRDS/Aurora PostgreSQL endpoint from AWS console
🌐 Google Cloud SQLPublic or private IPRequireWorks with Cloud SQL Auth Proxy or direct IP
🔷 Azure Databaseyourserver.postgres.database.azure.comRequireUsername must be in user@servername format
⚡ Neon / Supabaseep-xxxx.us-east-2.aws.neon.techRequireServerless PostgreSQL; connection string available in dashboard
🔗 Connection URLVia DSN paramPaste full postgresql://user:pass@host:port/db?sslmode=require
🐳

Docker Setup

Compose file structure and service configuration

ZippCRM ships as a three-service Docker Compose stack. The configuration below is the canonical docker-compose.yml — copy and adjust for your environment.

yaml
version: "3.9"

services:
  db:
    image: postgres:16-alpine
    container_name: zippcrm-db
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${DB_NAME:-zippcrm}
      POSTGRES_USER: ${DB_USER:-zippcrm}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-zippcrm}"]
      interval: 10s
      retries: 5

  backend:
    build: ./backend
    container_name: zippcrm-backend
    restart: unless-stopped
    env_file: .env
    depends_on:
      db:
        condition: service_healthy
    ports:
      - "5000:5000"
    volumes:
      - ./uploads:/app/uploads

  nginx:
    image: nginx:1.25-alpine
    container_name: zippcrm-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
      - ./frontend:/usr/share/nginx/html:ro
      - ./ssl:/etc/nginx/ssl:ro

volumes:
  postgres_data:
💡
TLS in Production Mount your SSL certificates into /etc/nginx/ssl/ and use the bundled nginx/nginx-ssl.conf template. Let's Encrypt via Certbot is fully supported.
🔑

Environment Variables

All configurable runtime parameters for ZippCRM

Core

The Setup Wizard writes these automatically. When configuring manually, all variables are read from the .env file in the project root at startup.

VariableRequiredDefaultDescription
SECRET_KEYRequired32+ char random string for session token signing. The Setup Wizard auto-generates a cryptographically secure 48-char value.
ENVIRONMENTOptionaldevelopmentSet to production to enable prod guards: random seed passwords, stricter CORS headers, no debug output.
SEED_ALLOW_DEMO_PASSWORDSOptional0Set to 1 to allow predictable demo passwords in seed data even when ENVIRONMENT=production. Never use in real production.
PORTOptional5000Backend HTTP port
LOG_LEVELOptionalINFOPython log level: DEBUG / INFO / WARNING / ERROR

Database

DATABASE_URL is the primary database configuration variable — set by the Setup Wizard. The legacy DB_HOST / DB_PORT / DB_NAME / DB_USER / DB_PASSWORD individual variables are still supported for backwards compatibility but DATABASE_URL takes precedence when set.

VariableRequiredDescription
DATABASE_URLRequiredFull PostgreSQL connection string: postgresql://user:pass@host:5432/dbname. Append ?sslmode=require for cloud-managed databases. Written by the Setup Wizard.
DB_HOSTLegacyPostgreSQL host — ignored when DATABASE_URL is set
DB_PORTLegacyPostgreSQL port, default 5432
DB_NAMELegacyDatabase name
DB_USERLegacyDatabase username
DB_PASSWORDLegacyDatabase password
DB_POOL_SIZEOptionalConnection pool size, default 10

Email / SMTP

VariableDescription
SMTP_HOSTSMTP server hostname (e.g. smtp.gmail.com)
SMTP_PORTSMTP port — 587 (STARTTLS) or 465 (SSL)
SMTP_USERNAMESMTP auth username / email address
SMTP_PASSWORDSMTP auth password or app-specific password
SMTP_FROMFrom address, e.g. compliance@yourfirm.in

Licensing

VariableDescription
ZIPPCRM_LICENSE_KEYYour issued license key — activates the plan tier and seat count
LICENSE_VALIDATION_URLOverride the license validation endpoint (for air-gapped deployments)
.env — written by Setup Wizard or manually
# ── Core ──────────────────────────────────────────────────────────
SECRET_KEY=Jx9kQm2nPvYwR7tUoL5sEhDcBfAzXiGp3NqWe6yKdCuVrTlMjFbOsHa4g8Z1
ENVIRONMENT=production
# SEED_ALLOW_DEMO_PASSWORDS=1   # only for dev/staging, never production

# ── Database (written by Setup Wizard — supports any PostgreSQL host) ──
DATABASE_URL=postgresql://zippcrm:yourpassword@db:5432/zippcrm
# For cloud managed databases, append sslmode:
# DATABASE_URL=postgresql://user:pass@mydb.xxxx.ap-south-1.rds.amazonaws.com:5432/zippcrm?sslmode=require

# ── SMTP ──────────────────────────────────────────────────────────
SMTP_HOST=smtp.zoho.in
SMTP_PORT=587
SMTP_USERNAME=alerts@yourfirm.in
SMTP_PASSWORD=your-app-password
SMTP_FROM=ZippCRM <alerts@yourfirm.in>
SMTP_SECURITY=starttls

# ── Licensing ─────────────────────────────────────────────────────
ZIPPCRM_LICENSE_KEY=ZCRM-XXXX-XXXX-XXXX-XXXX
🗄️

Database Setup

Schema auto-migration, backups, and manual operations

Auto-Migration

ZippCRM applies all migrations automatically on startup via the init_db() function in backend/app.py. There is no separate migration tool — all schema changes use CREATE TABLE IF NOT EXISTS and ALTER TABLE … ADD COLUMN IF NOT EXISTS so restarts are safe and idempotent.

Seeding

On a fresh database, the backend seeds regulatory workflows, compliance checklists, regulatory return templates, and an initial admin user. When ENVIRONMENT=production is set, seed user passwords are randomly generated and printed once to stdout — capture them immediately.

Backup Strategy

For production deployments we recommend daily pg_dump with off-site storage (S3, Backblaze B2). An example cron using the Docker exec pattern:

bash
# /etc/cron.d/zippcrm-backup — runs at 2:00 AM daily
0 2 * * * root docker exec zippcrm-db \
  pg_dump -U zippcrm -Fc zippcrm \
  > /backups/zippcrm-$(date +\%Y\%m\%d).dump

Restore from Backup

bash
# Stop backend, drop and recreate the database, restore
docker compose stop backend
docker exec -i zippcrm-db dropdb -U zippcrm zippcrm
docker exec -i zippcrm-db createdb -U zippcrm zippcrm
docker exec -i zippcrm-db pg_restore \
  -U zippcrm -d zippcrm < /backups/zippcrm-20260409.dump
docker compose start backend
📧

Email / SMTP Configuration

Outbound email setup, retry logic, and outbox monitoring

ZippCRM sends emails for deadline alerts, SLA escalations, maker-checker approvals, eSign invitations, client portal invites, and payment receipts. Email can be configured either via environment variables or via the in-app Settings → Email screen.

Delivery Behaviour

Every outbound email is inserted into the email_outbox table. The system attempts SMTP delivery immediately. If delivery fails (e.g. transient SMTP error), the email stays in status = 'queued' and the background scheduler retries it every 15 minutes — up to 3 attempts total. After 3 failures the status changes to 'failed' and operators are alerted in the Email Outbox screen.

Supported Security Modes

ModePortDescription
starttls587Plain connection upgraded to TLS via STARTTLS — recommended for most providers
ssl465TLS from the start (SMTP over SSL / SMTPS)
none25Unencrypted — only for internal relay on a trusted network
⚠️
India DPDP Act compliance All emails sent by ZippCRM carry client personal data. Ensure your SMTP provider stores data within India or is DPDP-compliant. Recommended providers: Zoho Mail, Mailgun (India region), AWS SES (Mumbai).
🔁

Email Retry Engine

Automatic queuing, retry, and failure handling for outbound email

ZippCRM queues all outbound emails in the email_outbox PostgreSQL table and retries failed sends automatically via the background scheduler. This ensures emails are never silently lost when the SMTP server is temporarily unreachable.

email_outbox Table

ColumnTypeDescription
idSERIAL PKAuto-increment primary key
to_emailTEXTRecipient email address
subjectTEXTEmail subject line
bodyTEXTPlain-text body
html_bodyTEXTOptional HTML body
statusTEXTqueuedsent or failed
retry_countINTEGERNumber of send attempts made so far (max 3)
sent_atTIMESTAMPTZTimestamp of the last send attempt (used for minimum 5-minute retry spacing)
error_messageTEXTSMTP error from the last failed attempt
created_atTIMESTAMPTZWhen the email was originally queued

Retry Logic

The background scheduler calls _retry_queued_emails() every 5 minutes. It picks up any email with status = 'queued' whose last attempt was more than 5 minutes ago, attempts the SMTP send, and updates the record:

python
# Retry logic summary — backend/app.py
MAX_RETRIES = 3
MIN_RETRY_AGE = timedelta(minutes=5)

# Picks up: status='queued' AND (sent_at IS NULL OR sent_at < now() - 5min)
# On success: status='sent'
# On failure, retry_count < 3: retry_count += 1, sent_at = now()
# On failure, retry_count >= 3: status='failed'
ScenarioBehaviour
SMTP server temporarily downEmail retried up to 3 times, 5 minutes apart. Status becomes failed after 3 attempts.
Invalid recipient addressSMTP error captured in error_message. Retries will also fail — marks failed after 3 attempts.
SMTP not configuredSend is skipped (no-op). Email stays queued indefinitely until SMTP is configured.
Server restartQueued emails survive restarts — they remain in PostgreSQL and are picked up on the next scheduler cycle.
🏦

RBI Module

Reserve Bank of India compliance workflows

The RBI module covers NBFC (Non-Banking Financial Companies), payment aggregators, and prepaid payment instruments. It tracks licence validity, capital adequacy requirements, and all periodic returns mandated under the RBI Master Directions.

Supported RBI Return Types

Return CodeFrequencyDescription
NBFC-NBS1QuarterlyBalance Sheet items (Deposits, Borrowings, Investments)
NBFC-NBS2QuarterlyStatutory Liquid Assets computation
NBFC-ALMHalf-YearlyAsset-Liability Management returns
NBFC-ANNAnnualAudited Balance Sheet and P&L filing
PA-VOLMonthlyPayment Aggregator transaction volume report
PPI-MONTHLYMonthlyPrepaid Payment Instrument outstanding balances
📌
RBI COSMOS / XBRL Integration ZippCRM tracks filing status and deadlines. Direct COSMOS/XBRL submission integration is available under the Enterprise plan.
📈

SEBI Module

Securities and Exchange Board of India workflows

Covers Investment Advisers (IA), Research Analysts (RA), Portfolio Managers (PMS), Alternative Investment Funds (AIF), and Stock Brokers. The module tracks SEBI SCORES complaint responses, BASL/AMFI disclosures, and annual compliance certificates.

Entity TypeLicences TrackedKey Returns
Investment AdviserIA RegistrationHalf-yearly networth certificate, client audit
Research AnalystRA RegistrationAnnual compliance report, SCORES responses
Portfolio ManagerPMS CertificateMonthly NAV disclosure, quarterly PMLA report
AIFCategory I/II/IIIQuarterly investor report, annual audit
🛡️

IRDAI Module

Insurance Regulatory and Development Authority workflows

Covers Insurance Brokers, Corporate Agents, Web Aggregators, and TPAs. Tracks license renewal cycles (3-year for brokers), IRDAI Bima Sugam portal filings, and grievance turnaround SLAs.

EntityLicence CycleKey Obligations
Insurance Broker3 yearsNetworth certificate, FIU compliance, broker exam renewal
Corporate Agent3 yearsSpecified Person training, product tie-up disclosure
Web Aggregator3 yearsWebsite audit, comparative product accuracy
TPA3 yearsClaims TAT report, hospital network update
🏛️

MCA / ROC Module

Ministry of Corporate Affairs and Registrar of Companies filings

Handles annual ROC filings (MGT-7, AOC-4), board resolution tracking, authorised signatory management with DSC validation, and NCLT / NCLAT matter tracking. All statutory filings are tracked against MCA21 deadlines with auto-breach detection.

📡

API Overview

RESTful JSON API for all ZippCRM operations

ZippCRM exposes a RESTful API at /api/. All endpoints return JSON and accept JSON request bodies. The API is the same interface used by the ZippCRM frontend — there is no separate "public API" layer.

Base URL

text
https://your-domain.com/api

Response Format

Successful responses return HTTP 200 (or 201 for creation) with a JSON body. Errors return 4xx/5xx with a body of {"error": "…"}.

json
{
  "id": 42,
  "clientName": "HDFC AMC Ltd",
  "gstin": "27AABCH1234F1Z5",
  "status": "active",
  "createdAt": "2026-01-15T10:30:00+05:30"
}
🔐

Authentication

Session token, TOTP, and rate limiting

ZippCRM uses HTTP-only session cookies. After login, the server issues a session_token cookie. All subsequent API requests are authenticated via this cookie. TOTP two-factor authentication is available for all users and required for admin accounts.

Login

http
POST /api/auth/login
Content-Type: application/json

{
  "email": "admin@yourfirm.in",
  "password": "your-password"
}

Rate Limits

Endpoint GroupLimitWindow
Auth endpoints (login, TOTP, forgot-password)5 requests60 seconds per IP
All other API endpoints100 requests60 seconds per IP
🚨
Rate limit exceeded Returns HTTP 429 Too Many Requests with a Retry-After header.
👥

Clients & Projects API

Core entity endpoints

MethodPathDescription
GET/api/clientsList all clients (paginated, filterable by regulator/status)
POST/api/clientsCreate a new client (validates GSTIN checksum, PAN, CIN)
GET/api/clients/{id}Get a single client
PATCH/api/clients/{id}Update client fields
GET/api/projectsList projects (filter by client, status, regulator)
POST/api/projectsCreate a project with SLA and workflow assignment
GET/api/projects/{id}Get project details with SLA timeline
📋

Compliance API

Return filings, penalties, SCN, and eSign

MethodPathDescription
GET/api/return-filingsList all return filings with due/overdue status
PATCH/api/return-filings/{id}Update filing status (filed, overdue, breached)
GET/api/penalty-registerPenalty register with exposure calculations
POST/api/penalty-register/recalculateForce-refresh penalty exposure estimates
POST/api/documents/{id}/esignInitiate an eSign request for a document
POST/api/esign/{id}/send-invitationsSend signing invitations to all signers
POST/api/esign/{id}/webhookReceive status callback from eSign provider
🔗

Webhooks

Inbound callbacks for eSign providers and automation engines

ZippCRM accepts inbound webhooks from eSign providers (Leegality, Digio, Signdesk, emudhra, NSDL) to update signature status. The endpoint is provider-agnostic — the provider sends a signed callback and ZippCRM maps it to the esign_requests record via provider_ref.

http
POST /api/esign/{id}/webhook
X-Provider-Signature: <hmac-sha256-of-body>
Content-Type: application/json

{
  "status": "completed",
  "providerRef": "LEG-20260409-1234",
  "signedAt": "2026-04-09T14:22:00+05:30"
}
🔒
Signature Verification Configure the provider's HMAC signing secret in Settings → Integrations → eSign. ZippCRM will reject callbacks that fail signature verification.
💳

ZippCRM License Model

Tier-based SaaS licensing with feature and seat gating

ZippCRM is available in four tiers designed for the scale of your compliance practice — from boutique advisories handling a handful of clients to large firm-of-firms managing hundreds of regulated entities.

Each tier is an annual subscription. Pricing is denominated in INR and billed per seat (named operator user). Client Portal users do not consume seats.

Starter
4,999/mo
Per seat · billed annually · up to 3 seats
  • Up to 25 clients
  • 2 regulators (choose any 2)
  • Return filing tracker
  • Basic penalty register
  • Client portal (read-only)
  • Email notifications
  • Maker-Checker
  • eSign integration
  • Workflow engine
  • API access
  • Dedicated support
Growth
9,999/mo
Per seat · billed annually · up to 10 seats
  • Up to 100 clients
  • 5 regulators
  • Return filing tracker
  • Full penalty engine
  • Client portal (full)
  • Email + WhatsApp alerts
  • Maker-Checker (2-level)
  • eSign (manual + OTP)
  • Workflow engine
  • API access
  • Dedicated support
Enterprise
Custom
Unlimited seats · volume pricing · SLA-backed
  • Unlimited clients
  • All regulators
  • Everything in Professional
  • COSMOS / XBRL integration
  • On-premises / private cloud
  • Custom workflows
  • SSO (SAML 2.0 / OIDC)
  • Dedicated support & SLA
  • Custom data residency
  • Annual compliance audit
All plans include: Automatic security updates · PostgreSQL backups (7-day retention on SaaS) · 99.5% uptime SLA · DPDP-compliant data handling · Standard email support
🗝️

License Keys

Activation, validation, and key management

Key Format

ZippCRM license keys follow the format ZCRM-XXXX-XXXX-XXXX-XXXX where each segment is a Base-36 encoded cluster of plan metadata (tier, seat count, expiry epoch, and HMAC checksum).

Activation

Set the ZIPPCRM_LICENSE_KEY environment variable before starting the backend, or enter it in Settings → License → Activate Key. The backend validates the key cryptographically on startup and every 24 hours thereafter.

Offline / Air-Gapped Validation

For Enterprise deployments without internet access, ZippCRM supports offline activation. Contact support to receive an offline license bundle (.zlic file) that encodes the full license claims without calling the validation endpoint.

python
# Example: reading license claims from environment at startup
from licensing import validate_license, LicenseClaims

claims: LicenseClaims = validate_license(
    key=os.environ["ZIPPCRM_LICENSE_KEY"],
    product="zippcrm",
)
# claims.tier → "professional"
# claims.max_seats → 30
# claims.valid_until → datetime(2027, 4, 9)
# claims.features → {"maker_checker", "esign_aadhaar", "workflow_engine", ...}

Grace Period

If the validation endpoint is unreachable (network issues), ZippCRM operates in a 7-day grace period. After 7 days without a successful validation, the system enters read-only mode until connectivity is restored or an offline bundle is applied.

🔒

Feature Gating

How plan tiers control access to modules and capabilities

Every API endpoint and frontend module checks the active license claims before rendering or executing. Gating is enforced at three layers:

1

Backend middleware

The require_feature("esign_aadhaar") decorator on API routes returns HTTP 402 Payment Required with a clear upgrade message if the active plan does not include the feature.

2

Frontend plan guard

The JS layer calls GET /api/license/claims on boot and stores the feature set in memory. UI buttons for locked features show a lock icon and open an upgrade modal instead of executing the action.

3

Seat count enforcement

When creating a new operator user, the backend checks current active user count against claims.max_seats. Exceeding the seat limit returns HTTP 402. Client portal users are never counted as seats.

Feature FlagStarterGrowthProEnterprise
maker_checker✓ (2-level)✓ (n-level)
esign_aadhaar
esign_dsc
workflow_engine
api_access
sso_saml
cosmos_xbrl
white_label_portal
whatsapp_alerts
💡
Custom feature sets Enterprise customers can request bespoke feature bundles. Contact sales@zippcrm.in or your account manager for a custom quote.