Inspiration

A while back, one of us was running a product with payments built right in. A customer paid, the payment went through, and then something went wrong with the order. The customer was annoyed, and fairly so. They simply wanted a fix.

Instead it turned into a dispute, and the money was held while it sat open. Then our cloud provider's bill came due, and we couldn't access the money we needed to pay it. Everything needed to settle it was already in the payment record. Nobody was looking.

The customer waited. We waited. Nobody was being helped. Settle is the tool we wish we'd had that week.

What it does

Settle is an autonomous AI mediator for PayPal disputes. When a buyer opens a dispute, Settle:

  1. Detects it, from a PayPal webhook or by polling.
  2. Gathers what PayPal already holds: the dispute, the transaction, shipment tracking and what both sides said, assembled into one case file.
  3. Reasons through a fixed chain: classify the dispute, weigh the evidence, apply the seller's fairness policy, choose an outcome.
  4. Acts or escalates. If the decision clears the seller's guardrails, Settle carries it out through PayPal: a full or partial refund, a replacement offer, or accepting the claim. If not, it escalates to the seller with a recommendation, and the seller approves or rejects with one click.
  5. Explains the decision in plain language for both sides, and records it in an audit trail.

Sellers watch the reasoning stream live in their console. They write their policy in plain words ("replace before refunding", "always refund under $25") and set hard limits the AI can't override: a confidence floor, an amount above which a human always decides, a ceiling on partial refunds, and a cap on accepting claims automatically.

Today Settle covers three dispute types (not received, not as described, unauthorized or other) and three outcomes (refund, reship, accept the claim), plus escalation.

How we built it

One rule shaped the whole design: the AI chooses, PayPal executes.

  • Mediator: AWS Bedrock's Converse API with tool use, with a fallback chain across Claude and Amazon Nova models. A LangGraph engine runs the same chain and can be switched on by config.
  • Safety boundary: the mediator's entire action surface is four propose_* tools. They record a proposal and nothing else. They cannot move money.
  • Executor: the only code that touches money. It checks every proposal against the guardrails (confidence, amount, refund ceiling, auto-accept cap, amount validation) before any PayPal call, and gives a plain reason whenever it escalates. If a PayPal call fails, the case escalates to the seller instead of failing silently.
  • PayPal APIs: Customer Disputes v1 (list, show, make offer, accept claim), Payments v2 (show capture, refund) and Shipment Tracking v1, through a typed REST client.
  • Backend: FastAPI with async SQLAlchemy 2.0, dependency injection and Alembic, in a layered architecture (api → core → domain ← infrastructure) whose boundaries are enforced by import-linter.
  • Live reasoning: a WebSocket streams each step of the trace and the final decision to the seller's console, and carries the seller's approve or reject back. Every open tab follows along.
  • Frontend: React 19 and TypeScript on Vite, TanStack Router and Query, a Zustand store fed by the socket, shadcn/ui on Tailwind v4, and API types generated from the backend's OpenAPI schema.
  • Testing: offline test suites on both sides, with no AWS, PayPal or database needed. The backend covers guardrails, the mediator, the API and the WebSocket. The frontend uses Vitest with MSW, Playwright end to end, and axe accessibility checks.

Challenges we ran into

  • Getting a PayPal account. Signing up for a PayPal account from our region runs into regional restrictions, so we couldn't work with real sandbox disputes. We built a fixture mode instead: seeded disputes in the same case-file shape the live PayPal source produces, with every money movement running as a dry run. The integration is written against PayPal's real APIs, and switching sources is a configuration change.
  • Letting an AI near money safely. Telling a model to "be careful" isn't a guarantee. We moved safety out of the prompt and into the architecture: the model can only propose, and a separate executor with hard limits decides whether anything happens.
  • Making the reasoning watchable. Streaming a live trace meant handling dropped connections, reconnects, a second tab watching the same run, and a mediation that never starts. In staging, the API sits behind a path prefix, which quietly broke the WebSocket URL while REST kept working. That one took some digging.

Accomplishments that we're proud of

  • A complete dispute flow, from detection to a plain-language explanation, that a seller can watch happen live.
  • Guardrails the AI can't argue its way past. Money only moves through a PayPal API, and only after the executor's checks.
  • Sellers stay in control: their policy in their own words, their limits, and the final say on anything large or uncertain.
  • Every decision is explained and auditable, for both the seller and the buyer.
  • A codebase we want to keep building on: enforced layer boundaries, swappable AI engines, and tests that run anywhere.

What we learned

  • Most disputes don't need a long investigation. The facts are already in PayPal. What's missing is someone to put them side by side and make a call.
  • Safety in AI agents is an architecture problem more than a prompting problem. A narrow set of tools and limits enforced in code beat instructions.
  • Seeing the reasoning is what makes an automatic decision feel trustworthy, so we made the live trace a core part of the product instead of a debug log.
  • Being upfront about limits made the design better. Because we couldn't use live data, the data source became one cleanly swappable piece.

What's next for Settle

  • Running on live PayPal accounts, starting with sellers in supported regions.
  • More dispute types and outcomes beyond today's three of each.
  • A fully autonomous mode driven by PayPal webhooks, so disputes are handled the moment they open.
  • Sending the plain-language explanation straight to the buyer through PayPal's dispute messaging.
  • Suggesting policy changes based on what a seller approves and rejects.
  • Explanations in the buyer's own language.

Built With

Share this project:

Updates

Submission history