JR
All work
Go2Green · EV mobility · 2026 Back office on n8n

A rental business that collects every day, without anyone chasing anyone.

Two apps were written by hand — the one the driver holds, the one the ops desk works in. Everything that happens between them is fourteen self-hosted n8n workflows: the money, the messages, the escalations and the locks.

1,000+
renters onboarded
₹10L+
collected via wallet
8
weeks to launch
Context

Rent is due daily. Nobody can phone a thousand people daily.

Go2Green rents electric two- and three-wheelers to gig delivery workers in Bengaluru — food, grocery, meat, last-mile parcel. The economics only work if rent lands every single day, from a population that is paid daily, banks on UPI, and switches platforms constantly.

Weekly bank mandates were the obvious answer and the wrong one: per-debit mandate friction, NPCI daily limits, and a failed debit that tells you nothing until the money is already a week gone. So the money model became a prepaid wallet — the driver loads it, and an internal ledger debits the day’s rent at a fixed hour. No bank transaction per day, no mandate to fail.

Which moves the entire problem into operations. A wallet that debits daily needs somebody watching balances, sending reminders before the debit and receipts after, routing KYC, escalating non-payers through a grace period, and — at the end of that ladder — immobilizing a vehicle safely and reversibly. At a thousand drivers that is not a job. It is a scheduler.

The decision

Write the app. Don’t write the back office.

Two things a human touches were built properly, in code: a React Native driver app and a Next.js admin console over Postgres with row-level security. Those are product surfaces, and product surfaces earn their handwritten code.

The rest — the cron jobs, the retries, the WhatsApp templates, the “if balance falls below X then” ladders, the webhook reconciliation — is the part of every fintech that quietly becomes forty thousand lines of untested glue nobody wants to own. That went to n8n, self-hosted beside the database.

Handwritten · TypeScript

What a human touches

  • Driver app — React Native, six languages, self-onboarding.
  • Admin console — Next.js, RBAC across five roles.
  • The wallet ledger itself — integer paise, immutable rows.
  • Postgres + RLS, object storage, the audit schema.
Orchestrated · n8n

What happens on its own

  • The daily debit run, and every receipt after it.
  • Low-balance and dunning ladders, WhatsApp and email.
  • KYC routing — Cashfree Secure ID into the review queue.
  • Cashfree webhook intake and nightly reconciliation.
  • The immobilization approval chain and its release.

The line between the two is deliberate and enforced: n8n never computes a balance. It calls a Postgres function that does, inside a transaction. Workflows decide when, and who to tell. The database decides what is true.

The automation spine

Four things wake the system up. Everything else is a consequence.

G2G · OPERATIONS ORCHESTRATION REV C TRIGGERS n8n · SELF-HOSTED EFFECTS CRON · 06:00 IST The day’s rent comes due WEBHOOK · CASHFREE Top-up, autopay, refund EVENT · POSTGRES Balance crosses a threshold APPROVAL · ADMIN Ops asks to immobilize VERSIONED WORKFLOWS · ONE JOB EACH Daily debit run — ledger write, then receipt Low-balance ladder — T−6h and T−1h Cashfree intake — idempotent, replayable KYC router — Secure ID into the review queue Dunning — grace, reminders, call task Immobilize chain — two approvals, one gate Nightly reconcile — gateway against ledger Deposit refund — on vehicle return No workflow computes money. Each one calls the ledger and waits. LEDGER · POSTGRES Integer paise, append-only WHATSAPP · WABA Six languages, templated EMAIL · RECEIPTS Debit, top-up, refund IMMOBILIZER · ADAPTER Vendor behind one interface APPEND-ONLY AUDIT LOG · EVERY RUN, EVERY NODE, EVERY PAISA Workflow and version Trigger and payload Balance before / after Actor, or the system IN · A CLOCK, A GATEWAY, A THRESHOLD, A HUMAN OUT · MONEY MOVED, DRIVER TOLD, ACTION LOGGED

No screenshots: the system is live and holds a client’s driver, KYC and payment records. This is the orchestration it runs.

Why n8n

Not because it was quicker. Because of where it runs and what it exports.

Automation platforms are mostly interchangeable until you put Aadhaar numbers and money through them. Two constraints eliminated the field, and n8n was what survived.

It runs on the client’s own metal

Aadhaar e-KYC payloads, PAN, selfies and the full payment ledger pass through these workflows. Under the DPDP Act that data cannot casually transit a third-party automation cloud in another jurisdiction. n8n is self-hosted in-region, in the same private network as Postgres — so the sensitive hop never leaves the client’s infrastructure at all. This alone ruled out every hosted-only option.

A workflow is a JSON file

