Inspiration

On 3 Oct 2026 we were testing an earlier idea on PayPal's sandbox and tried to play out a dispute from start to finish. Opening the dispute through the API was refused. After we escalated it, a dispute ruling took over twenty minutes to appear, and nothing could skip a month ahead to see the next renewal. Every test meant waiting in real time.

That is the problem every developer who bills through PayPal Subscriptions has. The code that handles a failed card, a repeated webhook, a suspended subscription or a dispute first runs on a real customer, with real money, because PayPal's sandbox can't skip ahead a month. PayPal's own Webhook Simulator page says why it can't help either: "Because these are mock events, you cannot verify, resend an event notification for, or show webhook details for simulator-generated events." So we built Fastforward.

What it does

Fastforward plays a whole bad month against your real app in seconds:

  1. It starts on the real PayPal sandbox: a real product, plan and card-funded subscription, with PayPal confirming every signature.
  2. Then it plays the months the sandbox can't reach on a stand-in for PayPal Subscriptions with a fast-forwarded clock: 75 days in seconds.
  3. Claude plays the customers. One pays, one's card starts failing, one opens a dispute. At each decision point Claude decides what that customer does next.
  4. It sends bad weather: notices arriving twice, late, out of order, and one forged, a fake pretending to be PayPal.
  5. Six plain checks judge the app: verifies signatures, fulfils each payment once, answers fast, ends in the right state, answers disputes in time, never calls live PayPal. Plain code, not the AI, decides pass or fail.
  6. You get the fix. Each failure comes with a plain-language explanation and the change to make. "How to fix" opens it in one click.

In the video we point it at Bean & Bloom, a flower shop we wrote the way a busy developer would, leaving one check out: PayPal can send the same message twice, and the shop never checks if it has seen it. Fastforward finds it: "Paid twice". We add three lines, rerun the same month, and all six checks pass. The shop is in the repo (examples/bean-and-bloom), so you can run it yourself.

Most Impactful: who it helps and why it matters

Who it is for: every developer whose app takes recurring payments through PayPal Subscriptions.

Tested on real code. On 5 Nov 2026 we ran Fastforward, unedited, on one of PayPal's own tutorial apps (paypaldev/video-kubowania-paypal-tutorial, commit d4a1c7c), a PayPal developer tutorial for building a subscription membership app. It is marked not for production, and it accepted a forged notice and left a dispute unanswered: 2 of 6 checks failed. In detail, it accepted all 21 notices, including the forged one, without checking that PayPal sent them. Its code also removes a supporter whenever a "cancelled" notice arrives, so an unchecked fake would have that effect (that part is from reading its code). PayPal's other subscription tutorial does both right, by reading its code; it needs a database, so we did not run it. The steps to repeat this are in the README.

The size of the problem. By PayPal's own figure, merchants using PayPal for recurring billing see an average payment success rate of 94.5%, so about 1 renewal in 18 fails, and the failed-payment code runs all the time. Recurly estimates failed payments could cost subscription businesses more than $129 billion in 2025 (both are vendor figures). Fastforward can't stop a decline; it tests the code that reacts to one. Illustrative example: a shop with 1,000 monthly subscribers sees about 56 failed renewals a month. If that code is wrong, it is wrong 56 times a month, from the first month.

Who pays. PayPal, as a feature in its developer dashboard. A handler that mishandles a notice loses the subscriber, and PayPal loses every later renewal fee. Developers don't have to wait for PayPal: Fastforward is open source (MIT), on npm today, and ships an MCP server so coding assistants can run it.

Use of PayPal + AI

PayPal and Claude do different jobs, and each makes the other worth more:

  • Claude's decisions become real PayPal calls. In the recorded real-sandbox run, Claude played a cafe owner whose card failed and chose to update it, and that choice became a real reactivate call on PayPal's sandbox. PayPal's own notices then reached the app byte for byte, and PayPal answered SUCCESS on all 5 signature checks, including a genuine duplicate from PayPal's own resend.
  • Claude plays customers a script can't. In our recorded run, Claude's Leo updated his failing card in time, while the scripted Leo keeps it until he is suspended, so the same month exposes different bugs (one recorded run, not a measured rate).
  • Claude explains failures in plain words and says what to change, labelled "Written by Claude", so a developer knows which words are the AI's.
  • Claude writes scenarios from plain English (fastforward new "a coffee club where one card fails in month two").
  • Your coding assistant can run it. In the video, Claude Code calls Fastforward's MCP server on the Bean & Bloom shop, runs the month, reads the failed check ("Paid twice") and explains the fix, inside the editor. Any MCP assistant can do the same.
  • The AI never decides pass or fail. Six deterministic checks do. The AI cannot talk a bug into passing, and every decision is saved to a lock file so reruns match.
  • Live, not only recorded: with an Anthropic key, the Live switch has Claude decide the customers during the run.

