Inspiration

Small sellers across Southeast Asia sell clothes, snacks and handmade things on live video. Their buyers don't fill in forms. They type "+1", "the blue one from before, M", "change that to L, don't add another", "if no M forget it", in English, Malay, Chinese and Thai, all at the same time, while the host keeps talking.

This is a large and fast-growing way to buy. Video commerce in Southeast Asia grew five-fold in three years and is expected to be about a quarter of the region's e-commerce in 2025, out of $185 billion in total (e-Conomy SEA 2025, Google, Temasek and Bain). In Ninja Van's survey of over 1,000 sellers in six Southeast Asian countries, 31% of live sellers go live every day, and 47% in the Philippines.

After the live, the seller scrolls back through hundreds of comments and rebuilds the orders by hand. Who meant which item? Did that change replace the first order or add a second one? And the buyers who said "+1" and never paid keep items off sale for everyone else.

Sellers already pay to get help with this. Comment-selling tools are common: CommentSold and SoldLive in the US (SoldLive starts at $35 a month for 35 live-sale orders), SHOPLINE in Hong Kong and Taiwan, EasyStore and BigSeller in Southeast Asia. They work from a fixed format: a code (A1+1, CF A01, sold 12), or at the simplest a bare "+1" for the one item in a flash sale. The closest anyone comes to reading free text is SHOPLINE labelling comments as purchase or question (no orders) and SoldLive confirming the variant by SMS after the comment. That works when buyers follow the format. In a test chat I wrote the way buyers type (ten buyers, 22 messages, four languages), 16 messages place, change or cancel an order, and only one of them is a product code with a quantity or a bare "+1" for a one-option item. I wanted the opposite: let buyers talk the way they already do, and make the software understand them while the live is still running.

What it does

PlusOne sits in the seller's own live page.

For buyers

  • They watch the live and chat. "+1" orders what's on screen; "the dress just now, blue S" points back at the previous item; "change to L, don't add another" changes the order in place; "still got pink S?" gets an answer without taking stock.
  • A name is all it takes to join; PayPal brings the email and address at checkout.
  • Everything they order in one live goes in one parcel, drawn as the shipping label it will become: paid items marked PAID, what's still held adding up at the bottom with the time left and one button to pay.
  • PlusOne replies privately in their own language and asks only when it can't tell ("Sage M or Blue L?").
  • If the last one is gone, they join a waitlist; if a hold runs out, the item goes to the next person automatically, already held for them.
  • If they hold one piece of the host's bundle deal, they're offered the other with one tap.
  • At their first checkout they can save their PayPal with the shop. The next order is one tap, no PayPal window. Or they turn on auto-pay for this live with a limit ($50, $100, $200): then "+1 the rattan bag" is paid within that limit. Their parcel counts down 15 seconds after the order last changed, so "and the scarf too" joins the same payment, and while PlusOne is asking them something, auto-pay waits for the answer.

For the seller

  • Tonight's orders are three manifests on a packing table, one line per order: waiting to pay, paid and ready to pack, sent. The chat stays closed unless the seller wants to read it; PlusOne already answered it.
  • The host just talks. "Dress and blouse together, five dollars off" becomes a card; one tap applies it, and the discount goes into the PayPal order.
  • Only the things a person must decide reach the seller: a refund request (one tap refunds through PayPal), a question the shop policies don't answer.
  • Let PlusOne watch: with the camera on, the host holds a product up and it goes on screen for buyers within a few seconds, so their "+1" means what they can see. The host never has to touch the console mid-sale.
  • Ship with a tracking number: PayPal shows it to the buyer.
  • End the live: everyone who still owes gets a PayPal invoice, and Claude writes the seller tomorrow's to-do list: who still owes, what sold out and should be restocked, what buyers kept asking for.
  • Ask PlusOne: the seller types, or the host says out loud mid-live, "Hey PlusOne, who still owes?" It looks through tonight's orders and the shop's PayPal account through PayPal's Agent Toolkit (invoices, refunds, tracking, disputes). Anything that moves money or messages buyers comes back as a card to approve: chat reminders, PayPal invoice reminders, a refund, shipping with a tracking number. It can also put a product on screen or make a pay QR code for an invoice.
  • A report (AG Studio) with an assistant that answers "why is blue M sold out?" and can remind everyone who still owes, each in their own language.