Every workflow exports as JSON, so it lives in git, arrives by pull request, and gets reviewed like any other change. The audit log records which workflow version caused each side effect. A visual tool you cannot diff has no business moving money; this one you can.

Real code where it’s needed

The awkward 5% — Cashfree signature verification, idempotency-key construction, six-language template selection — is written as TypeScript in Code nodes rather than contorted into drag-and-drop conditionals. The other 95% stays visual, which is exactly the part the ops lead needs to be able to read.

Priced per server, not per task

A thousand drivers generate a debit, up to two reminders, a receipt and assorted webhook traffic every day — six figures of task executions a month, growing linearly with the fleet. On per-task pricing the automation layer would have become a cost centre that punishes growth. Self-hosted, it is one VM.

What we built in n8n

Fourteen workflows. Each one does a single thing and says so.

Eight carry the business. The remaining six are plumbing: the shared error handler, the audit writer, the WhatsApp send sub-workflow, the template resolver, a health probe and the staging smoke test. The node chain under each one below is the actual shape of the workflow.

01 · Daily debit run

Schedule trigger · 06:00 IST · 11 nodes

One cron, batched by city. For each active assignment it calls a Postgres function that debits the day’s rent inside a transaction and returns the new balance. The workflow never does the arithmetic — it fans out, collects outcomes, and a Switch sends each one where it belongs: a receipt, a shortfall notice, or the retry lane.

Schedule TriggerPostgres · due todaySplit In BatchesPostgres · fn_debit_wallet()Switch · outcomeWhatsAppPostgres · audit

02 · Low-balance ladder

Schedule trigger · T−6h, T−1h · 9 nodes

Fires twice before the debit, only for wallets that will not cover tomorrow. A Postgres query does the selection, so the “who is short” logic has exactly one home. Deduplicated per driver per day against a sent-messages table — a driver who tops up between the two never receives the second message.

Schedule TriggerPostgres · shortfall forecastFilter · already nudgedCode · pick template + languageSub-workflow · sendPostgres · mark sent

03 · Cashfree webhook intake

Webhook trigger · 8 nodes

Signature verified in a Code node, then written to a raw-event table keyed on the gateway’s own reference before anything else happens. A duplicate delivery hits the unique index and stops there. Only then does a Switch route by event type — top-up, autopay debit, payout, refund — into the ledger. Replaying a week of events changes no balances.

Webhook TriggerCode · verify signaturePostgres · raw event (unique)IF · already seenSwitch · event typePostgres · credit ledgerRespond 200

04 · KYC router

Webhook trigger · from driver app · 12 nodes

Aadhaar offline e-KYC and PAN through Cashfree Secure ID, selfie through liveness and face-match, the three calls running in parallel branches and merging. Clean passes queue as pre-approved; anything ambiguous routes to a human with the failing check named. Aadhaar is masked in a Code node before it is ever persisted, so the full number exists only in memory for the length of one execution.

Webhook TriggerHTTP · Aadhaar OKYCHTTP · PAN + name matchHTTP · livenessMergeCode · mask + scorePostgres · review queue

05 · Dunning and escalation

Schedule trigger · daily · 13 nodes

A shortfall opens a grace window whose length is read from the config table the client edits in the admin console — not hard-coded in the workflow. Reminders on a schedule, then a call task for the ops desk, then — and only then — the driver becomes eligible for the lock chain. Eligibility is a flag. It is never the lock itself.

Schedule TriggerPostgres · open shortfallsPostgres · read grace configSwitch · days overdueSub-workflow · sendPostgres · call taskPostgres · mark eligible

06 · Immobilization chain

Webhook trigger · from admin console · 15 nodes

The most guarded workflow on the system. It refuses to start unless eligibility is already set, waits on a second approver from a different role, warns the driver, and re-reads live telematics at the last node before the command — if speed is not zero it aborts and reschedules. Prevent-restart only. The release path is a separate, much shorter workflow with no approval gate at all.

Webhook TriggerIF · eligible?Wait · second approverSub-workflow · warn driverHTTP · telematicsIF · speed = 0HTTP · immobilizePostgres · audit

07 · Nightly reconciliation

Schedule trigger · 02:00 IST · 10 nodes

Pulls the gateway’s settled transactions for the day, diffs them against the ledger in a Code node, and files any row that exists on one side and not the other as a finance task. Finance hears about a mismatch over morning coffee rather than at month end.

Schedule TriggerHTTP · Cashfree settlementsPostgres · ledger for dateCode · diffIF · discrepanciesPostgres · finance taskEmail · summary

08 · Deposit refund

Webhook trigger · on vehicle return · 9 nodes

