Skip to content

Repository files navigation


```
██████╗ ███████╗██╗   ██╗ ██████╗ ██████╗  █████╗
██╔══██╗██╔════╝██║   ██║██╔═══██╗██╔══██╗██╔══██╗
██████╔╝█████╗  ██║   ██║██║   ██║██████╔╝███████║
██╔══██╗██╔══╝  ╚██╗ ██╔╝██║   ██║██╔══██╗██╔══██║
██║  ██║███████╗ ╚████╔╝ ╚██████╔╝██║  ██║██║  ██║
╚═╝  ╚═╝╚══════╝  ╚═══╝   ╚═════╝ ╚═╝  ╚═╝╚═╝  ╚═╝
```
**AI REVENUE RECOVERY CONTROL PLANE**

Revenue at risk isn't recovered by a recommendation.
It's recovered when the provider confirms the money came back.


Python 3.11+ FastAPI Gemini 3.6 Flash Razorpay Test Mode 684 tests passing



The Invariant

AI PROPOSES  ·  POLICY AUTHORIZES  ·  PROVIDER EXECUTES  ·  WEBHOOK OBSERVES  ·  RECONCILIATION PROVES  ·  AUDIT RECORDS

Why REVORA

Failed payments create compounding revenue leakage. Systems built to detect failures are not recovery systems. Most retry infrastructure operates as a blunt instrument: fixed intervals, no failure-mode differentiation, no verification that money was actually captured.

REVORA is different. It closes the full loop — from failure signal to provider-confirmed, independently reconciled recovery — under deterministic policy constraints.

PAYMENT FAILURE
  → AI DIAGNOSIS (Gemini 3.6 Flash)
  → RECOVERY DECISION
  → POLICY ENGINE (deterministic guardrail)
  → PROVIDER ACTION (Razorpay order)
  → CUSTOMER CHECKOUT
  → WEBHOOK (payment.captured)
  → HMAC-SHA256 VERIFICATION
  → INDEPENDENT RECONCILIATION
  → RECOVERED

Creating a Razorpay order is not recovery.
Checkout success is not recovery.
Recovery closes only when the provider confirms capture and independent reconciliation matches.


The Agentic Loop

REVORA agentic recovery loop

Stage What happens
OBSERVE Ingest payment failure signal, error codes, customer history
DIAGNOSE Classify failure mode: transient network, issuer timeout, invalid instrument
DECIDE Gemini 3.6 Flash proposes action + confidence score
POLICY CHECK PolicyEngine evaluates retry budget, status locks, risk thresholds — ALLOW or DENY
ACT Provider adapter creates recovery order if and only if policy granted ALLOW
OBSERVE RESULT Await customer checkout and inbound provider webhook
VERIFY HMAC-SHA256 signature validation + independent Razorpay API reconciliation
STOP / RECOVER Transition to RECOVERED on matching proof, or STOPPED on limit exhaustion

Architecture

REVORA architecture

Layer breakdown
INGESTION LAYER
  FastAPI                  HTTP API, webhook ingress, auth gate
  Revenue Risk Engine      Failure triage and context extraction
  Diagnosis Engine         Root-cause classification (transient / permanent / escalation)

REASONING LAYER
  AI Router                Routes to FAST (simple) or DEEP (complex) AI mode
  Gemini 3.6 Flash         Analyzes failure telemetry → structured RecoveryDecision
  Deterministic Fallback   Offline rule-based fallback if AI provider unavailable

CONTROL LAYER
  Policy Engine            Sole authorization gate. Max 3 attempts. ALLOW or DENY.
  Recovery Pipeline        Orchestrates diagnosis → decision → policy → provider

EXECUTION LAYER
  PaymentProvider          Provider-neutral abstract protocol
  RazorpayProvider         Implemented reference adapter (Razorpay REST API)

VERIFICATION LAYER
  Webhook Processor        Raw-body HMAC-SHA256 verification + event idempotency
  Reconciliation Service   Independent two-way API call: amount, currency, order, status
  SQLite Repositories      Durable storage: payments, recoveries, audit, webhook events

Provider-Neutral Adapter Model

REVORA's recovery logic communicates with payment infrastructure through a clean, provider-neutral protocol:

PaymentProvider  (abstract boundary)
├── RazorpayProvider  ──  implemented · verified · Razorpay Test Mode
├── [StripeProvider]  ──  future adapter
└── [AdyenProvider]   ──  future adapter