How we built it

PayPal, the whole money path

  • Orders v2 with intent=CAPTURE, paid from the buyer's order label with the PayPal JS SDK v6 button; the server creates and captures with the PayPal Server SDK.
  • Stock is only locked as sold when the money is in. Webhooks (PAYMENT.CAPTURE.COMPLETED and related events) are signature-verified, and the server creates and keeps its own webhook pointed at itself on boot.
  • Refunds, including a single line of a combined order.
  • Shipment Tracking on the capture, so the buyer sees the parcel in PayPal.
  • Invoicing v2 after the live, with items held until the invoice is due and cancelled if it runs out.
  • Bundle discounts and combined postage go into the PayPal order breakdown. Every call that moves money carries a PayPal-Request-Id, and a saved-PayPal charge is written down before it is sent, so a retry doesn't charge twice.
  • Save PayPal during purchase (Vault): the first checkout asks PayPal to store the buyer's PayPal with store_in_vault: ON_SUCCESS; later orders are created with the vault_id and complete in one call, shipped to the address from the saving checkout. "Forget it" deletes the payment token at PayPal.
  • PayPal Agent Toolkit: the seller's copilot gets its PayPal tools (orders, invoices, QR codes, refunds, shipment tracking, disputes) from @paypal/agent-toolkit, converted to Claude tools. Read-only tools run straight away; invoice reminders and cancellations come back as cards.

Claude as the agent that keeps orders right

  • Each buyer message is read with what's on screen, what was shown before, the buyer's open order, waitlists, active deals, the shop's policies and what the host said in the last minute. Claude (Opus 5.5) returns a structured action: buy, change, cancel, waitlist, question, combine shipping, or a question back to the buyer.
  • Claude decides what the buyer meant; code decides price, stock and holds. Messages are understood in parallel but applied in the order they arrived, under row locks, so three buyers racing for the last blue M are served first come, first served.
  • The host's voice is streamed through the server to Deepgram; Claude turns finished sentences into cards for new items, prices, bundles and limits. Nothing changes until the host taps Apply.
  • The host's camera: every two seconds the console sends a small frame, and Claude names the catalog product being shown, or none. Two frames in a row must agree before it goes on screen; frames aren't stored.
  • 33 evals cover what the video and judges will try, including Malay, Chinese, Thai, Indonesian and Singlish.

Agents that spend, with limits someone chose

  • The buyer's agent is auto-pay: a spending limit for one live, a countdown that restarts on every change and holds while a question is open or a message is still being read, the limit checked again at the moment of payment, and a decline that turns auto-pay off instead of retrying. It never buys what the buyer didn't just ask for: nothing handed over from the waitlist, nothing after "if no M, forget it".
  • The seller's agent is Ask PlusOne: Claude with tools over tonight's orders and PayPal. It reads freely and proposes; the seller approves anything that moves money or messages a buyer, one card at a time or all at once.

Render Workflows for the work around a live

  • closeOutLive fans out one invoiceBuyer run per buyer who still owes, each retrying on its own, then runs writeRecap.
  • remindToPay waits until a few minutes before a hold runs out and nudges the buyer, unless they paid or the hold changed.
  • Task runs touch only Postgres and PayPal; their live updates reach browsers through a Postgres NOTIFY channel the web service listens on.

AG Studio powers the seller's report: takings, money still held, units by product, stock with held and waiting counts, every order line with custom cells, all updating live. Its built-in agents run on Claude through the PlusOne server, with one extra tool that sends payment reminders.