Settles outstanding dues against the deposit, initiates the balance as a Cashfree payout, and then stops — the assignment stays open until the payout webhook confirms, at which point workflow 03 closes it. Money leaving the business is never assumed to have left.

Webhook TriggerPostgres · dues vs depositCode · net payableHTTP · Cashfree payoutPostgres · pendingSub-workflow · notify
Workflow 01, node by node

The one that moves the money, every morning at six.

G2G · WF-01 DAILY DEBIT RUN 11 NODES TRIGGER Schedule NODE 02 · POSTGRES Due today NODE 03 · LOOP Split In Batches NODE 04 · POSTGRES fn_debit_wallet() NODE 05 · SWITCH Route on outcome OUTCOME A · PAID The receipt goes out WhatsApp, in the driver’s language Email carrying the ledger row OUTCOME B · SHORT A shortfall opens Top-up link sent immediately Grace clock starts, WF-05 armed OUTCOME C · ERROR Nothing is lost Retry with backoff, then dead-letter Ops task carries the whole payload IDEMPOTENCY KEY · DRIVER + DATE + OPERATION · ENFORCED BY A UNIQUE INDEX Re-run this workflow for a date it already processed and it writes nothing the second time. That property is what makes a visual workflow safe to touch. IN · A CLOCK OUT · ONE LEDGER ROW AND ONE MESSAGE PER DRIVER
Non-payment

The hardest workflow is the one that takes someone’s livelihood away.

G2G · ESCALATION LADDER · WF-05 INTO WF-06 REV C 01 · DEBIT SHORT The wallet didn’t cover it Shortfall recorded, not charged Top-up link sent on WhatsApp 02 · GRACE Still riding, still reminded Window length set by the client Call task raised for the ops desk 03 · ELIGIBLE A human has to ask Ops raises, finance confirms Driver warned before anything 04 · IMMOBILIZED Won’t restart. Won’t stop. Speed = 0 read at the last node Payment releases it, ungated GUARDRAILS · CHECKED AT EVERY RUNG, NOT ONLY THE LAST Never while moving Two people, two roles Warned in advance Release needs no approval IN · A WALLET THAT CAME UP SHORT OUT · A REVERSIBLE, AUDITED, ANNOUNCED ACTION

Every rung is reversible and every rung is logged. The asymmetry is deliberate: locking a vehicle takes two people and four checks, unlocking it takes a successful payment.

Running n8n in production

What it takes before you trust a workflow with money.

A default n8n install is a prototyping tool. Six things turned it into something a payments back office can sit on.

Queue mode, not single-process

n8n runs in queue mode with Redis and separate worker processes. The 06:00 debit run for the whole fleet does not block a Cashfree webhook arriving in the same second, and a worker restart mid-batch resumes rather than loses.

One shared error workflow

Every workflow points at the same error handler. A failed execution becomes an ops task with the input payload attached, plus an alert if it touched money. Nothing fails into a log file nobody reads.

Sub-workflows for shared work

Sending a WhatsApp message — resolve the template, pick one of six languages, fall back to email, record what was sent — is one sub-workflow called by five others. The WABA credential is configured in exactly one place.

A staging instance that matters

Workflows are imported into staging against gateway sandbox credentials and a seeded database, and a smoke-test workflow runs the full debit path before anything is promoted. Nobody edits nodes on the production canvas.

Credentials scoped and rotated

Cashfree, WABA and the telematics vendor each hold their own credential with its own role; the Postgres credential n8n uses cannot read the KYC document table at all. Rotation is a config change, not a hunt through nodes.

Policy lives in the console

Daily rent, deposit, auto-reload threshold and grace period are rows the client edits in the admin app and the workflows read at runtime. Changing the grace window from two days to three is an operations decision, not a deployment.

Results

Collections became a scheduled job.

  • 1,000+ renters onboarded and collecting daily, with no collections headcount added.
  • A debit that does not go through is a shortfall, never a technical failure — the retry lane and the dead-letter handler mean an error can no longer be mistaken for non-payment.
  • Reminders before the debit do most of the work — the overwhelming majority of shortfalls resolve inside the grace window, before a lock is ever requested.
  • 8 weeks from spec to launch in Bengaluru, across Android, iOS and the admin console, in six languages.
  • ₹10L+ has moved through the wallet, every paisa of it against a ledger row with a workflow run behind it.
  • The gateway and the ledger reconcile every night. Finance finds out about a mismatch the next morning, not at month end.
  • Adding a city is a config row and a WhatsApp template — the workflows do not know how many cities there are.

Is your back office a person with a spreadsheet and an alarm?

Start with a two-week operations leak audit. We map the work that happens on a schedule, the work that happens because somebody remembered, and the money that moves in between — then show you which of it should be a workflow. Applies against the build if you continue.

Book the leak audit