Precision: Razorpay is the implemented and tested reference adapter. The architecture is provider-neutral at the boundary; it does not claim multi-provider support as a current capability.

Every adapter must supply:

  • Order creation
  • Independent payment status reconciliation
  • Webhook signature verification

Real Test-Mode Proof

The following was verified end-to-end using Razorpay Test Mode:

13-step verified lifecycle
Step Action Real?
1 Failed ₹500.00 INR payment (bank_timeout) enters REVORA
2 Gemini 3.6 Flash evaluates failure telemetry → RETRY_NOW REAL
3 PolicyEngine checks attempt count (0/3) → ALLOW REAL
4 Razorpay adapter creates authentic recovery order via REST API REAL
5 ReconciliationService records server-side expectation: 50000 minor units, INR REAL
6 Customer opens Razorpay Standard Checkout, completes test payment REAL
7 Razorpay generates new payment entity (pay_...) bound to recovery order REAL
8 Razorpay dispatches payment.captured webhook over HTTP REAL
9 REVORA validates X-Razorpay-Signature over raw bytes using RAZORPAY_WEBHOOK_SECRET (HMAC-SHA256) REAL
10 Webhook processor claims idempotency lease on event_id REAL
11 ReconciliationService queries Razorpay REST API: status=captured, amount=50000, currency=INR, order match REAL
12 PaymentIntentCAPTURED, Recovery → RECOVERED REAL
13 Complete chain of custody recorded in append-only SQLite audit repository REAL
ORDER CREATED  ≠  RECOVERED
CHECKOUT SUCCESS  ≠  RECOVERED
RECOVERY = provider-confirmed capture + independent reconciliation

Synthetic Batch Evaluation

SYNTHETIC — deterministic benchmark, not production financial results.
4,000 cases generated with fixed seed 20260825. Validates control-plane decision logic. Does not represent real merchant revenue.

┌─────────────────────────────────────────────────────────────────┐
│                   BENCHMARK  (seed: 20260825)                   │
│                   4,000 cases · 1,200 history                   │
├──────────────────────────────────┬──────────────────────────────┤
│  REVORA Policy Pipeline          │  Naive Retry Baseline        │
├──────────────────────────────────┼──────────────────────────────┤
│  ₹3,035,091.00  recovered        │  ₹1,696,559.00  recovered    │
│  49.82%  recovery rate           │  27.85%  recovery rate       │
│  1,959  successful               │  1,091  successful           │
│  1,908  stopped by policy        │  2,909  failed retries       │
│    133  escalated to review      │                              │
│  2,041  non-recovered            │                              │
├──────────────────────────────────┴──────────────────────────────┤
│  Total at risk:  ₹6,092,450.00                                  │
├─────────────────────────────────────────────────────────────────┤
│  DELTA  +₹1,338,532.00                                          │
│         +21.97 percentage points                                │
│         +78.90% relative recovered-money uplift                 │
└─────────────────────────────────────────────────────────────────┘

All figures are synthetic simulation results. Not real money. Not production data.


Engineering Controls

Controls currently implemented and verifiable in this repository:

Control Implementation
Bounded retry policy PolicyEngine: max 3 attempts, deterministic DENY on exhaustion
Terminal-state protection State machine: RECOVERED/STOPPED cases cannot be re-entered
HMAC-SHA256 webhook verification app/core/webhook_signature.py: constant-time comparison over raw bytes
Event idempotency webhook_events table: duplicate event_id silently acknowledged
Independent reconciliation ReconciliationService: 4-way match (status, amount, currency, order_id)
Exact amount/currency/order binding PaymentIntent: server-side expectation verified at reconciliation
API authentication X-REVORA-API-Key via hmac.compare_digest
AI provider fallback AIRouter: deterministic offline fallback on AIProviderError
Secret isolation app/core/config.py: env-only, redacted from logs and __repr__
Auditable audit records Append-only SQLite audit trail, sequence-numbered

Quick Start

# 1. Clone and set up environment
git clone <repository-url>
cd REVORA
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# 2. Configure credentials
cp .env.example .env
# Edit .env — see below for required keys

# 3. Start server
.venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 8000

# 4. Run offline test suite (no credentials required)
.venv/bin/pytest -q
# → 684 passed, 1 warning, 124 subtests passed

Endpoints after startup:

