Inspiration

Prices for local services rarely have public reference points. When a boiler breaks or a car needs work, customers have virtually no way of knowing whether the quote they were given is reasonable or not. The information exists but it has never been systematically collected and made available in such semi-urgent situations. Significant financial decisions such as buying a house, booking a flight, accepting a job offer, and so on, almost always come with a reference point. Local services are an exception and Plumline is our attempt to change that.

What it does

Plumline is a price intelligence platform for local services that aggregates price observations (quotes, receipts, completed jobs, etc.) and presents the geospatially-relevant ones to users. By doing this, we give the users a way to see what a particular service actually costs near them before engaging a provider. Users interact through a conversational search interface that first collects the necessary details about their needs for a service using a defined checklist based on service category, then runs a search. The search itself is able to handle dense and verbose queries, and combines full-text search, semantic vector search and geospatial matching to return nearby service providers with their respective pricing histories. If no such local data exists for a query, Plumline has a discovery pipeline that automatically queries Google Maps via SerpAPI. This pipeline adds the discovered providers into the database and returns said providers in the results without any manual intervention needed.

How we built it

Our team split across four parallel workstreams - backend API and database, frontend UI, stripe integration, and the scraping pipeline. The backend was written in Python using FastAPI and the primary data store is MongoDB Atlas. Full-text search runs through Atlas search with fuzzy matching, geospatial search uses MongoDB's own $geoNear aggregation pipeline, and semantic search was handled using Atlas Vector Search on embeddings generated using OpenAI's text-embedding-3-small (handled via LangChain). The full-text and semantic searches ran in parallel and the results were merged and deduplicated before the geo stage. The conversational layer that the user interacts with uses GPT-4o-mini to extract the search parameters in a structured way, with a (deterministic) validation layer that overrides the model if it tries to finalise any searches before all the required fields have been collected. The frontend is built in TypeScript and Next.js with its purpose being to provide users with a conversational search interface and a map view of the results. The discovery pipeline was written in Python and condenses verbose user queries if needed, and in the case that a search returns no local data, the pipeline automatically uses SerpAPI to query Google Maps. Providers that are discovered via this search are filtered by distance and added to the database accordingly. The Stripe integration handles customer creation, customer payment methods, and virtual card issuance (Stripe Issuing). A Playwright script drives the end-to-end booking procedure.

Challenges we ran into

Combining three kinds of search methods (full-text, vector, and geospatial) into a single set of results required us to have carefully thought out scoring and deduplication systems. When two text-based methods returned overlapping results but different confidence scores, the conflict needed to be handled without the need for manual intervention. The conversational aspect of Plumline was also slightly challenging to handle as GPT-4o-mini kept marking searches as ready before all required fields were collected. This issue was addressed through a validation step (post-processing) that enforces checklist completion regardless of the returned output of the model.

Accomplishments that we're proud of

The Complete End-to-End Orchestration: We are incredibly proud of connecting a complex tech stack into one seamless 1-click user experience. We successfully bridged a Lovable-generated Next.js frontend, a MongoDB Atlas Hybrid Vector Search (combining OpenAI embeddings with Lucene matching), a dynamic web-scraping fallback, Stripe Issuing, and a Playwright-driven Python backend.

Mastering "Optimistic UI" for Async AI: Autonomous web agents take time to act (often 30+ seconds to fill a form). Instead of overengineering WebSockets, we built a highly responsive frontend state machine that cycles through the agent's predicted steps ("Opening browser...", "Filling in your details..."). This provides a high-signal feeling of progress and keeps the user engaged without freezing the app.

The "Verified Connector" Agent: Watching our Playwright agent visibly open a Chromium browser, intelligently navigate a dummy local business form, type out the user's details using human-like delays (slow\_mo), and successfully process a payment using a dynamically generated Stripe virtual card---all completely autonomously---was our absolute highlight.

Zero-API Agentic Commerce: We proved that we can bring one-click checkout to the most fragmented, un-digitalized sector of the economy (local offline services) without ever asking the merchants to change their software or build an API for us.

What we learned

Mastering Hybrid Semantic Search: We learned that simple keyword matching fails in the local service industry. By combining OpenAI embeddings (text-embedding-3-small) with MongoDB Atlas Vector Search and Lucene fuzzy matching, we discovered how to accurately map semantic user intent (e.g., "spark plug") to the correct service category ("Mechanic") in milliseconds.

Dynamic Data Discovery (Cold Starts): We learned how to handle empty database states intelligently. If our $geoNear spatial query finds no local price data for a recognized service, we learned to seamlessly trigger a "Discovery Fallback" that fires up an external scraping engine (Linkup/Google) to fetch the data on the fly.

The Power of "Zero-API" Automation: We learned that you don't need formal partnerships or APIs to modernize a legacy industry. By using Playwright, we successfully built an agent that bridges the gap between modern fintech (Stripe) and clunky, old-school local service websites.

Managing Async AI UX: We realized that autonomous agents take time to act (e.g., typing out forms like a human). Handling this 30-second delay required a specific architectural decision: utilizing FastAPI background tasks and async state management in Next.js so the user interface wouldn't freeze while the agent did the heavy lifting.

Fintech for AI (Stripe Issuing): Connecting a modern payment gateway to an autonomous web agent is complex. We learned how to provision virtual credit cards on the fly, creating an incredibly powerful "moat" for agentic commerce.

What's next for lgtm

Building a Proprietary Data Moat: Currently, we rely on scraping available public data. Moving forward, every successful transaction our agents complete will feed into a proprietary pricing database. By comparing scraped prices with actual paid prices, our algorithm will learn to identify truly "good" deals, spot hidden premiums, and offer users highly accurate, verified price recommendations that no competitor can easily replicate.

Predictive "Offline" Onboarding: To tackle businesses that have zero online presence (no websites to scrape), we will leverage user search queries to build demand heatmaps. If we detect high demand for phone repairs in a specific region, our system will proactively and automatically email local, offline-only shops to request their standard pricing. This allows us to ingest un-scrapable data into our ecosystem, breaking the final barrier of market transparency and locking in a massive long-term defensibility.

Built With

Share this project:

Updates