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:

  1. 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.

  1. 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.

How I built it Architecture

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

Share this project:

Updates

Submission history