Use of AG Grid

AG Grid Community is how a developer reads the evidence. In the video's Bean & Bloom run, one month produced 20 notices and 35 deliveries. On the Result step, "See the 8 notices" under the failed "Paid twice" check opens the grid filtered to exactly the notices behind that failure; clicking one shows every delivery attempt and how the shop answered it. That is the path from "a check failed" to "this is the notice that broke it" in two clicks. What the grid does:

  • Notices table: one row per notice PayPal sent the app, with when, customer, event, findings, the app's answer, tries, signature result and the worst answer. Sort any column, filter text and number columns, or search everything at once.
  • "Failing checks only" (an external filter) shows just the evidence, across every failed check at once.
  • Click a row to open the inspector: every delivery attempt, its timing, the signature result and the raw payload.
  • "Show every attempt" switches from one row per notice to one row per delivery, to see retries and repeats.
  • Custom cell renderers show findings as coloured check tags ("Paid twice", "Not verified"), so a problem is visible before you read a word.
  • The PayPal match table lists the 17 requests sent to both PayPal's real sandbox and Fastforward's stand-in, with status, response shape, spec match and the one known difference in wrapped text.

We use only the Community modules we need (text, number, quick and external filters, row selection, cell and row styles, tooltips, auto height, row and scroll APIs), registered one by one instead of AllCommunityModule: the dashboard's JavaScript is 1.21 MB instead of 1.48 MB, 17.7% smaller (measured 6 Nov 2026). Community edition only; no charts and no Enterprise features.

How we built it

  • A twin of PayPal Subscriptions built from PayPal's official OpenAPI specifications, with signed webhooks, verify-webhook-signature, and a virtual clock (Node, TypeScript, Fastify).
  • A small add-on (fastforward-register) redirects an app's PayPal sandbox calls to the twin and blocks any call to live PayPal before a socket opens. It works with PayPal's official Node SDK unmodified, with plain fetch, and with Next.js.
  • Checked against the real thing: npm run fidelity sends the same 17 requests to PayPal's real sandbox and to Fastforward's stand-in. The first runs found 49 differences; now seventeen of seventeen match (last measured 5 Nov 2026).
  • A four-step dashboard (React, Vite, AG Grid Community): Choose, Watch, Result, Details.
  • 532 automated tests, plus 8 end-to-end tests that start real apps and a real twin.
  • Deployed as a live demo, and published as three npm packages: fastforward-cli, fastforward-register, fastforward-mcp.

Challenges we ran into

  • PayPal's official Node SDK has no custom base URL, so an app can't simply be pointed at a stand-in. We redirect its calls in-process, safely, sandbox only.
  • The real sandbox is slow and uneven. Notice delivery took 10 to 54 seconds, once over 2 minutes, and one activation notice never arrived within 3 minutes. The app says so plainly instead of hiding it.
  • Disputes can't be created through the sandbox API, so disputes are modelled: the dispute part of the month runs on the twin, labelled Simulated, and no real PayPal dispute is opened.
  • Making AI honest: keeping pass/fail deterministic while Claude plays customers, and labelling every AI-written sentence.

Accomplishments we're proud of

  • Fastforward found a forged-notice bug in one of PayPal's own tutorial apps, unedited.
  • Seventeen of seventeen requests match PayPal's real sandbox.
  • A judge can verify every claim: live demo, open source repo, npm packages, and repeat steps for every result.

What we learned

PayPal's sandbox is excellent for "does my call work" and has no way to test "what happens next month". Most billing bugs live in the second.

What's next

More PayPal products (Orders and Payouts notices), non-Node apps through the stand-in's HTTP API, and offering it to PayPal as a Testing Tools feature beside the Webhook Simulator.

Built With

  • ag-grid
  • anthropic-api
  • claude
  • docker
  • fastify
  • model-context-protocol
  • node.js
  • paypal-openapi
  • paypal-sandbox
  • paypal-server-sdk
  • paypal-subscriptions-api
  • paypal-webhooks
  • railway
  • react
  • typescript
  • vite
  • vitest
Share this project:

Updates

Submission history