Inspiration Moroccan artisan markets (souks) are full of unique handmade goods - tagine pots, argan oil, handwoven rugs - but buying them online is hard for international shoppers: catalogs are static, product discovery requires knowing exactly what to search for, and checkout trust is a barrier. We wanted to show how an AI assistant plus PayPal's trusted checkout can make discovering and buying artisan goods as easy as describing what you want in one sentence.
What it does SoukMate is a web app where a shopper describes what they want in plain language ("a gift for my mother under $60"). An AI assistant reads a catalog of Moroccan artisan goods, builds a cart, and explains its picks. The shopper then pays through a real PayPal checkout flow (Smart Buttons + Orders API v2), all running against the PayPal sandbox so no real money moves.
- AI cart building: the shopper's free-text request goes to a large language model (Cloudflare Workers AI Llama 3.3 70B by default, Google Gemini 2.0 Flash as an optional alternative) which returns strict JSON ({items:[{id, qty}], reply}). The server validates every product id against the catalog, recomputes all prices server-side, and clamps quantities - the model never sets prices.
- PayPal checkout (sandbox): the frontend uses PayPal JS SDK Smart Buttons. Order creation and capture happen server-side through the PayPal Orders API v2 (intent CAPTURE) with OAuth client-credentials auth, so the client secret never reaches the browser. Itemized per-product amounts are sent with each order.
- Order confirmation: after buyer approval the server captures the order and the UI shows the capture id, amount, and sandbox payer email. Verified live end to end: a $31.00 cart built by the AI was checked out through PayPal Smart Buttons, approved from the buyer's PayPal balance, and the order was captured server-side with status COMPLETED (buyer-side sandbox transaction 9LT74876C1170881X). A second API-level order confirms the server-side create/capture path directly: order 8P836734UX5390111 ($72.00) with capture id 8W911151SV7760708, status COMPLETED.
How we built it
- Frontend: vanilla HTML/CSS/JS served via Cloudflare Workers static assets.
- Backend: a single dependency-free Cloudflare Worker exposing /api/assistant, /api/paypal/order, and /api/paypal/order/:id/capture.
- AI: Cloudflare Workers AI (Llama 3.3 70B) via the free binding; Google Gemini 2.0 Flash via REST when GEMINI_API_KEY is set; a clearly-labelled offline keyword matcher exists only as a fallback when no API key is configured.
- Payments: PayPal sandbox only (api-m.sandbox.paypal.com is hard-coded).
Challenges we ran into
- Making the AI's output safe for commerce: the model can hallucinate product ids or prices, so all pricing is recomputed server-side and every id is validated against the catalog before an order is created.
- Keeping secrets server-side: PayPal credentials live only in Worker secrets; the browser only ever sees the client-id-scoped JS SDK.
- Reliability: LLM output is not always valid JSON, so the worker parses defensively and falls back gracefully instead of breaking the checkout.
Accomplishments that we're proud of
- A fully working end-to-end flow: one sentence from the shopper becomes a validated cart and a real PayPal sandbox order, approved and captured, with the capture id shown in the UI.
- Zero-dependency backend that deploys for free on Cloudflare Workers.
- Honest engineering: prices always come from the server, and the fallback mode is clearly labelled.
What we learned
- How the PayPal Orders API v2 create/approve/capture lifecycle works in practice, and how to keep client credentials out of the browser.
- How to constrain LLM output into strict JSON that a commerce backend can trust after validation.
What's next for SoukMate
- Multi-language chat (Arabic/French) for real Moroccan buyers and sellers.
- Real artisan onboarding so sellers can list their own goods.
- Moving from sandbox to live PayPal payments.
Built With
- cloudflare-workers
- gemini
- javascript
- llama-3.3
- paypal-js-sdk
- paypal-orders-api
- workers-ai