I recorded a raw ~6.5 minute screen capture of my IDE running a full FetchSandbox MCP guided flow. No polish, no voiceover script — just what happens when you ask an agent to add Slack notifications for failed payments in a repo that already has Stripe checkout, Clerk JWT verification, and Resend receipt webhooks.
The video:
YOUTUBE_URL
This post is the written version of that session, with the parts that are easier to scan in prose than in a screencast.
The ask (and why it is not a greenfield task)
Prompt:
add slack notifications for failed payments — should plug into the existing stripe + resend webhook handlers
Repo: a small Next.js 15 + FastAPI demo (stripe-checkout-demo) that had seen three prior integration sessions:
| Session | What landed | Where Slack attaches |
|---|---|---|
| Stripe seed |
POST /create-payment-intent, POST /webhook
|
payment_intent.payment_failed branch |
| Clerk | JWT dep, POST /clerk-webhook (Svix) |
(out of scope for this alert) |
| Resend |
send_receipt(), POST /resend-webhook
|
bounce/complaint branches + receipt try/except |
Slack is the fourth layer. The agent cannot treat this like a tutorial repo with one file and one webhook. It has to find the exact lines where failures today only print().
That repo reading is why a full guided run is ~6–7 minutes in the recording — not because MCP is slow, but because brownfield integration is mostly comprehension.
What “guided” means in practice
FetchSandbox MCP does not jump straight to POST /chat.completions style codegen. The flow I used (fs-router skill) looks like:
intake → introspect repo → comprehend stack + failure surfaces → guide() routing → discovery questions → prove upstream contract → (then) propose changes
Step 1 — Introspect
The introspect script scanned the repo and returned framework hints (Next.js ^15, FastAPI backend) and SDK signals for Stripe in server/main.py. The intent string mentioned Resend too; Slack is not in the FetchSandbox brain catalog, so it never appears as a routable spec.
Step 2 — Comprehend (the load-bearing step)
The agent catalogued where alerts would attach, not a new /slack-webhook route:
| Event | Today | Location |
|---|---|---|
payment_intent.payment_failed |
print() only |
webhook handler ~L95–98 |
email.bounced / email.complained
|
print() + TODO |
Resend handler ~L139–145 |
| Receipt send raises (Resend SDK) | swallowed with print()
|
inside Stripe success path ~L92–94 |
The user named Stripe + Resend handlers. The comprehend step also flagged the receipt try/except as a third visibility gap — correct webhook hygiene (do not fail Stripe retries) but operationally invisible without something like Slack.
Step 3 — guide() routing
guide(intent="add slack notifications for failed payments — plug into existing stripe + resend webhook handlers...")
Result:
-
spec:
stripe -
workflow:
accept_payment(Tier-1 default) - confidence: 0.85
-
reasoning: no
slackspec; Stripe is the upstream that emits the event Slack will format
That routing is the right call, but it needs to be said plainly: FetchSandbox proves the upstream event, not the Slack POST.
Step 4 — Discovery (failures tab matters)
Multi-tab confirmation:
| Question | Answer | Implies |
|---|---|---|
| Customer geo | US only | no 3DS scenario |
| Capture | Auto on confirm |
accept_payment workflow |
| Failure modes | Declined card (~60s) |
payment_declined scenario |
If you skip the failures tab, you get a happy-path proof that does not exercise the webhook your Slack message cares about.
Step 5 — Proof run (and the honest limit)
Delegated to fs-prove-payments: spec=stripe, workflow=accept_payment, scenario=payment_declined.
Sandbox import reused the bundled Stripe spec with hand-curated workflows. Run result on paper: 6/6 steps passed, webhooks verified: payment_intent.created, payment_intent.succeeded.
| Asked for | Got | Why |
|---|---|---|
payment_declined → payment_intent.payment_failed
|
Terminal succeeded, success webhooks |
Curated accept_payment uses a deterministic pass card; scenario hook exists in the engine but this Tier-1 workflow does not exercise it |
Same class of limit as other Stripe sessions: the catalog workflow is a fast preflight, not a substitute for driving a real decline.
To prove the handler your Slack code will sit in:
| Method | What it proves |
|---|---|
stripe listen --forward-to localhost:8000/webhook + card 4000000000000002
|
Full PI flow → payment_intent.payment_failed at your handler |
stripe trigger payment_intent.payment_failed |
Fast iteration on Slack message template from a realistic payload |
What the agent got right without me asking
Five things worth stealing for your own brownfield prompts:
- No new endpoint — side effects only at existing handler lines.
- Third target surfaced — receipt-send swallow, not only the two webhooks the user named.
- Routing limitation named — upstream Stripe proof, Slack downstream on you.
-
Idempotency applied to Slack — Stripe retries on 5xx; use
pi.idas dedupe key for duplicate alerts. - Resend proof deferred — one workflow per delegation; bounce/complaint shapes need a separate Resend run.
What was not done in this recording
- No Slack diff applied yet (proof handed back; propose-changes step not shown in the artifact).
- No Resend proof run for
email.bounced/email.complained. - No Slack spec proof (none in catalog).
Expected next moves from the session:
- Propose
payment_intent.payment_failed→ Slack at L95–98 (SLACK_WEBHOOK_URLenv). -
stripe trigger payment_intent.payment_failedbefore editing message text. - Separate Resend proof for bounce/complaint templates.
- Ship payment-failed path first; Resend alerts in a follow-up PR.
MCP setup (unchanged from shorter demos)
{
"mcpServers": {
"fetchsandbox": {
"command": "npx",
"args": ["-y", "fetchsandbox-mcp"]
}
}
}
Cursor: ~/.cursor/mcp.json, restart IDE, enable server in Settings → MCP.
Optional skills:
curl -sL https://fetchsandbox.com/skills/install.sh | bash
The takeaway
Docs tell your agent what should happen. Runnable workflows tell it what did happen in a sandbox — and brownfield comprehend tells it where your code already handles failures.
For Slack-on-Stripe, the valuable proof is not “can we call chat.postMessage” in FetchSandbox. It is: when payment_intent.payment_failed arrives, does your handler have the fields you need for an alert, and have you tested that path with a real or triggered event?
Try FetchSandbox: https://fetchsandbox.com
Stripe workflows: https://fetchsandbox.com/docs/stripe
Watch the raw demo: https://youtu.be/AB36LXwfoTQ
If you have done brownfield API work with agents, I am curious: should the default flow always map existing handlers before any proof run, or do you prefer prove-first on greenfield repos?
Top comments (2)
stripe vs paddle is mostly a billing-ops tax question: chargeback handling + dunning + state filings get expensive fast. for indie/early-stage shipping, we charge $3 flat per shipped saas (no monthly). first run free, no card. moonshift.io
Yep, billing ops is definitely where Stripe vs Paddle starts to matter.
The angle I was exploring here is a bit lower-level: before choosing the billing provider or alerting layer, can an agent actually map the existing webhook handlers and prove the failure path it is about to wire into?
That brownfield mapping step is where I keep seeing the most value.