-
-
The proceed by login with paypal to access their dashboard
-
Paypal then redirects them to their dashboards after a complete authentication
-
A seller can login in to access the their dashboard.
-
Paypal also confirms to the seller that delivery was received and the money has been paid to their account
-
The deal indicate shipped after the seller makes the shipment and adds tracking code.
-
The deal indicates payment held and waits for seller to make shipment
-
SafeDeal's home page
-
The buyer confirms the deal and if indicates agreed and opt the buyer with a paypal button to proceed to payment
-
Seller proceeds and creates the deal
-
Exported text uploaded on SafeDeal and AI retreiving information from it.
-
The selller sends the deal to the buyer and waits for confirmation
-
Payment verified and paypal window closes
-
The buyer confirms item received upon delivery
-
The buyer clicks the button and it directs him to login to his paypal account for payment
-
The seller access their dashboard where they can manage their multiple deals in one place.
Inspiration
In Kenya, a lot of buying and selling happens in WhatsApp and Instagram chats. A used phone goes from Nairobi to Nakuru, or a pair of trainers comes from a seller you've never met, and one person always has to trust the other first. Buyers lose money to sellers who never ship. Sellers lose goods to fake payment screenshots and buyers who say they never received anything. Escrow services exist, but they ask you to open a new account, install a new app and type the whole deal in again.
I wanted something that starts from the chat people already have and uses the PayPal account they already trust. That became SafeDeal: pay on proof for deals agreed in chat.
What it does
- The seller pastes the chat or uploads the exported chat file. Claude reads it and proposes a deal card with the item, price, courier, ship-by date and conditions. Each field links back to the message it came from.
- Both people confirm the same terms, and the buyer pays with PayPal. The payment is authorised but not captured, so the money stays on hold in the buyer's own PayPal account.
- The seller ships and adds a tracking number, or hands the item over in exchange for a 6-digit code that the buyer only gives once they have it.
- When delivery is proven and the buyer confirms, SafeDeal captures the payment. If the buyer says nothing, the payment is captured when the 48-hour inspection window ends. If the seller misses the ship-by date, the hold is voided automatically.
- Late deliveries, complaints and disputes go to a reviewer, who sees the evidence, an AI comparison of that evidence against the agreed terms, and an audit log that shows if anything was altered. Sellers with many buyers can log in with PayPal and manage all their deals from one dashboard.
The rule behind all of this is simple: the AI proposes and the rule engine decides. Nothing the AI outputs can move money.
How I built it
PayPal. Orders v2 with intent: AUTHORIZE, the JS SDK v6 button, Payments v2 capture and void, webhooks with signature verification, Log in with PayPal (OpenID Connect) for sellers, and read access to the Disputes API. Every PayPal POST carries a fixed PayPal-Request-Id (deal-<uuid>-<action>-v<n>), so retrying after a lost reply can never capture twice.
Rule engine. A state machine with 14 states, and a single module that is the only code allowed to call capture or void. A test fails if anything else tries. Each trigger locks the deal's row, makes its decision, calls PayPal, and then saves the new state and a hash-chained audit entry in one transaction. Every 10 minutes a scheduled job checks deadlines and re-reads PayPal, which recovers deals whose replies were lost.
AI. Claude Sonnet 5.5 through the Anthropic API turns messy chats into JSON, which I validate with Zod. Phone numbers, emails, card numbers and M-Pesa codes are removed before the chat leaves my server. Lines that look like instructions are flagged and never followed. A second prompt compares the seller's photos and notes with the agreed terms, for the reviewer to read.
Stack. Next.js 15, strict TypeScript, Tailwind, and Postgres with Drizzle, hosted on Render as a web service, a database and a cron job. Every screen works on a 360 px phone.
Testing. Unit, database and Playwright end-to-end tests run in CI, with one test for each money-safety rule. A race test checks that a buyer confirming at the same moment as the scheduled job still produces exactly one capture. In 25 randomly generated 31-day deal histories, no seller was ever paid without a verified delivery. On 43 labelled chats, extraction scores 91.4% field-level F1, and the system resisted all 30 of my prompt-injection attacks.
Claude Code. I planned the build in phases, and Claude Code wrote most of the code, tests and documentation under my direction. Every change went through a pull request.
Challenges I ran into
Making "time running out" safe. The obvious design pays the seller whenever nobody complains. I had to guarantee that a timeout on its own never releases money, while still making sure a buyer who goes quiet after delivery can't block payment. My answer is that an automatic capture needs a verified delivery, either a courier event or the handover code. Each of these situations has its own test.
The limits of a PayPal authorisation. An authorisation lasts 29 days, and PayPal only guarantees the funds for the first 3. Every deal's ship-by, delivery and inspection periods therefore have to fit inside a single authorisation, and anything still open by day 26 goes to review before PayPal's limit.
Lost replies and repeated events. Webhooks can arrive late, twice or out of order, and a capture can succeed at PayPal even when its reply never reaches my server. Fixed request IDs, stored event IDs, and re-reading PayPal before every change made each action safe to repeat.
Prompt injection through the chat. My own test harness found two holes: a chat line could close the tag that wraps untrusted text, or pretend to be a new message. I now neutralise both. A database test replays all 30 attacks against a model that deliberately obeys them, and confirms that no money moves.
Sandbox surprises. One early payment was refused with TRANSACTION_REFUSED. Voids came back 403 for one payee account but worked for another. Log in with PayPal needed fallbacks when the userinfo endpoint misbehaved. Each time, the fix started with logging PayPal's debug_id and checking the real state instead of guessing.
What I learned
Authorise-then-capture fits pay-on-proof well, provided the rules around it are strict and tested.
An AI's output is best treated as a suggestion from a source you can't fully trust. I validate it, show where each field came from, and let a person confirm it.
Wording affects trust. A vague "AI: unsure" label made people doubt the whole card, so I replaced it with specific instructions such as "Check this" or "Confirm the US$ price".
Even a small payments app needs careful engineering. Idempotency keys, row locks and reconciliation are what make the claim "your money is safe" actually true.
What's next for SafeDeal
- PayPal Multiparty approval, so SafeDeal can pay sellers as a platform in production
- Real courier tracking feeds, starting with G4S
- Submitting dispute evidence directly through the Disputes API
- More Swahili and Sheng chats, and attacks, in my evaluation set
- Local payment options alongside PayPal
Built With
- anthropic
- claude-code
- drizzle.orm
- github-actions
- log-in-with-paypal
- next.js
- node.js
- paypal
- paypal-js-sdk
- paypal-orders-api
- paypal-payments-api
- paypal-webhooks
- playwright
- postgresql
- react
- render
- tailwindcss
- typescript
- vitest
- zod
Log in or sign up for Devpost to join the conversation.