Dashboard http://127.0.0.1:8000
Test Checkout http://127.0.0.1:8000/checkout
API Docs (Swagger) http://127.0.0.1:8000/docs
Health http://127.0.0.1:8000/health
Required environment variables
# Razorpay Test Mode (from Razorpay Dashboard → Settings → API Keys)
RAZORPAY_KEY_ID=rzp_test_...
RAZORPAY_KEY_SECRET=<your_razorpay_test_secret>

# Inbound Webhook Secret (from Razorpay Dashboard → Settings → Webhooks)
RAZORPAY_WEBHOOK_SECRET=<your_webhook_secret>

# Merchant API Authentication
REVORA_API_KEY=<your_revora_api_key>

# AI Provider
REVORA_AI_PROVIDER=gemini
GEMINI_API_KEY=<your_gemini_api_key>

# Storage
REVORA_DATABASE_PATH=/tmp/revora.sqlite3
REVORA_DEMO_ENABLED=true
Webhook ingress for local development

Razorpay requires a public URL to deliver webhooks. Use a tunneling utility during local development:

zrok share public 127.0.0.1:8000
# → exposes https://<host>.zrok.io

In Razorpay Dashboard → Settings → Webhooks:

  • URL: https://<your-zrok-host>/api/webhooks/razorpay
  • Events: payment.captured, payment.failed, order.paid
  • Secret: must match RAZORPAY_WEBHOOK_SECRET

Tunneling is for local development and demonstration only.


Demo Scenarios

The built-in dashboard exposes three verifiable scenarios:

Scenario A — Live Recovery (Razorpay Test Mode)
Full end-to-end agentic loop: failure → Gemini → policy → order → checkout → webhook → reconciliation → RECOVERED.

Scenario B — Policy Guardrail
Exhausted retry account (3/3 attempts): PolicyEngine returns DENY. Provider never called. Zero Razorpay orders created.

Scenario C — Verified Case Inspection
Inspect an existing reconciled recovery case with complete auditable trail and reconciliation proof.

See docs/demo.md for the complete step-by-step reviewer walkthrough.


Real vs. Synthetic

Component Nature What it proves
Gemini 3.6 Flash AI REAL Contextual reasoning via google-genai SDK on live failure data
Razorpay order creation REAL Authenticated REST API call to Razorpay /v1/orders
Customer test payment REAL Razorpay Standard Checkout SDK, Test Mode cards
Webhook delivery REAL HTTP delivery from Razorpay servers to /api/webhooks/razorpay
HMAC-SHA256 verification REAL Constant-time comparison over raw bytes using webhook secret
API reconciliation REAL Server-to-server call to Razorpay /v1/orders/{id}/payments
Recovery state transitions REAL State machine driven by verified provider reconciliation
Audit trail REAL Append-only SQLite event records
Benchmark dataset SYNTHETIC 4,000 cases, seed 20260825 — validates policy mechanics
Batch simulation SYNTHETIC Algorithmic comparison: REVORA vs naive retry baseline

API Surface

All 14 routes
Method Endpoint Description Auth
GET /health Service + SQLite health probe None
GET / Interactive control plane dashboard None
GET /checkout Standalone Razorpay Test Mode checkout None
GET /docs Swagger / OpenAPI interactive docs None
GET /redoc ReDoc API reference None
POST /demo/recovery/prepare Prepare isolated recovery scenario (rec_live_{uuid}) None
POST /demo/recovery Simulate a single recovery pipeline run None
POST /demo/simulation Run 4,000-case synthetic benchmark None
POST /api/recovery/execute Execute real recovery pipeline X-REVORA-API-Key
GET /api/recovery/{id} Retrieve recovery state, execution state, audit trail X-REVORA-API-Key
POST /api/razorpay/orders Create Razorpay Test Mode order + record expectation X-REVORA-API-Key
POST /api/razorpay/verify Verify checkout signature + reconcile X-REVORA-API-Key
POST /api/webhooks/razorpay Ingest Razorpay webhook (HMAC verified) X-Razorpay-Signature

Project Structure

