I asked a simple question: what if the ranking of a car was a public, verifiable computation, and the payment that followed it was recorded permanently? That question became RentalRide.
I entered the PayPal AI Hackathon because PayPal is the only payment rail that a mainstream renter actually trusts — and Agentic Commerce needs a bridge between AI decisions and real settlement. I wanted to build that bridge.
What it does
RentalRide is a verifiable P2P rental protocol. It has three layers:
- Natural-language search (AI)
You type:
"Find the cheapest electric car with the best interior and low mileage."
A Flask backend sends this to DeepSeek, which parses it into a weighted vector: w = (w_price, w_mileage, w_power, w_rating, w_year, w_interior, w_fuel)
The result is a score and car ID that anyone can reproduce. No server decides the winner — the contract does.
- Payment + verifiable settlement (PayPal + CarBridge)
The user picks a car, connects MetaMask, and pays via PayPal Sandbox. Our Java backend:
Creates a PayPal order (POST /api/paypal/create-order).
On approval, captures it (POST /api/paypal/capture-order).
Records the payment in CarBridge.sol — a Solidity contract on Robinhood Chain — with the PayPal capture_id, rental_id, amount, and timestamp.
After that, the rental is permanently on-chain: searchable on Arbiscan-style explorers, auditable, and non-repudiable.
Stack:
- UI: HTML + ethers.js v6 + PayPal JS SDK
- AI: Flask, DeepSeek API
- Reverse proxy: Caddy + nip.io (Let's Encrypt)
- Payment API: Java 21, Spring Boot 3.2.5, PayPal Checkout SDK 2.0.0
- Blockchain: Robinhood Chain Testnet, Stylus (Rust), Solidity 0.8.x, web3j 4.12
- Hosting: VPS (Contabo), GitHub Pages
Search:
User types query → POST /api/parse (Flask).
DeepSeek returns weights.
findBestCar(carIds, weights...) on Stylus → returns (bestCarId, score).
cars(bestCarId) on CarBridge → returns full car data.
Render top car + alternatives.
Rent:
User clicks Rent → modal → Confirm booking.
PayPal Button SDK → POST /api/paypal/create-order.
User approves in PayPal Sandbox.
POST /api/paypal/capture-order → Java captures via PayPal API.
Java calls CarBridge.recordPayment(rentalId, orderId, amount) via web3j.
PaymentRecorded event emitted on Robinhood Chain.
Challenges we faced 1. Getting HTTPS on a bare VPS
GitHub Pages serves over HTTPS. PayPal JS SDK requires HTTPS. Our VPS only had HTTP. We tried Cloudflare quick tunnels — but Edge caching returned 404 for every path we proxied, even after Registered tunnel connection. We spent hours debugging before switching to Caddy + nip.io, which obtained a Let's Encrypt cert in 20 seconds.
Lesson: trycloudflare.com quick tunnels are not reliable for production-ish demos. Caddy is 10 lines and just works. 2. Mixed content (HTTPS → HTTP)
The UI on https://mafsc.github.io couldn't call http://194.5.152.242:5050 — browsers block mixed content. We solved it with two HTTPS endpoints:
https://194-5-152-242.nip.io (Caddy) for the AI backend.
https://1b6d-194-5-152-242.ngrok-free.app (ngrok) for PayPal.
Both point to the same VPS. The UI uses different API_BASE constants for each. 3. Separating "what AI decides" from "what code decides"
Inspired by Tally (winner of Agents for Humans Hackathon), we drew a hard line:
The AI names the weights. The Stylus contract computes the ranking. The Java backend records the payment. No single component can lie.
This meant:
DeepSeek never sees the car list — only the query.
Stylus never sees the query — only the weights.
Java never computes — only proxies and records.
This separation is what makes the system verifiable, not just "AI-powered." 4. Key management (and one leak)
Early in development, our start.sh had a hardcoded private key visible in ps aux. I cleaned the git history with git filter-repo, moved secrets to secrets/*.env (chmod 600), and rewrote start.sh to read from environment variables via source. Then I removed -D JVM flags so secrets don't appear in process listings.
Lesson: Never pass secrets via -D. Always use env vars, and verify with ps aux | grep java. 5. PayPal Sandbox quirks
PayPal's Sandbox is not as polished as its documentation suggests. We learned to:
Use https://api-m.sandbox.paypal.com (not api-m.paypal.com).
Capture after user approval, not before.
Never test capture-order with curl alone — it needs a UI approval step.
Use test cards 4012888888881881 / CCREJECT-REFUSED for error triggers.
Accomplishments we're proud of
Working end-to-end demo — from plain English query to on-chain payment record, in one UI.
Verifiable ranking — the car selection is deterministic and reproducible from weights.
Real PayPal integration — Sandbox create/capture with proper OAuth2 flow.
Real blockchain settlement — CarBridge.sol emits PaymentRecorded events on Robinhood Chain Testnet.
Stylus contract — the ranker runs as WASM on-chain, not as an off-chain service.
Deployed on production-like infra — GitHub Pages + VPS + Caddy + ngrok + Flask + Java.
CORS, HTTPS, mixed-content — all fixed.
What I learned
Verifiability is a UX feature, not just a technical one. Users don't want to "trust the algorithm" — they want to check it.
Caddy is the fastest way to HTTPS on a bare VPS. nip.io gives you a free domain that resolves to your IP.
Cloudflare quick tunnels are unreliable for proxying non-trivial paths.
PayPal's SDK abstracts a lot, but you still need to understand the Orders v2 API to debug.
Separating AI from code is a design choice — and it makes the product stronger, not weaker.
Git history matters. One leaked key in a commit meant rewriting history with filter-repo — a painful but necessary lesson.
What's next for RentalRide Short term
Mainnet PayPal — move from Sandbox to Live credentials.
Multi-currency — support EUR, GBP, JPY via PayPal's currency_code.
Deposit + dispute — hold a refundable deposit in CarBridge, release after rental completion.
Reputation NFTs — mint a soulbound token for each completed rental.
Medium term
Decentralized arbitration — if the renter disputes the car condition, an on-chain jury (via Kleros or similar) rules on the deposit.
Insurance integration — partner with a crypto-native insurer to cover rentals automatically.
Agent-to-agent rentals — let an AI agent rent a car on behalf of a human, using PayPal's Agentic Commerce rails.
Long term
Move ranking fully on-chain — remove the Flask/DeepSeek dependency by using an on-chain LLM oracle (e.g., Ora or Ritual).
Cross-chain settlement — accept payment on Ethereum, settle on Robinhood Chain, verify on Stylus.
Open protocol — let other rental platforms plug into CarBridge as a shared, verifiable ranking + settlement layer.
Acknowledgements
PayPal Developer for the Sandbox and Checkout SDK.
Arbitrum / Stylus team for the Rust-on-chain toolchain.
DeepSeek for the natural-language parsing.
Tally team (Agents for Humans Hackathon) for the "AI names, code decides" principle.
Caddy and nip.io for making HTTPS trivial.
Devpost for hosting the hackathon.
Links
Live demo: https://mafsc.github.io/RentalRide/
GitHub: https://github.com/MAFSC/RentalRide
Stylus ranker: 0x7cf39e42a1266343e068b0e48600f27488d7efe9
CarBridge: 0x484cB35720a9bB6fcEA175e041A221408d01eC02
Network: Robinhood Chain Testnet (chainId 46630)
Built With
- arbitrum
- blockchain
- deepseek
- ethers.js
- flask
- java
- large-language-models
- natural-language-processing
- python
- robinhood-chain
- rust
- smart-contracts
- solidity
- spring-boot
- stylus
- web3
- web3j
Log in or sign up for Devpost to join the conversation.