APIMatic: the PayPal code was written with the APIMatic Context Plugin for Claude Code. It pointed out that the SDK has no timeout or retries by default (I set both, retrying POSTs only with a request id), how to read typed errors versus raw bodies, and the SDK's calling conventions the code follows for create, capture, refund and tracking.

Stack: TypeScript everywhere. Fastify and Socket.IO, Postgres with Drizzle, React 19 with Vite and Tailwind, LiveKit for the host's camera, deployed on Render (web service, workflow service and Postgres from one Blueprint).

What's real in the demo: the host footage in the video and the demo's replay was generated with Seedance 2.5, the video's narration is a synthetic voice, and the buyers are simulated (they go through the same chat pipeline real buyers use). Every order, payment, refund and invoice is real in PayPal Sandbox.

Challenges we ran into

  • Three people, one last item. Understanding runs in parallel because the model takes a few seconds, but orders must be applied in the order people spoke. I split the two: interpretation per buyer in parallel, application in arrival order with row locks on stock.
  • Late webhooks. A capture webhook arriving after a refund briefly marked a refunded order as paid again. Settlement now only moves forward from "created" or "approved".
  • Mixed-language hosts. Automatic language switching in speech-to-text doesn't cover Malay or Chinese, so the host picks the language they're speaking and PlusOne reads mixed sentences from there.
  • Money that moves without a tap. Auto-pay had to be safe to leave on: a correction mid-countdown must land before the charge, an open question must not be paid over, and a charge PlusOne never heard back about must not be repeated. The countdown and the "waiting for an answer" state live on the order; a due order is claimed once in the database; a saved-PayPal charge is written down before it's sent. A PayPal window opened before the buyer changed their order no longer captures, and refunds give back each item's share of what was paid.
  • Background jobs that can be retried. An invoice run that fails halfway must not send a second invoice. PayPal request ids and a check before sending make each run safe to repeat.

Accomplishments that we're proud of

  • Every PayPal path runs for real in Sandbox, end to end in a browser: checkout, saving PayPal, one-tap payment (about 3 seconds from tap to PAID), auto-pay, webhooks, partial refund, shipment tracking, invoice payment, and invoice reminders sent through the Agent Toolkit.
  • Ending a live on the deployed app sends two invoices in under 10 seconds and the recap in under 20, running on Render Workflows.
  • In that 22-message test chat, PlusOne ended with all ten parcels right, three runs in a row, asking one short question and passing one question to the seller ("is the dress see-through?"), with replies in about 3 seconds. The chat and the script that plays it are in the repo (scripts/messy-chat.*); it's my own test, not data from real sellers.
  • About 3 seconds from a buyer's message to their parcel updating, while the live keeps going, in whatever mix of English, Malay and Chinese they type.
  • Buyers never need instructions beyond "type +1".

What we learned

  • The hard part of agentic commerce isn't the model call; it's deciding what the model is allowed to change. Letting Claude decide meaning and code decide money made both simpler.
  • Sellers don't want a dashboard during a live; they want to be interrupted only when it matters.

What's next for PlusOne

  • Real channels. The engine only needs who said what, and when; today that comes from the seller's own live page. YouTube Live chat has a public API, so it's the first channel to add, then Facebook Live.
  • Onboarding real sellers to PayPal so each shop gets paid directly.
  • A pilot with sellers in Singapore and Malaysia.

Built With

  • ag-grid
  • ag-studio
  • apimatic
  • claude
  • deepgram
  • drizzle-orm
  • fastify
  • livekit
  • paypal
  • paypal-agent-toolkit
  • paypal-orders-v2
  • paypal-server-sdk
  • paypal-vault
  • paypal-webhooks
  • postgresql
  • react
  • render
  • render-workflows
  • socket.io
  • tailwindcss
  • typescript
  • vite
Share this project:

Updates

Submission history