File tree
REVORA/
├── app/
│   ├── core/
│   │   ├── config.py              # Configuration boundary & secret isolation
│   │   ├── diagnosis_engine.py    # Payment failure classification
│   │   ├── money.py               # Exact-or-raise currency & minor units math
│   │   ├── policy_engine.py       # Deterministic authorization gate
│   │   ├── recovery_agent.py      # Agent protocol & deterministic fallback
│   │   ├── recovery_pipeline.py   # End-to-end recovery pipeline orchestrator
│   │   └── recovery_agent.py      # RecoveryContext & agent protocol
│   ├── models/
│   │   ├── audit.py               # Append-only audit events & trail
│   │   ├── decision.py            # AI & policy decision dataclasses
│   │   ├── payment.py             # Payment domain models
│   │   ├── payment_intent.py      # Server-side capture expectations
│   │   ├── recovery.py            # Recovery entities & actions
│   │   └── revenue_risk.py        # Failure classification enums
│   ├── repositories/
│   │   ├── protocols.py           # Storage interface protocols
│   │   ├── in_memory.py           # In-memory adapters (dev/test)
│   │   └── sqlite.py              # Durable SQLite repository
│   ├── services/
│   │   ├── ai_provider.py         # AIRecoveryProvider protocol & fallback
│   │   ├── ai_router.py           # FAST / DEEP routing logic
│   │   ├── gemini_provider.py     # Google Gemini 3.6 Flash adapter
│   │   ├── razorpay_provider.py   # Razorpay PaymentProvider adapter
│   │   ├── razorpay_service.py    # Razorpay REST API client
│   │   ├── reconciliation.py      # Two-way payment reconciliation
│   │   └── webhook_processor.py   # Webhook validation & idempotency
│   ├── simulation/
│   │   ├── batch_runner.py        # Deterministic benchmark engine
│   │   └── synthetic_dataset.py   # Dataset generator (seed: 20260825)
│   └── main.py                    # FastAPI app & route definitions
├── static/                        # SPA dashboard & checkout
├── tests/                         # 684-test automated suite
├── docs/                          # Architecture & reviewer docs
│   ├── architecture.md
│   ├── architecture-diagram.md
│   ├── demo.md
│   └── assets/                    # SVG diagrams
├── requirements.txt
└── README.md

What Broke, and How We Fixed It

Engineering challenges encountered during development

1. Shared recovery ID audit pollution
Early demo runs reused static IDs (rec_live_demo). The append-only audit log retained historical webhook + reconciliation events, causing stages 7–9 to appear complete before any payment. Fixed by generating fresh rec_live_{uuid8} identifiers on every /demo/recovery/prepare call.

2. Frontend polling race conditions
Background polling timers persisted after scenario switches, overwriting newer execution states with stale responses. Fixed with monotonic activePollSessionId tokens that immediately invalidate obsolete polling cycles.

3. Payment entity correlation
When a customer completes checkout, Razorpay creates a new payment entity (pay_...) separate from the initial failure. Fixed by establishing PaymentIntent as the correlation nexus binding failure ID, recovery order ID, and captured payment ID.

4. Webhook ingress in local development
Local machines cannot receive external webhooks without public routing. Fixed by integrating headless zrok tunneling with raw-body HMAC validation and an idempotency lease table.

5. Strict reconciliation binding
Webhook receipt alone was insufficient — partial payments or misattributed orders could pass. Fixed with 4-attribute reconciliation: payment status, exact minor units, currency, and order ID association.

The lesson: treat recovery as a verified, auditable state transition — not an optimistic UI event.


Limitations

  • Prototype scope: Designed for evaluation and demonstration; not an off-the-shelf production deployment.
  • Gateway coverage: Razorpay is the implemented reference adapter. Other gateways require a PaymentProvider implementation.
  • Benchmark scope: 4,000-case synthetic dataset validates policy mechanics; it does not predict real-world merchant conversion rates.
  • Tunneling: zrok is for local webhook ingress during development. Production requires proper webhook infrastructure.
  • Horizontal scaling: Production deployment would require async task queues (Celery/Kafka), multi-tenant isolation, and enterprise secret management.

Roadmap

  • Additional provider adapters
  • Subscription recovery
  • Checkout abandonment recovery

Docs

Document Contents
docs/demo.md Complete reviewer walkthrough: setup, demo paths, Razorpay live flow
docs/architecture.md Deep-dive: components, data flow, invariants, benchmarks
docs/architecture-diagram.md Mermaid architecture diagram

AI proposes.  Policy controls.  Providers execute.  Reconciliation proves.

About

AI revenue recovery control plane that diagnoses payment failures, enforces bounded policies, executes provider actions, and verifies recovered revenue.

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages