Home/Lead marketplace development

Build a contractor lead marketplace of your own

There are two ways to be in the lead business: rent them from a network, or own the platform that sells them. This is the studio that builds the second one — intake, checkout, matching, and delivery, running on infrastructure we build and maintain. We have one in production right now.

Renting leads means buying an outcome you cannot inspect

When you buy from a lead network, the terms are usually theirs. You do not set the price, you do not see the routing, and you cannot tell how many other contractors got the same request. When the price moves or the radius widens, you tend to find out from your bank statement.

Owning the platform changes what is yours to decide. You set the intake form, the price of each category, who is eligible to receive a lead, and the record of what was sent and whether it arrived. That platform is five systems that have to agree with each other:

  • Intake and qualification — what the homeowner tells you, and what makes it worth selling.
  • Pricing, checkout, refunds — what a lead costs, who gets a discount, what happens on a dispute.
  • Matching and routing — who is eligible, how many get the lead, in what order.
  • Delivery with proof — the message goes out and you can show it arrived.
  • Attribution — what your ad spend bought, measured where a browser cannot lose it.
All Service Leads, a live two-sided lead marketplace built by Hummus Development
CASE STUDY

A live lead marketplace

A two-sided marketplace that takes a homeowner’s request, charges the buyer, and gets the lead to the contractor who should have it — payments, messaging, and matching all running on infrastructure we built and maintain.

Visit the live site ->
Live atallserviceleads.com
TypeTwo-sided lead marketplace, built and maintained by us
PaymentsLive Stripe checkout, custom coupon engine, admin-side refunds
MessagingTwilio SMS fan-out with per-message delivery tracking
DataSupabase Postgres behind a PgBouncer pooler, row-level security
AttributionMeta CAPI + GA4 with server-side dedup
BackendRoughly 8,000 lines of Node across Netlify Functions
StackNode, Express, Netlify Functions, Supabase, Stripe, Twilio, Meta CAPI

What is inside it, and why each piece is built that way

The backend is roughly 8,000 lines of Node across Netlify Functions, monitored daily on the paths that handle money. Here is what those paths do, and what goes wrong when they get built the easy way.

Money logic lives on the server, never in the browser

The browser is your customer’s computer running your code. A price, a discount, or a quantity that arrives from it can be edited on the way, so none of them decide anything. The price of a lead, the validity of a coupon, and the amount charged are all settled on the server. The browser is told what happened; it does not get a vote.

The same holds for the moment a lead is released. A buyer landing on a success page is not proof of payment, it is proof that a redirect happened. The signed webhook Stripe sends your server is the proof.

What a coupon engine has to get right

A discount code looks small until you write one. It has to know whether it is single-use or multi-use, whether the limit is per code or per buyer, when it expires, which categories it covers, whether it stacks, and what happens on a refund. Two of those cost money.

The first is the race. Two buyers redeem the last use of a code in the same second. If the system reads the remaining uses and then writes the redemption as two separate steps, both reads pass and you give away more than you meant to. Redemption has to be one atomic operation in the database, not a read followed by a write in application code.

The second is the refund: when you refund an order that used a single-use code, does the use come back? Either answer works, having no answer does not. Refunds are issued from the admin side rather than the Stripe dashboard, so whoever clicks refund is inside the system that also knows what the coupon did and where that lead went.

Per-message delivery tracking, because an undelivered lead is a refund

Fan-out means one lead can reach several contractors at once. The important word is not fan-out, it is tracking. Every message gets its own record and its own status callback — queued, sent, delivered, undelivered, failed — because Twilio accepting a message is not the same as a carrier delivering it. US carriers filter business texting, and a number can be blocked while your code keeps getting clean responses from the API.

Without that, the failure is invisible: the buyer paid, the system says it sent, and the first you hear is a phone call about a lead that never showed up. With it, an undelivered status is a row someone can act on before it becomes a refund.

Row-level security, when your buyers are each other’s competitors

In a lead marketplace every buyer competes with every other buyer. One contractor seeing another’s orders, prices, or lead history is not an embarrassing bug. It is the end of the business.

Leaks like that rarely come from an attack. They come from an endpoint that takes an ID and forgets to check who is asking — change the number in the URL, see someone else’s data. Row-level security moves that check into Postgres itself. The rule lives on the table: a buyer reads the rows that belong to them, and a query that forgets its filter returns nothing anyway.

The PgBouncer pooler is there for a related reason. Serverless functions open connections in bursts, and without pooling a traffic spike exhausts the connection limit and checkout stops taking money at the moment there is most of it to take.

Server-side conversion dedup, because ads are how the marketplace fills

Ad platforms optimize against the events you send them, and browser pixels lose events: blockers, privacy settings, a tab closed before the pixel fires. Meta’s Conversions API sends the purchase from your server instead, because the server is what charged the card.

Run both and the same purchase can arrive twice, which teaches the platform to bid on the wrong things. Dedup fixes it: both events carry the same event ID and the platform collapses them into one. GA4 gets the same treatment, so your reporting and your ad account stop disagreeing.

That is commercial, not technical. Cost per acquisition and revenue per lead are the same conversation, and holes in the data mean you are guessing at the number that decides whether you scale spend or cut it.

What “monitored daily on the paths that handle money” means

The checks point at the places where failure costs money — checkout, the payment webhook, lead delivery, message status — and they run on a schedule instead of waiting for someone to notice.

The narrow scope is deliberate. A broken image on a marketing page can wait; a checkout throwing errors cannot. A lead paid for and never delivered is worse still, because a loud failure tells you and a quiet one shows up later as a refund.

What building one involves for you

Scope and pricing come first, in plain language, with a hard launch date, written and signed off before a line of code gets written. Pricing is fixed and agreed before work starts. The decisions that set the schedule are yours, not ours:

  • What a lead is, and when it becomes billable. A form submission? A verified phone number? An answered call?
  • Price per category and per area, and whether a lead is exclusive to one buyer or shared.
  • How many contractors a lead goes to, in what order, and how long each has before it moves on.
  • Your refund policy, in words, before it is code. Written down, it becomes a rule the software enforces rather than a weekly argument.
  • Who is allowed to buy — open signup, or approval with license and insurance checked first.

Our side is the build: Stripe with the money logic on the server, Twilio numbers plus the carrier registration US business texting requires, the database and its security rules, the admin screens your team runs the day on, the ad conversion pipeline, and the launch — apex DNS cutover, SSL, sitemap submission, Search Console and GA4 wired, real-device smoke tests before we call it live.

You see it daily while it is built. Deploys go out on preview URLs, you review the real thing live, comment inline, and we ship the change the same day. You talk to the person writing the code. Afterward there is an optional monthly retainer for patches, analytics, new features, and the daily monitors.

What you end up with is a platform of your own rather than a seat in someone else’s, which is the problem you started with.

Smaller versions of the same machine

A marketplace is the largest thing we build, but its parts show up smaller. Pickup and delivery scheduling for a dry cleaner is the same intake-and-messaging problem in a smaller box, and an auto shop booking flow is that again. If the buyer side belongs in a phone, that is iOS app development. To talk it through, get in touch, or look through the rest of the studio first.

You have the demand. Own the platform that sells it.

Tell us what a lead is worth in your market and who should receive it. You get scope, fixed pricing, and a launch date back before any code is written.