-
-
Honest fit check against the provider's own facts: the coastal walk fits, the canoe has steps
-
The offer comes from the server: €120 total, €30 deposit now, free cancellation until 24 h before
-
Saying "I've paid" changes nothing: only the traveler's own button can accept
-
Accepting holds 4 places for 15 minutes and creates a PayPal order with the official Server SDK
-
The traveler approves the €30 deposit on PayPal's own page (sandbox)
-
Deposit captured: the booking link shows PayPal's order and capture IDs, no account needed
-
Cancellation refunds the deposit through PayPal; confirming twice never refunds twice
-
Provider panel: every deposit checked against PayPal Transaction Search
-
How it works: Claude asks and quotes, PayPal Orders, Payments, Invoicing and Transaction Search handle the money
▶ Watch the 3-minute demo · Try it live at paisaxe.es (judges: the voucher is in the testing instructions; all money is PayPal sandbox) · Source code
In one sentence: a traveler tells an AI guide what their group needs, gets an honest answer about which local experiences fit, and books one with a PayPal deposit that always ends confirmed or refunded, never stuck. I built it solo.
Inspiration
Paisaxe started as an immersive way to discover Asturias, in northern Spain: photo stories of its places, a guide you can chat with, and a voice guide. Visitors kept asking the same follow-up question: can I actually go and do this? Small local providers (a coastal walk, a canoe descent, a 4x4 viewpoint route) rarely have a booking system, and travelers rarely know whether an experience suits their group: four people, a budget, someone who needs a step-free route. I wanted the conversation to end in a real, safe booking.
What it does
A visitor describes what they want in their own words: how many people, the day, the budget and any needs. The assistant (Claude, with tools) checks the provider's catalog, live availability and the provider's own stated facts, and answers honestly: fits, may fit (not confirmed by the provider) or does not fit, with the reason. It never invents a fact or a price.
When the visitor accepts an offer, the place is held and a PayPal deposit is taken (sandbox). Money only moves on a button the visitor presses; the model cannot accept, pay or cancel by itself. The visitor gets a booking link that needs no account, shows the status and the PayPal ids, and allows cancellation with an automatic PayPal refund inside the free-cancellation window. The rest of the price is invoiced through PayPal, due on the day.
The provider gets an operator panel: upcoming bookings, deposits collected, the balance due, exceptions, holds, free places, and, new during the hackathon, a check of every deposit against PayPal's own records (Transaction Search): "PayPal confirma", "Reembolso en PayPal", or "Pendiente en PayPal" while PayPal has not listed it yet.
For a provider who wants to confirm by phone first, the deposit is authorized, not captured: an AI voice agent calls the provider, and the recorded answer either captures or voids the authorization.
Everything you can try is clearly marked as a demo: a fictitious merchant, "Demo" badges, and sandbox money.
Built during the hackathon
Before the hackathon, Paisaxe was already a live discovery site: photo stories of Asturian places, a chat guide grounded in tourism guides, and a voice guide. During the hackathon I added the whole commerce journey on top of it:
- the booking domain (catalog, provider facts, availability, quotes, holds) with its database rules;
- the booking assistant's tools and its "fits / may fit / does not fit" answers;
- PayPal deposits, capture, refunds, balance invoices, webhooks and the reconciliation job, on the official PayPal Server SDK;
- authorization-first deposits confirmed by an AI phone call to the provider;
- the account-free booking link, the operator panel with Transaction Search, the Postman collection and the Zapier hook.
How I built it
- Next.js 16 + TypeScript on Vercel, Supabase (Postgres, row-level security, pg_cron) for bookings, holds, quotes and vouchers. Prices, holds and capacity are enforced in the database (atomic
accept_quote, one inventory owner, idempotent operation keys). - Claude runs the booking conversation with typed tools (search, draft, quote, payment order, status, cancellation preview, balance invoice); every input is validated with zod and every tool checks ownership on the server.
- PayPal: Orders v2 (create, capture, authorize), Payments v2 (captures, refunds, authorization capture and void), Invoicing v2, verified webhooks, and Transaction Search, all through the official PayPal Server SDK (
@paypal/paypal-server-sdk2.5.0), written with the APIMatic Context Plugin in Claude Code. - Never stuck: one capture path is shared by the return page, the
CHECKOUT.ORDER.APPROVEDwebhook and a reconciliation job every 5 minutes, so a buyer who approves and closes the browser is still confirmed, and a capture that cannot be honoured is refunded exactly once. Every POST carries a PayPal-Request-Id, so retries never double-charge. - Postman collection for the whole journey (including the 404/409/401 cases), run locally with Newman against a PayPal mock; Zapier receives booking confirmations and refunds.
- Tests: about 9,700 unit and integration tests, live-database suites, Playwright release probes, and a model evaluation of the booking assistant (8 of 8 scenarios).
Challenges I ran into
- Not losing money in the gaps: a buyer who approves and never returns, a webhook that arrives late or twice, a refund racing a cancellation. I designed one capture path and an idempotent inbox, and tested each stuck state.
- Honesty about accessibility: "step-free" must come from the provider, not from the model. Facts are stored with who confirmed them, and an unconfirmed fact is shown as unconfirmed.
- The SDK runtime's retries: with the default settings, the runtime counts a declared PayPal error as a timeout, so a 422 on a capture was sent three times. I chose a safe configuration, pinned it with tests and reported it to APIMatic (apimatic/apimatic-js-runtime#323).
- Transaction Search needs an app permission that took about an hour to apply, and PayPal lists movements about two hours late, so the panel shows "pending" honestly instead of a false mismatch.
Accomplishments that I'm proud of
A complete, recoverable booking and payment cycle verified end to end against the real PayPal sandbox (order, capture, refund, invoice, webhooks), an operator view that can prove each deposit against PayPal's own records, and an assistant that refuses to invent prices or facts.
What I learned
Typed SDK errors plus idempotency keys make retries safe; webhooks are a signal, not the source of truth; and for AI-driven commerce the most important design decision is which actions the model is not allowed to take.
What's next for Paisaxe
Real Asturian providers (with their own PayPal accounts and onboarding), multi-day and multi-party bookings, booking by voice, and collecting the balance on the day through PayPal.
Built With
- anthropic
- apimatic
- claude
- elevenlabs
- next.js
- paypal
- paypal-server-sdk
- pgvector
- playwright
- postgresql
- postman
- react
- sentry
- supabase
- tailwindcss
- typescript
- upstash
- vercel
- vitest
- voyage-ai
- zapier
- zod

