OPERATIONAL · POLLING EVERY 30 MIN

131 inboxes.
Zero missed bills.

Bill Hub watches every managed Gmail inbox for Starlink billing traffic — parsing payments, catching failures, and relaying OTP codes to Telegram in seconds. One cron tick, end to end, running serverless at the edge.

Live from production

Numbers straight out of D1

SELECT COUNT(*) — queried at the edge, cached 5 min. Not marketing math.

131
Inboxes monitored
3,291
Emails parsed
1,412
OTPs relayed
737
Payment alerts
233
Days of history
The pipeline

From inbox to alert in one cron tick

Every 30 minutes a scheduled Worker sweeps the whole fleet. No queues, no servers, no idle cost — the entire run finishes inside a single invocation.

01

Poll Gmail

gmail.js · REST, no SDK

OAuth2 refresh-token exchange, then from:starlink.com across every account. New registrations backfill 90 days.

02

Parse

parser.js · regex, HTML-aware

Classifies payment failed, payment scheduled, and OTP mail; extracts account numbers, amounts, periods and 6-digit codes.

03

Store & dedupe

D1 · SQLite at the edge

Idempotent writes keyed on the Gmail message ID — re-polls and retries can never double-alert.

04

Alert

telegram.js · two bots

Urgent failures and OTPs go to the ops group instantly; billing-expiry reminders ship on a 7-day and 3-day cadence.

05

Dashboards

SSR · zero client frameworks

Executive KPIs, accounting, sales and analytics — rendered server-side with CSS-only charts.

Feature set

Built for the whole billing desk

One system, four roles — operators, accountants, sales and management each get their own surface over the same live data.

OTPInstant OTP relay

Starlink login codes land in Telegram seconds after they hit the inbox. Anyone in the ops group can also pull one on demand — the bot polls Gmail with a retry loop until the code arrives.

# in the Telegram group
/otp customer14@gmail.com
482913 · received 04:31 UTC

PAYPayment intelligence

Failed payments page the team with the account number and amount. Scheduled payments feed the billing calendar — statement periods drive a renewal ring on every account card, and amounts are kept verbatim (PHP 5,700.00) so nothing is lost to float rounding.

⚠ payment_failed · ACC-2884…
amount PHP 5,700.00 → Bot 1, ops group

RMDBilling reminders

A second bot nudges the team 7 days and 3 days before each statement period ends — tracked per account so nothing fires twice.

RBACRole-based access

Admin, accountant and sales roles land on their own dashboards. PBKDF2 at 100k iterations, HMAC-signed cookies, lockout after 5 failed logins.

SLSSales → accounting handoff

Sales uploads one KPay screenshot across multiple accounts; accountants confirm from a pending queue with independent amounts per account.

RPTNine reports, CSV out

Monthly summary, aging, regional, outstanding, recorder, annual statement and more — all print-optimized with one-click CSV export.

OBDSelf-service onboarding

New accounts join through a public OAuth flow — consent, token exchange, then an immediate 90-day sync with alert flooding suppressed.

EXECExecutive overview

Collections, renewals, regional revenue, six-month trend and a sales leaderboard — the whole operation on one screen.

Engineering notes

Small surface, sharp edges

/01

Zero runtime dependencies. Gmail, Telegram and OAuth are all raw fetch against REST — no SDKs, so the whole Worker bundles in kilobytes and cold-starts in nothing.

/02

Idempotent by design. INSERT OR IGNORE on the Gmail message ID means polling is safely re-runnable; a separate notified flag decouples fetching from alerting, so a Telegram outage just retries next cycle.

/03

Token self-healing. Every refresh token keeps a backup — if Google revokes the primary, the poller falls back automatically before flagging the account for re-auth.

/04

CSS-only charts. Every donut, trend line and bar across five dashboards is rendered with CSS and inline SVG — no charting library ships to the client.

/05

Locale-proof parsing. Starlink emails arrive with MX-locale dates; the period parser detects and swaps DD/MM ambiguity instead of silently corrupting billing cycles.

Cloudflare Workers D1 · SQLite R2 object storage Gmail REST API Google OAuth2 Telegram Bot API Cron triggers ~$5/mo all-in