Inspiration

If you've ever lent out a camera or a drill and taken a deposit, you know how it ends. The thing comes back with a mark on it, one person says it was already there, and the other says it wasn't. Nobody took photos, and whoever is holding the money decides.

Small rental shops deal with this constantly. We wanted a deposit that gets settled from evidence both people can see.

What it does

The owner enters the item, price and deposit, and sends the renter a link. For the replacement value, they can click Look up current price, which searches Channel3's product catalog and fills in a real store price with its source, like "Channel3, adorama.com". Damage is priced as a share of that value, so it matters that it's real.

The renter reads the terms and approves a PayPal authorization for the rental fee plus the deposit. No money is taken at this point.

At pickup, the renter takes six photos from guided angles, and AI points out any that are too dark or blurry. At return they take the same six, with the pickup photo shown over the live camera as a ghost image so the shots line up.

Then an AI agent checks that the hold is still valid and compares each pair of photos. It marks each thing it finds as new damage, already there, normal wear, or unsure. The renter can watch this happen.

Our code works out the charge from a fixed table, and the renter can accept it or contest it. If they contest, the owner reviews it and can only lower the amount.

Once it's agreed, PayPal captures what's owed from the original hold and releases the rest. If damage costs more than the deposit, the renter gets a PayPal invoice for the difference.

Both sides keep a record with the photos, findings, prices and PayPal IDs. The owner also gets a ledger of every rental.

The renter also keeps their normal PayPal rights. If they still disagree after settlement, they can open a dispute with PayPal, and PayPal decides it. When that happens, a webhook puts a dispute banner on the rental for both sides, and the owner can answer in PayPal using the evidence record.

In our sandbox test, a $210 hold on a camera with two new damages and one old scuff ended as $60 for the rental, $126 for damage, and $24 back to the renter.

Rules the code enforces

  • The AI never sets an amount. It describes what it sees and the pricing code takes it from there.
  • Old damage, normal wear, and anything the AI is less than 75% sure about are free.
  • A dent that shows up in five photos is charged once.
  • PayPal captures nothing until the renter accepts, or the owner approves after a contest.
  • A capture can't go above the hold, and a retry can't charge twice.
  • Writing inside a photo is treated as part of the photo. A sticker saying "no damage" does nothing.

How we built it

We used PayPal Orders v2 with intent AUTHORIZE, partial capture with final_capture so the remainder is released, voids for when an owner cancels, the JavaScript SDK for checkout, and webhooks. The PayPal Agent Toolkit handles creating and sending invoices, and the agent uses it to look up the order. Everything runs on the sandbox.

The inspection uses Claude Haiku 5.5 through the Anthropic SDK. It's a tool-calling agent with vision, and none of its tools can touch money. Haiku also does the quick check on each photo.

The app is Next.js and TypeScript with SQLite. The live inspection comes through a server-sent event stream. The owner ledger is AG Grid with custom cells for photos, status and how each hold was split. Channel3's product search API supplies replacement prices: we take the matching product's in-stock US offers and use the middle price, and the owner can still edit it. It's hosted on Render from a Blueprint in the repo, with PayPal webhooks verified by signature.

Challenges we ran into

Our first real inspection reported the same dent from five angles, and we would have charged the renter five times. Now each physical damage has its own ID and gets priced once.

Payments can fail halfway. PayPal might capture the money and the response never reaches us, so we save the exact amount the first time and retry with the same request ID. It can't capture twice.

PayPal only guarantees a hold for three days, so rentals are limited to three days for now.

Accomplishments that we're proud of

The whole loop works on PayPal's sandbox, on the hosted site too: hold, photos, inspection, verdict, partial capture, release, overage invoice and the webhook coming back. The ghost overlay was simple to build and made a big difference to how well the photos match. An inspection costs under a cent, so this makes sense even for a cheap rental.

What we learned

We started out expecting to need the strongest AI model. A cheaper one did the job once we told it clearly what counts as damage and how to judge its own confidence.

What's next for Handback

Longer rentals, condition checks suited to each kind of item, and sending the evidence straight into a PayPal dispute if one gets opened.

Try it

Everything runs in PayPal's sandbox, so no real money moves. Open the hosted demo, click Create a rental (3 days at most), and open the renter link in the same browser. Pay with a sandbox PayPal account, or use Debit or Credit Card with PayPal's test card 4111 1111 1111 1111, any future expiry, CSC 123, and made-up details. Upload the pickup photos from samples/camera/pickup, then the return photos from samples/camera/return (AI-generated images of a made-up camera). Watch the inspection, read the verdict, and accept it. Console shows the ledger.

The demo runs on Render's free plan, so the first visit after a quiet spell can take about a minute to wake up.

Built With

Share this project:

Updates

Submission history