You call one shop, get a price, and settle, because who has time to call five more or haggle with each one? Callsweep calls them all for you and haggles on every call, trying to get the price closer to your budget. Then it shows you the best offers, and you choose which one to book.

Inspiration

It's a Tuesday afternoon and your car won't start. You need it back today. Google finds a dozen garages nearby. Their pages list hours, directions, a stock photo, and almost nothing that matters. Not today's price. Not whether they can even fit you in.

So you call. First shop: $380. Is that fair? No idea. The only way to know is to call the next one, and the next, asking the same three questions on hold each time, while your car sits dead in the driveway. Second shop: $340. Third rings out. By the fourth you're out of patience, so you book the $340 and hope you didn't overpay. And you never once pushed back on the price, because who has the nerve to haggle a garage on the phone four times in a row.

You didn't get the best deal. You got the best of the two you had the patience to reach. That's the problem.

The best deal is rarely online. It's whatever the person who picks up says, right now, and it sits behind a wall of phone calls nobody has time to make. I wanted to hand that whole job to an agent that doesn't get tired, calls every shop, and does the one thing most of us never do: actually haggle, every time.

What it does

You type what you want and a budget, like "haircut under $40". Then:

how it works

  1. Figures out the request with Groq (what service, where, and your budget).
  2. Finds real shops nearby from OpenStreetMap (no API key).
  3. Calls each shop once with CALL-E. It asks their price, then haggles toward your budget: "can you do any better, closer to $40?" And if they won't come down on price, it asks what they can throw in instead, a wash, an add-on, a faster slot. It also tells them it'll confirm and call back, so nothing gets booked by accident.
  4. Ranks them by the best deal, not just the cheapest. A $28 cut with a wash can beat a $27 cut with nothing, which is exactly why the extras matter.
  5. Shows you the list and asks which one to book. You decide.
  6. Calls your pick back to book it, and gives you the details.

You just watch the board and pick at the end.

The part I'm proud of

Most "call around" tools stop at a list of quotes. The number they show you is just the first thing the shop said. Callsweep haggles on every call, so what you see is already the lower price, not the sticker one. And when a shop won't drop its price, it doesn't just give up, it goes after value instead: "can't do $40? then what can you include?"

You: "haircut under $40"

It calls each shop, asks the price, then negotiates:
  Sharp Cuts    $37                    already under budget
  Fade Factory  $42 -> $40             haggled down to budget
  Style Studio  $49 -> $45  +wash      wouldn't hit $40, threw in a wash
  Classic Cuts  $51 -> $48  +massage

Ranked by best deal:
  [1] Sharp Cuts    $37
  [2] Fade Factory  $40
  [3] Style Studio  $45  +wash

Book which? Enter 1-4:  ___     <- you decide

The hard part wasn't making calls. It was moving a price inside a normal conversation and pulling a clean number back out of it. CALL-E runs each call on a fixed goal, so I had to script the haggle right into the call: ask the price first, then push toward the budget, then hang up politely without booking. And the booking itself is always my choice, the agent never books until I pick one.

One call per shop, ever. Calling every shop back with "the best I have is $35, can you beat it?" would squeeze out more money. It would also mean every shop in town gets dialled twice by a robot, and that's the line between a useful assistant and a nuisance. So the negotiation happens once, inside the call it was always going to make.

How I built it

Layer What's running
Runtime Bun + TypeScript
Calls CALL-E (@call-e/calle). createAndWait with recipientResultSchema for structured results. Two kinds of call: quote-and-haggle to each shop, and a booking call to the one you pick
Understanding Groq (openai/gpt-oss-20b), turns the request into { category, location, priority, budget }
Discovery OpenStreetMap, Nominatim to geocode and Overpass to find shops with phone numbers
View A live terminal board that fills in as results land

Two things are always real: the shops (pulled live from OpenStreetMap, real names and numbers) and the phone calls once you set MOCK=false. By default it runs in mock mode, so anyone can try the whole flow without spending money or calling strangers. The real path is the same code. And every real call is gated: it only dials numbers you put on an ALLOWED_PHONES allowlist, masks them in the output, and asks you to type yes first.

