Inspiration
This summer my girlfriend found a dead mosquito in our malatang. The restaurant refused to pay us back, and the platform sent us back to the restaurant. Every refund system asks should we refund? The real question is who pays? The customer pays first and argues last, and nobody keeps a record everyone trusts.
What it does
FairSettle is an AI referee for delivery disputes, built on PayPal.
- A customer orders in the storefront and pays with PayPal checkout.
- They file a complaint (for example, food safety: a dead mosquito).
- A LangGraph agent reads the order, the delivery events, the payment in the ledger and the customer's complaint history, and proposes an outcome: refund type, amount in cents, and the liable party as basis points (restaurant / driver / platform). Every reason cites a record.
- Fixed policy code checks the proposal: amount caps per reason, cited evidence, delivered order, repeat complaints. Any violation escalates to a person.
- The agent cannot move money. A reviewer approves the exact proposal with one click.
- The ledger refunds on PayPal, then posts a journal that charges the liable party. Nothing says "refunded" until PayPal answers; retries reuse one idempotency key, so there is only one refund. ## How we built it
- Ledger (Java 21, Spring Boot, PostgreSQL, Kafka, Redis): double-entry, payment and refund state machines, PayPal Orders and Refunds adapter, verified PayPal webhooks, signed merchant notifications, the review page.
- Dispatch (NestJS, TypeORM, PostgreSQL, Redis) and a Next.js storefront: orders, couriers, PayPal checkout, the order timeline the agent reads.
- Agent (Python, LangGraph, LiteLLM, DeepSeek): gather → investigate (up to three read-only tools) → decide → policy → submit. Tracing in Langfuse records step and tool names only, never complaint text or evidence.
- Complaint page (Gradio).
- Contracts first: OpenAPI and GraphQL contracts in
contracts/, recorded fixtures, typed clients. - An evaluation suite runs the PRD scenarios against the real model: 29/30 correct, 0 policy violations; a food-safety check proposes a full refund charged to the restaurant 3/3. ## Challenges we ran into
- Head-of-line blocking in the liability worker. A batch picked rows with a weaker rule than the one it posted with, so 25 stuck rows could starve every newer refund. Fixed with an attempt cursor that rotates stuck rows to the back.
- The agent refused food-safety refunds. In rehearsal it escalated every "mosquito in my food" complaint because no photo reached it. We defined that the customer's report is the evidence unless the records contradict it, and added a real-model check. ## Accomplishments that we're proud of
- The AI proposes; a person approves; only the ledger touches PayPal, and every cent is integer and on the books.
- Seven ledger invariants, append-only postings, unknown provider outcomes resolved by querying, never by resending.
- The whole chain runs on the PayPal sandbox end to end, locally and deployed. ## What we learned Agentic commerce needs boundaries more than autonomy: an agent is most useful when it explains a decision with citations, a policy can veto it, and money moves only through a system that can prove what happened. ## What's next for FairSettle: AI refunds that name who pays Photo evidence, partial liability splits learned from history, restaurant-side dispute responses, and payouts that settle each party's share.
Built With
- caddy
- deepseek
- docker
- gradio
- graphql
- java
- kafka
- langfuse
- langgraph
- litellm
- nestjs
- next.js
- paypal
- postgresql
- python
- react
- redis
- spring-boot
- typescript
