Inspiration

Dispute decisions rest on scattered evidence: an order record in one place, a carrier scan in another, a chat log, a return policy, and a response deadline counting down. A wrong call costs a buyer or a seller real money. We wanted one place that gathers the evidence, shows what is verified and what is only someone’s claim, and leaves the decision to a person. So our rule from day one was that the AI recommends, a human decides, and everything is logged.

What it does

Guard Pay is a console for PayPal staff who resolve disputes. A dispute arrives from PayPal, and Guard Pay gathers the order, tracking and evidence in one case view. Each piece of evidence is marked Verified, Unverified or Contradicts, so staff see what is established and what is only a claim.

Automatic checks watch for deadlines and for parcels that are stuck or contradict the buyer’s story. Account checks surface unusual history, such as repeated claims in a short time.

Staff can ask the buyer or merchant for more information through PayPal, and then record a decision. The system suggests a resolution, but it never decides: choosing anything other than the suggestion requires a note, and every action, from a decision to an automatic reminder, is written to an audit log.

How we built it

Guard Pay is a staff console for PayPal dispute teams, built by a team of three: backend and PayPal, AI and rules, and frontend. The backend is FastAPI and Postgres, and the console is React and Vite. We integrated with the PayPal sandbox through:

An OAuth client and order lookup. A Disputes API wrapper. Refund and tracking calls. A webhook receiver that verifies PayPal’s signature before doing anything and ignores duplicate deliveries.

Challenges we ran into

The mid-build pivot, and reconciling the two sides afterward. Environment issues: a .env that wasn’t being read (401 errors), database credentials, and Docker where localhost has to become the db hostname. A Render deploy that crashed because the blueprint never supplied a required session secret. Strict signature checks, which reject hand-made webhook tests by design, so real sandbox events were the only valid test. Time, because the AI layer competed with everything else for it.

Accomplishments that we're proud of

A human decides every case, and the code enforces it. The approval and audit rows are saved before any money-moving call is made, and refunds carry an idempotency key, so a double click can’t pay twice. Strict PayPal webhook handling. We verify PayPal’s signature before touching an event, and the database rejects duplicate deliveries. Evidence you can trust at a glance. An item counts as verified only if it comes from PayPal or a carrier. Chats, photos and policy text are labelled unverified, and contradictions are flagged. Real sandbox integration. We tested orders, captures, tracking and dispute lookups against the live PayPal sandbox, and we wrote down what the sandbox can’t do instead of hiding it. Over 100 automated tests, and the database migrations apply cleanly on Postgres. A demo anyone can try. The console runs on built-in sample data with no login or credentials, and the repo includes Postman collections, a mock carrier and a one-click Render blueprint.

What we learned

PayPal’s API can’t create sandbox disputes, so end-to-end tests need a real buyer account to open one. Webhooks must be idempotent, and uniqueness belongs in the database, not in a loop in the code. A safety gate works best as a hard order: approval first, action second. Agree the data contract early. We changed direction from a merchant-and-buyer helper to a staff console, and the frontend and backend drifted apart.

What's next for Guard Pay

Keep the automatic checks running through a proper scheduler, so delivery and deadline watches work even when the service is idle. Harden for production: same-site sessions, rate limiting that works across several servers, and a cleaner developer log page for tracing requests and PayPal calls.

Built With

Share this project:

Updates

Submission history