Inspiration

I keep paying what I call a "dumb tax". In Vietnamese we say học phí ngu: the tuition you pay for being careless. I sign up for a free trial, don't read the terms closely or forget to turn off auto-renew, and a few days later the charge lands on my Visa debit card. Each time it is my mistake. Each time it also feels like the product was counting on me forgetting.

I don't think the fix is to make customers more careful. It is to make free trials honest. Tell people clearly, in their own language, exactly when they will be charged and how much. Let them cancel in one click. And when someone obviously forgot, give the money back quickly instead of waiting for a dispute. For a small merchant this is also the cheaper path: a refunded $9.99 costs less than a chargeback and a customer who never comes back.

No Dumb Tax is the tool I wish the services I signed up for had used.

What it does

No Dumb Tax sits between a small subscription merchant and PayPal Subscriptions.

  • Honest trial plans. The merchant sells a plan with a free trial through the PayPal subscribe button.
  • A reminder before the first charge. From PayPal's next_billing_time and the plan price, the customer's portal shows exactly when and how much they will be charged, in their language, with a one-click cancel.
  • An "I forgot to cancel" agent. The customer writes in their own words, in any language. An AI model sorts the message (forgot to cancel, cancel only, other, or an attempt to game it). Plain code then applies the merchant's refund rules — first charge after a trial, within 48 hours, once per subscription, the charge must equal the plan price — and either cancels and refunds through PayPal right away or queues the case for the merchant. The AI never decides whether money moves.
  • A merchant console built with AG Studio. KPI tiles, upcoming conversions, a custom approval-queue widget whose Approve button says exactly what will move, an audit log of every action, editable refund rules, and AG Studio's AI agent, which asks a read-only PayPal assistant (PayPal Agent Toolkit) about subscriptions, refunds and disputes.

Everything runs on the PayPal sandbox; no real money moves.

How we built it

  • Next.js 16 on Vercel, TypeScript, Upstash Redis for state, Vercel cron for reminders.
  • PayPal: Subscriptions (products, plans with a TRIAL cycle, subscription details, transactions, cancel), Payments v2 capture refunds with PayPal-Request-Id, webhook signature verification, and the JavaScript SDK subscribe button. The PayPal Agent Toolkit (OpenAI adapter) powers the merchant assistant with read-only tools only: show_subscription_details, list_disputes, get_dispute, get_refund.
  • AI: Nebius Token Factory (Qwen/Qwen3-30B-A3B-Instruct-2507) for message classification, reply and reminder translation, the assistant, and AG Studio's agent — through our own proxy, so the model and the key stay on the server and one daily budget covers everything.
  • AG Studio 3 for the console: custom theme, a custom React widget, and the Studio Agent Framework with a custom tool (ask_paypal) that bridges Studio's agent to the PayPal assistant.
  • Guardrails in code: refund decisions are a pure, unit-tested function; a number guard throws away any model text that contains a date or amount not in PayPal's facts; customer text is delimited and pre-checked for injection; refunds are idempotent and one request per subscription is handled at a time.
  • Tests and review: 130 Vitest tests, written test-first. Each plan ended with an independent AI code review, and every finding was fixed with a test that failed first.
  • Built with Claude Code as the coding partner; the owner set the product direction and approved every plan.

Challenges we ran into

  • The model invented a charge. In the first spike the model told a trial user they "were charged" before any charge existed. That changed the design: code fetches every fact from PayPal, the model only classifies and rephrases, and any number it writes that is not in the facts sends the reply back to a fixed template.
  • A double click could refund twice. Two simultaneous requests both passed the "already refunded?" check. We reproduced it in a test (two refunds), then made the request key and a per-subscription lock atomic.
  • Our own evaluation looked too good. The first set of 120 messages scored 100%. A harder set found 7 messages that the model read as "forgot to cancel" although they were double charges, a wrong amount, an annual-plan refund, or attempts to get several months back. We wrote a fresh held-out set before touching the code (77.5% there), then added a rule (the charge must equal the plan price) and clearer instructions: 95.0% on the held-out set afterwards, with the remaining misses still capped at one charge by the rules.
  • Wiring AG Studio's agent to a non-OpenAI model. The Studio adapter streams the OpenAI Responses API. Our provider failed on streamed tool calls and required ids on earlier assistant items, so our proxy calls it without streaming and replays the result as the event stream Studio expects. We also learned that every Studio field needs a format, that a custom widget must extend the default widget menu (or the AI can only create your widget), and that the AI panel lives in edit mode. One thing we could not fix in time: on our 30B model, Studio's agent says it added a KPI tile but the tile renders empty, so the video shows only the ask_paypal tool, which works.

Accomplishments that we're proud of

  • The safety model is simple and holds: no AI can move money, every refund is capped at the last charge, and every action is in the audit log with who took it.
  • We published the evaluation with its misses and limits, including a before/after on a held-out set, instead of the flattering 100%.
  • An end-to-end run on the live sandbox: a real trial, a reminder, the conversion charge, an automatic refund and cancel from a customer's message, and the webhooks recorded (docs/e2e-run.md). Done twice; the second time on camera: 3.6 seconds from "I forgot to cancel" to a completed PayPal refund, with the refund webhook mapped back to the subscription.

What we learned

  • "Rules decide, the AI proposes" is easy to say and needs a test for every boundary — 47 vs 49 hours, a second refund, a wrong amount, a double click.
  • Evaluate on data you did not tune on. Our hard set was useful because it hurt.
  • Vendor SDKs and model providers disagree in small ways (streaming tool calls, item ids, field formats); a thin proxy with tests is cheaper than fighting each one in the UI.

What's next

  • Email and SMS reminders (the demo shows reminders in the customer portal only).
  • "Connect with PayPal" onboarding so any merchant can use it, not one per deployment.
  • A real-message evaluation with merchant consent, and per-merchant refund policies with analytics on disputes avoided.

Built With

  • ag-grid
  • ag-studio
  • claude-code
  • nebius
  • nextjs
  • paypal-agent-toolkit
  • paypal-js-sdk
  • paypal-subscriptions-api
  • qwen
  • react
  • typescript
  • upstash-redis
  • vercel
  • vitest
Share this project:

Updates

Submission history