What I got working

  • Real shop discovery, end to end, from a plain-English request with no API key.
  • The agent haggles on a live CALL-E call and reports the price it got down to.
  • Same pipeline places real CALL-E calls, mock is just the default.
  • I make the booking call, not the agent. It shows the ranked deals and books the one I pick.
  • It ranks by best deal, so a slightly pricier shop with a free wash can win.

What's real, and the one thing I chose not to do

Everything about the shops is real. Names, addresses and phone numbers come live from OpenStreetMap, and with MOCK=false the same code places real CALL-E calls.

But I never dialled an actual business. Every real call this project has made went to a phone I own, on an allowlist I wrote myself, with a yes typed at the prompt first. That is a deliberate choice, not a gap I ran out of time to close. A haircut shop did not sign up to be a test subject for my hackathon project, and I am not going to tie up a small business's phone line to prove a point about negotiation.

So, precisely:

  • Verified on real calls: outbound dialling, the two-step haggle script, the structured price coming back per recipient, and the allowlist refusing anything not on it. Logged locally during testing.
  • Not verified on real calls: a stranger's shop actually lowering its price. The negotiation logic is exercised against a real phone and a real conversation, but the person on the other end was me.

The safeguards this design already has are the reason I would be comfortable pointing it at real shops: it opens by saying it is an assistant calling on behalf of a customer, it only pushes against a budget the user really set, it never invents a competing quote to squeeze anyone, and it hangs up without booking. Haggling is ordinary commerce. Pretending to be a human, or making up a rival's price to apply pressure, would not be, and it does neither.

Challenges

  • CALL-E checks that a task is concrete. A vague one ("beat the price for the service") gets rejected, and the booking call needs a real date and a name. So I learned to spell out the service, the target, the date, and the customer every time.
  • Its result schema doesn't like nullable unions. price: ["number","null"] got rejected, so I used single types and marked optional fields not-required.
  • "Only haggle if the price is above budget" got ignored mid-call. I rewrote it as a plain two-step (ask price, then push lower) and then it worked every time.
  • I thought one call with many recipients would dial in parallel. It's a sequential survey, and the free tier serializes anyway, so I stopped claiming parallel.
  • Calls started dying instantly with failureCode 480, three times in a row, after working fine earlier the same day. I decided the carrier was throttling repeated AI calls, wrote that down as the cause, and moved on. It wasn't the carrier. My own phone had quietly added the number to its block list after a few robot calls in a row. A 480 tells you the call never connected, not why, and I had filled in the why myself.
  • Free APIs are flaky. Groq retired the model I started on, and Overpass times out a lot, so I added a mirror fallback and caching.

What I learned

  • The interesting part of a phone agent isn't placing the call, it's what it does during the call. Haggling is something software can now do that a tired person on hold usually won't.
  • "Cheapest" is the wrong goal. People want the best deal, which is price plus what's included plus how soon. That changed how I ranked everything.
  • Leave the booking to the human. Automating the calls and the haggling saves the annoying part, automating the commitment would just be scary.

What this is NOT

  • Not a spam dialer. It says up front it's an assistant calling for a customer, and it only haggles against a real budget, never a made-up competing quote.
  • It doesn't invent prices. If a shop won't quote on the phone, it says "wouldn't quote".
  • It doesn't book behind your back. Nothing happens until you pick a shop.
  • Not for medical, legal, or financial calls.

What's next

  • Shop-vs-shop leverage without a second call: carry the best real quote forward through the sweep, so a shop called later hears "I've been quoted $35 today, can you beat it?" on its one and only call.
  • Let people trade off price, speed, and extras instead of one priority.
  • Haggle the whole offer, not just the price ("beat $28 with a free wash").
  • If a shop says "we're out, try Miller's", add Miller's to the list automatically.

Built With

Share this project:

Updates

Submission history