Inspiration
Small sellers lose disputes they should win. A buyer says "item not received", the seller has a few days to answer, and the evidence that would win (the carrier scan, the signed delivery, the buyer's own "it's out for delivery" message) is spread across three tabs and an inbox. Most sellers refund to make the problem go away, and they lose the item, the money and the fee.
Big merchants have chargeback teams. A one-person shop has nobody, so we built them one.
What it does
Rebuttal is a dispute inbox with an AI investigator behind every case.
- Investigates. For each dispute the agent calls PayPal itself. It reads the dispute, the original order, the shipment tracking and the buyer's transactions, then checks the shop's own records (carrier scans, customer messages).
- Recommends. It returns one of three decisions with a win probability and a plain-English rationale:
- Fight, with a ready-to-send evidence package.
- Partial refund, with the amount (for example $24 for one chipped mug in a $96 set, instead of losing all $96).
- Refund, when the case can't be won and fighting would waste the seller's time.
- Shows its work. Every fact in the evidence trail is tied to the tool call it came from, so the seller can see nothing is made up.
- Waits for approval. Nothing reaches PayPal until the seller clicks approve. Then Rebuttal sends the evidence (with a generated PDF) and the tracking number, makes the offer, or accepts the claim.
- Tracks outcomes. The queue is an AG Grid table with search, column filters, a live totals row for money at risk, kept and refunded, and a CSV export of every outcome for bookkeeping.
The hosted demo runs in a simulator by default, so judges can run the whole flow with no PayPal login. A switch at the top moves to the live PayPal sandbox, where real sandbox disputes went through the same flow and PayPal ruled for the seller.
How we built it
- Next.js 16 + TypeScript + React 19 + Tailwind, hosted on Render (free web service, Blueprint in
render.yaml, health check at/api/health). - PayPal Agent Toolkit (
@paypal/agent-toolkit) for the agent's tools and the core actions:list_disputesandget_disputeto load the inbox and read each case.get_orderto read the original order, items and shipping address.get_shipment_trackingandcreate_shipment_trackingto read and add carrier tracking.list_transactionsto check the buyer's history.accept_dispute_claimto refund when the seller agrees.
- PayPal REST APIs, called directly for what the toolkit doesn't cover:
- Disputes API
provide-evidence(multipart, with a PDF of the seller's response) andprovide-supporting-info. - Disputes API
make-offerfor partial refunds, andaccept-claimas a fallback. - Disputes API
adjudicateto get a sandbox ruling. - Orders v2
/v2/checkout/orders/{id}/trackto attach tracking to the order. verify-webhook-signaturefor incoming dispute webhooks.
- Disputes API
- Google Gemini (
@google/genai,gemini-3.5-flash-litewith automatic fallback to other Gemini models and a 45-second timeout) runs the investigation as a function-calling loop. It picks which PayPal tools to call, reads the results, and must finish by callingsubmit_recommendation. A zod schema rejects invalid output, such as an offer of $0 or an offer at or above the disputed amount. - AG Grid Community for the dispute queue (quick filter, floating filters, a pinned totals row that recalculates when filters change, CSV export with export-only columns) and for the evidence trail grid.
- Investigation cache. Real Gemini runs are saved and replayed, so the hosted demo is fast and doesn't burn API quota.
Challenges we ran into
- Every sandbox dispute became a chargeback. Whatever the buyer chose, the sandbox created an "item not received" chargeback, and PayPal doesn't allow offers on chargebacks. Partial-refund offers are fully built against the Disputes API, but we could only demo them in the simulator. The app reads the dispute's allowed actions first and explains when an action isn't available instead of failing silently.
- Evidence uploads were picky. The sandbox accepted chargeback evidence only one item per call and only with a document attached. Sending several items returned
ITEM_ID_IS_MANDATORYor a server error. We generate a one-page PDF of the seller's response and send the strongest evidence type first, falling through when a type isn't allowed. - Agent Toolkit quirks. The toolkit reports failures as a normal return value (
ok: false) rather than throwing, which at first made a failed refund look successful. We now treat that as an error. It also calls a legacy sandbox host that our locked-down hosting network blocked, so we point it atapi-m.sandbox.paypal.com. - Refunds and currency. Our seller account is based in India and had no USD balance, so a real refund came back
INSUFFICIENT_FUNDS. The app shows that clearly. We also learned a buyer from the same country couldn't pay this seller in USD, so we used a US sandbox buyer. - Slow sandbox disputes. The first dispute took about four hours to appear in the API; later ones took minutes. We added a seeding script that creates and captures orders, adds tracking, and walks through filing the dispute.
- Picking a model. Some Gemini models returned 404 for new keys and others hung. We added a fallback chain and a timeout so one slow model never freezes the app.
Accomplishments that we're proud of
- A real end-to-end win in the PayPal sandbox: a $184 dispute investigated by Gemini, evidence and tracking sent through PayPal, and the case resolved in the seller's favour.
- The agent sometimes says "don't fight". Recommending a $24 partial refund or a straight refund when that's the honest answer is what makes it trustworthy.
- Every claim in the evidence trail traces back to a PayPal API call or a shop record.
- Judges can run the whole thing in a browser with no account.
What we learned
- Sandbox behaviour differs a lot from the docs. Chargeback-only disputes, single-item evidence and cross-border currency rules all shaped the design.
- Agentic commerce needs a human approval step. The value is the investigation and the draft; the seller's click is what makes it safe.
- Small details matter for trust. Showing the source of each fact did more than a higher confidence score.
What's next for Rebuttal
- Run on a production PayPal account with webhooks, so new disputes are investigated the moment they're filed.
- Pull carrier proof directly from UPS, USPS and FedEx APIs, and order data from Shopify, Etsy and WooCommerce.
- Learn from outcomes: use won and lost cases to tune when to fight, offer or refund.
- Deadline reminders and an optional auto-approve rule for small, clear-cut cases.
- Team accounts for shops with more than one person handling disputes.
Built With
- ag-grid
- google-gemini
- next.js
- node.js
- paypal
- paypal-agent-toolkit
- paypal-disputes-api
- paypal-orders-api
- react
- render
- tailwindcss
- typescript
- zod
Log in or sign up for Devpost to join the conversation.