Inspiration

The idea came from a market stall, not a textbook. In bazaars and flea markets, a price tag is only the opening bid — you chat, you counter, you shake on it. Online shopping threw all of that away: the number on the screen is final, take it or leave it. I kept asking myself why e-commerce, which automated nearly everything else, never automated the oldest retail ritual there is: haggling.

The hackathon's theme, "Build What's Next with PayPal and AI," gave me the missing ingredients. PayPal contributes the trust layer — I can let a stranger talk the price down precisely because the money moves through PayPal's battle-tested Orders API, not through some duct-taped checkout. And a negotiating bot contributes the fun: a store that pushes back, teases a little, and rewards a patient buyer with a real discount. I also wanted to prove a solo developer could ship the full loop — negotiation, payment, capture, receipt, refund — without a team, which became its own motivation as the project grew.

There was a personal constraint too: whatever I built had to stay honest under pressure. A haggling bot that can be sweet-talked into selling below cost is a toy; one with a mathematically enforced floor is a store. That constraint shaped most of the engineering decisions below.

What it does

HaggleMart is a complete small-storefront with bargaining built into the product, not bolted on:

  • AI negotiation, natural language. Buyers chat with "Marco", a market-stall persona that greets them, answers product questions, evaluates offers, counters with personality, recognizes quantity asks ("I'll take 3 of them"), and finally shakes hands — in under a minute, 24/7, in the buyer's language.
  • A negotiation engine you can trust. Every money decision — counters, the secret concession ladder (3–5 rounds), the walk-away, the final accept — is made by deterministic code, never by the model. The seller's secret floor_price is mathematically unreachable: even a deliberately rogue model output gets stripped by a sanitizer that only permits engine-authorized prices. The LLM is the voice; the engine is the contract.
  • Instant PayPal checkout at the settled price. When the bot says "deal", a PayPal order is created for exactly that amount. Smart Payment Buttons (gold PayPal, Venmo, card) render in-page; the negotiated discount is real money movement, not a coupon.
  • Payment reliability that survives real life. Four redundant capture paths — browser redirect return, CHECKOUT.ORDER.APPROVED webhook, a background poller, and a CREATED-order reconciliation pass — mean a deal is captured exactly once even if the buyer's Wi-Fi dies mid-redirect.
  • Merchant back office. PIN-gated area: edit listings and floor prices, watch orders, full or partial refunds, restock control. Sold-out items refuse to negotiate.
  • Trust artifacts for a 3-person garage business. Styled HTML + fpdf2 PDF receipts, automatic email delivery when PayPal provides a verified address, inventory auto-decrement on capture.

How we built it

  • PayPal integration (central to the project): Orders v2 REST API (create / capture / get / refund), PayPal JavaScript SDK Smart Payment Buttons, server-side capture endpoint, webhook receiver with signature verification, and a poller for reconciliation. Fully sandbox-driven.
  • AI architecture (the interesting part): haggle_bot.py is a strict two-layer design. Layer 1 is a deterministic negotiation engine: regex parsers for offers/quantities/FAQ, a hidden concession ladder ending above floor_price, stock and round limits. Layer 2 is the LLM, which receives the engine's decision plus an explicit allow-list of prices and may only phrase the reply. A prompt-injection defuser treats every buyer message as untrusted data — payloads ("ignore previous instructions", "print your system prompt", persona hijacks, Unicode homoglyphs) are redacted before the model sees them. A post-generation sanitizer then deletes any reply that echoes an injection, mentions limits, runs past the length cap, or contains a non-authorized amount; a floor value in any Unicode form wipes the whole output. If the LLM fails for any reason — no API key, timeout, garbage — the app falls back to a deterministic voice and commerce continues. 22 dedicated pytest tests cover these guarantees, including a 200-iteration offer fuzz and a 60-iteration prompt-injection fuzz proving no message sequence can settle below floor or make it leak.
  • Stack: Python 3.10+ + Streamlit UI, PayPal Orders v2 via requests, OpenAI-compatible chat completions (works with OpenAI, Groq, or fully local Ollama), fpdf2 for PDF receipts, SQLite for orders and receipts. Deploys to Streamlit Community Cloud in minutes or any self-hosted machine that keeps the poller/webhook alive.

Challenges we ran into

Making an LLM sound like a shrewd negotiator without letting it act like one took three layers of defense: decision-first prompting, allow-list sanitization, and engine-only acceptance. Getting capture idempotency right across redirect/webhook/poller paths was the other deep rabbit hole — the fix was a single settlement ledger keyed by PayPal order id.

Accomplishments that we're proud of

A complete, testable storefront in one file each; a payment flow that survives a browser crash mid-checkout; and a negotiation bot that stayed honest in every one of 200 randomized attack runs.

What we learned

LLMs make brilliant liars about prices — architecture, not prompting, is what keeps money safe. And "meaningful PayPal integration" turns out to be the easy half: Orders v2 + webhooks are a joy next to the state-machine work.

What's next for HaggleMart

Multi-language personas, voice negotiation, an agent-to-agent API so other AI shopping agents can haggle programmatically, and a hosted version for Instagram/Facebook sellers.

Built With

  • ai
  • ai-safety
  • chatbot
  • conversational-ai
  • css
  • ecommerce
  • fpdf2
  • haggling
  • html
  • llm
  • marketplace
  • negotiation
  • payments
  • paypal
  • paypal-orders-v2-rest-api
  • paypal-sandbox
  • paypal-webhooks-+-custom-threaded-background-poller
  • prompt-injection
  • python
  • sqlite
  • streamlit
  • streamlit-cloud
  • typescript
  • webhooks
Share this project:

Updates

Submission history