Beta — not yet production-ready. See caveats below.
A nano-service platform for Indian retail lending. Designed for RBI Digital Lending Guidelines compliance, with DPDPA 2023 data protection, 30+ independently deployable services connected by an event bus with Ed25519 cryptographic attestation.
- 31 nano-services — KYC/AML (PAN + Aadhaar Verhoeff), CIBIL/Experian/Equifax credit bureau, CKYC registry, RBI rate-capped pricing, KFS generation, DPDPA consent + DSR, Razorpay PG, risk scoring, fraud detection, collections, recovery, notifications, governance
- Event-driven — typed events with Ed25519 signatures, saga orchestration, dead-letter queues, circuit breakers
- Pluggable backends — memory / filesystem / Postgres; local / SQS / Modal event bus; console / OTLP tracing
- 1167 tests — rate limiting, idempotency guards, PII redaction, Prometheus metrics
This is an early-stage beta. It is not production-ready. Known gaps:
- Real API integrations for PAN (NSDL/ITD), Aadhaar (UIDAI), CKYC, CIBIL, and AML blocklists are stubbed — format validation only
- Video KYC provider integration is not yet implemented
- e-NACH / UPI Autopay mandate collection is stubbed (event definitions exist, Razorpay integration skeleton present)
- No RBAC beyond basic access control
- No disaster recovery procedures documented
- Developer experience is rough — no pre-built Docker images, no Helm charts, manual service wiring required
If you need a production-grade Indian lending platform today, underwrite is not the right choice.
git clone https://github.com/sachn-cs/underwrite.git
cd underwrite
./setup.sh
source .venv/bin/activate
python -m pytest tests/ --tb=short -q # 1167 testsTo run an Indian lending scenario:
underwrite init
# edit underwrite.json to enable: mechanism,audit,risk,fraud,compliance,consent,credit_bureau,kfs,pricing,underwriter,decision
underwrite run mechanism audit risk fraud compliance consent credit_bureau kfs pricing underwriter decision
# In another terminal:
python docs/examples/indian_lending.py
# See docs/QUICKSTART.md for the full walkthroughFull docs at docs/ — but expect rough edges:
| Area | Documents |
|---|---|
| Getting Started | Installation · Quickstart (Indian scenario) · Configuration · Env Vars |
| Architecture | Overview · System Design · Domain Model · Design Decisions |
| Development | Guide · Testing · Debugging · Code Style · Build |
| Operations | Deployment · Operations · Observability · Security (DPDPA) · Performance |
| Reference | API · Troubleshooting · FAQ · Glossary |
| Project | Contributing · Maintenance · Roadmap |
- Python 3.10+
- PostgreSQL 14+ (optional — memory/filesystem backends work without it)
- Docker (optional — for
docker compose upwith Postgres + Vault + OTLP)
pip install underwrite
# With extras:
pip install "underwrite[risk,serve,postgres,otlp,vault,aws]"
# Development:
pip install -e ".[dev,risk,serve,postgres,otlp,vault,aws]"| Extra | Provides |
|---|---|
risk |
NumPy, scikit-learn — ML risk models |
serve |
Uvicorn, FastAPI — HTTP server |
postgres |
psycopg2-binary — Postgres state store |
otlp |
OpenTelemetry SDK — distributed tracing |
vault |
hvac — HashiCorp Vault secrets |
aws |
boto3 — SES, SQS, Secrets Manager |
security |
bandit, pip-audit — vulnerability scanning |
dev |
pytest, ruff, mypy, hypothesis, testcontainers |
Configure via JSON file (created with underwrite init), env vars, or both (env vars override). See .env.example for all supported vars, including RBI pricing caps, AML thresholds, credit bureau API keys, Razorpay credentials, and DPDPA retention periods.
UNDERWRITE_STORE_BACKEND=postgres
UNDERWRITE_STORE_DSN=postgresql://user:pass@localhost:5432/underwrite
UNDERWRITE_PERSONAL_LOAN_RATE_CAP=0.28
UNDERWRITE_PENAL_INTEREST_CAP=0.24underwrite
Commands:
init [PATH] Create default config
run <service>... Start one or more services
list List all 31 nano-services
identity <service> Generate Ed25519 keypair
health System health status
dlq [--replay] [--max N] Show or replay dead-letter queue
metrics Metrics snapshot (Prometheus-format on /v1/metrics)
migrate Run pending schema migrations
serve Start HTTP daemon (requires [serve] extra)
When running underwrite serve:
| Endpoint | Method | Description |
|---|---|---|
/healthz |
GET | Liveness probe |
/readyz |
GET | Readiness probe |
/v1/health |
GET | Full system health |
/v1/metrics |
GET | Prometheus-format metrics |
/v1/publish |
POST | Publish a domain event |
Authentication via Authorization: Bearer <token> when started with --require-auth.
underwrite/ # Source (90+ modules, fully typed)
__config__.py # Pydantic configuration (28 sections)
__bus__.py # Event bus — pub/sub, DLQ, rate limiter
__store__.py # State store — memory / file / postgres
__saga__.py # Saga orchestrator
__authz__.py # Access control & Ed25519 verification
__identity__.py # Ed25519 key management
__events__.py # 105+ event types
__pii.py # PII redaction (Aadhaar, PAN, etc.)
services/ # 31 nano-services
base.py # NanoService ABC
mechanism/ # Delegation state machine (core)
compliance/ # KYC/AML — PAN category, Aadhaar Verhoeff, risk score
pricing/ # RBI caps, APR, EMI, penal interest, foreclosure
kfs/ # Key Fact Statement generation
consent/ # DPDPA consent lifecycle
dsr/ # Data Subject Rights fulfillment
credit_bureau/ # CIBIL/Experian/Equifax + CKYC
razorpay/ # Payment gateway integration
risk/ # ML risk scoring
fraud/ # Fraud detection
audit/ # Event ledger (PII-redacted)
npa/ # Asset classification (SMA/NPA/DLG)
recovery/ # Default recovery (store-backed)
... # 17 more services
tests/ # 58 test files, 1167 tests
docs/ # 9 updated docs for Indian market
Each nano-service extends NanoService with a single handle(event: Event) -> None:
- Subscribe — declare interest in event types via config
- Dispatch — handler wrapped with authz, idempotency, tracing, metrics, timeout
- Emit —
self.emit(event)signs with Ed25519 and publishes to bus - Persist — state via
Store(MemoryStore / FileStore / PostgresStore)
Cross-cutting concerns (authz, tracing, metrics, sagas, supervisor, circuit breaker) are injected by the bus and runtime — not inherited by services.
| Principle | Implementation |
|---|---|
| Event provenance | Ed25519 signature on every event, verified before dispatch |
| Fault isolation | DLQ with replay; per-subscriber circuit breaker; per-handler timeout |
| Security-first | No str(default) in signing; joblib gated by env var; bearer auth; PII redaction |
| RBI compliance | Per-product rate caps, all-in-cost APR, penal interest limit, KFS cooling-off |
| DPDPA compliance | Consent lifecycle, DSR fulfillment, breach notification, auto-purge |
MIT — see LICENSE. Not legal advice. Consult a qualified attorney before deploying in a regulated environment.