Inspiration
AI assistants are starting to shop for people. They can search, compare and fill a cart, but only where there is something to buy from: a big marketplace or a store with an API. The bakery down the street has a five-page website, a PDF catering menu and a PayPal account. To an assistant, that is a brochure, not a shop.
We wanted the smallest possible step for that owner: paste the website address, check what was read, connect PayPal, and be open to AI shoppers. No product feed, no plugin, no new platform to learn. PayPal's own agentic commerce programs need an onboarding request, so Walk-In uses only the generally available Orders API. Any shop with a PayPal business account can be paid today.
What it does
- Reads the site. Walk-In crawls up to 14 pages and up to four linked PDFs, since many food businesses publish their menu only as a PDF. An LLM turns them into a catalog.
- Checks every price. A price is kept only if its exact textcited from and parses to the same amount. Anything else is flagged for the owner, such as a price written out as "forty-five dollars". Items with no published price become by quote, and the model is told never to guess one.
- Opens a door for assistants. Each shop gets its own MCP server at
/mcp/<slug>with seven tools:search_products,get_product,get_shop_info,create_checkout,get_order_status,request_quoteand `repohout an assistant get a hosted chat that calls the same code. - Gets the shop paid.
create_checkoutbuilds a PayPal order from catalog prices only, withpurchase_units[].payeeset to the shop, so an assistant can't change a total. The shopper approves in PayPal and the mon's own account. Walk-In never holds funds. - Handles quotes. For custom work, the assistant sends a quote request. The owner names a price on the dashboard, and the shopper pays it through PayPalfrom a status link.
- Shows what people wanted. When an assistant can't find something, it reports that instead of inventing it, and the owner sees the unmet demand on the dashboard.
How we built it
- Rust on AWS Lambda behind a Function URL, with one DynamoDFormation. An axum
webfunction serves the API, the MCPendpoints (rmcp, stateless JSON mode) and the frontend. Animporterfunction reads sites asynchronously, because that takes longer than a request should. - DeepSeek V4.1 Flash through OpenRouter extracts the catalot and runs the shop chat. Code, not the model, verifies prices,sets totals and talks to PayPal.
- PayPal Orders v2 and webhooks. Each order is created with the shop as payee and captured idempotently with
PayPal-Request-Id, so it is capturedexactly once whether the return page, the assistant or a webhook reports it first. Webhook signatures are verified before approvals, captures and refunds are applied. Amounts are integer minor units, and zero-decimal currencies are handled. - Tests. An end-to-end test walks a shop from import to refund against mocked PayPal and OpenRouter on a local DynamoDB. It checks that an assistant can't set a price, that hidden text never reaches the model and that a forged webhook is rejected.
- We used Claude Code as a coding partner. The demo video shows a real Claude Code session shopping a Walk-In store over MCP.
Challenges
- Models invent prices. An extraction model will happily write a plausible number. Every price therefore has to survive a check in code against its source page, and the owner confirms anything that can't be verified.
- The platform can't act for the seller. With the platform's credentials, sandbox refunds and tracking return
403 PERMISSION_DENIED, and partner referrals returnNOT_AUTHORIZED. So the dashboard links each order to the seller's own PayPal for refunds, and the signed refund webhook brings the resultback. Tracking numbers are kept in Walk-In and shared with the shopper's assistant. - Unapproved orders expire. PayPal dropped an unapproved sandbox order within hours. A quote might be paid days later, so its PayPal order is created only when the shopper clicks Pay.
- Time limits. Reading costs about 3 s per product through the model, and 60 products ran into the Lambda time limit. Imports are now capped at 40, whichtakes about two minutes: $40 \times 3\,\text{s} = 120\,\text{s}$.
- Untrusted pages. A website can try to instruct the model. Text hidden with CSS is stripped before the model sees it,
robots.txtis respected, andprivate addresses are refused. - Real sites are messy. On four real bakery and pottery sites, our first importer found 0 or 1 products each. Reading PDF menus and keeping unpriced items as by quote raised that to between 15 and 40.
What we learned
- The Orders API
payeefield is enough to route money to many sellers without holding it. Every seller-side action, such as a refund, has to happen in the seller's own account, so the product should be designed around that from the start. - MCP makes a tiny shop as reachable as a big one: one URL, and any assistant can use it.
- Honest failure is a feature. An assistant saying "they don't sell that, so I told the owner" is more useful to both sides than a confident guess, and itgives the owner real demand data.
- Wherever money is involved, the model proposes and code decides.