Skip to main content

Stripe

What Is a Verification Layer for Coding Agents?

Cursor, Claude Code, and Lovable write the integration. The request still has to hop MCP, hit a twin, fail on old code, pass on new code, and exit 0.

2026-09-22FetchSandbox Engineering

Cursor wrote the Stripe handler. Claude Code says the retry is fixed. Lovable checkout looks done. Then POST /v1/payment_intents/{id}/confirm returns 402 card_declined, and the app still marks the customer paid.

That is not an editor problem. It is a missing hop. The agent can write the code. Something else has to run the request against a host that can fail on purpose, then say whether old code failed and new code passed.

Short answer

A verification layer for coding agents sits between the agent and the third-party API. Cursor, Claude Code, or Lovable call MCP. MCP drives a stateful twin (an API-compatible host, not a tap on live Stripe). You inject a named failure such as payment_declined. Old code must violate the invariant. New code must hold it. The verdict is an exit code, not another model score.

Lovable, Bolt, v0, and Replit are the same shape. The builder writes the first charge. The layer has to prove the second delivery, the decline, and the unlock.

What hops sit between the agent and the API?

This is the request path, left to right:

Cursor, Claude Code, and Lovable on the left. MCP in the middle. A verification sphere labeled old code fails, new code passes. A run trace ends at exit 0.

The same hops in motion:

  1. Agent. Cursor asks to prove nobody was charged twice. Claude Code asks to prove the fix holds. Lovable asks to test checkout before go-live.
  2. MCP connector. The agent does not guess URLs. It calls shipped tools: guide, run_workflow / quickrun, set_scenario, verify_behavior, prove_fix.
  3. Twin. The HTTP host speaks Stripe paths (/v1/customers, /v1/payment_intents). Point the app at sandbox_base_url. If the app still calls api.stripe.com, the twin is a spectator.
  4. Run trace. Intent routed. Old code run: FAIL. New code run: PASS. Receipt: exit 0.

The packet is a real API request. It is not a chat summary of what the model believes happened.

Why is an MCP inspector or an OpenAPI checker not this layer?

Search results for "verify AI-written API integrations" mostly test a different object.

What people openWhat it checksWhat it misses
MCP InspectorThe MCP server itself (tools/list, tools/call)Your handler's side effect on a decline or retry
OpenAPI / contract MCPResponse shape against the specWhether one event.id created one booking
Static "anti-hallucination" gatesInvented symbols, skipped testsRuntime lifecycle: 402, replay, out-of-order webhooks
Mocks and Stripe test modeOne happy 200 / one 4242 cardThe failure you did not stub
An LLM judgeWhether the diff sounds rightA stable exit code you can put in CI

Kaktoos named the right split on Dev.to this month: if the same agent writes the integration and the tests, the tests can confirm the agent's assumptions. Contract validation is a start. The missing hop is still outcome: create, decline, or replay, then read state back.

FetchSandbox's job on that hop is a deterministic eval: same failure on old code and new code, green only on 1 → 0.

What does payment_declined look like on the wire?

I ran Stripe accept_payment through FetchSandbox MCP today, then armed payment_declined on the same twin.

Happy path: six steps passed. Customer create, PaymentIntent create, confirm, capture, retrieve. The twin is https://fetchsandbox.com/sandbox/a8c3b9fbd9.

Same workflow, payment_declined on: confirm fails. The scenario overrides PostPaymentIntentsIntentConfirm with HTTP 402 and error_code: card_declined. The run stops. status: fail. That is the point.

A local replay of the same scenario today stopped at confirm with:

{
  "type": "invalid_request_error",
  "code": "card_declined"
}

A handler that treats "I posted confirm" as "they paid" will unlock on that 402. A handler that retries without an idempotency key can credit the same declined attempt twice. Neither bug shows up in the editor.

quickrun with a scenario only proves the twin declined. It does not prove your app. The MCP response says that in plain language: use verify_behavior for FetchSandbox reference handlers, or prove_fix on the still-broken tree, before you write the diff to disk.

How do you put the layer on the request path?

Connect FetchSandbox MCP in Cursor, Claude Code, Claude Desktop, or Lovable (https://fetchsandbox.com/mcp/v1 with a Bearer token from /keys, not None).

Then ask the agent to:

  1. guide the intent ("prove they were not charged twice on a declined card").
  2. quickrun stripe accept_payment so you have a sandbox_id and a twin URL.
  3. Point the app at that twin. Twins are hosts, not a proxy of live Stripe traffic.
  4. set_scenario payment_declined (or webhook_retries if the bug is a second delivery).
  5. Drive checkout again. Read the row your UI reads, not the HTTP status.
  6. Call prove_fix with the still-broken tree plus the proposed diff. Old probe must exit 1. New probe must exit 0. Anything else stays unproven.

Paste the receipt into the pull request by hand. FetchSandbox does not post GitHub comments yet. Keep the same workflow in CI with npx fetchsandbox run --all --json after the flip holds. That is the pre-merge proof in a pipeline, not a second model review.

For Lovable and Bolt specifically, the builder-facing version of this loop is integration testing for AI-built apps.

Receipts

Two real Stripe accept_payment runs against the same twin, captured 2026-09-22:

Happy path (scenario omitted), 6/6 steps, status: pass:

fetchsandbox.com/runs/a8c3b9fbd9?flow=run_c0d00703-3275-4ba6-b5fd-7273ba3a0adc

payment_declined on, 2/3 steps, status: fail, confirm never reaches capture:

fetchsandbox.com/runs/a8c3b9fbd9?flow=run_2f8e7882-6c49-406f-96e0-90ffa2b9dc5c

The same receipt also attached the webhook_duplicate_side_effect handler diff. Event evt_dup delivered twice. Buggy reference handler: charge_count: 2, then GET /charge-check409 ("double charge — 2 charges recorded"). Fixed reference handler: charge_count: 1, second POST labeled duplicate. Flow state: pattern_proven_fix_unproven. The class is proven on FetchSandbox handlers. Your repo still needs prove_fix.

Questions about a verification layer for coding agents

What is a verification layer for coding agents?

It is an independent runtime between the agent and the provider API. The agent can request the run. It cannot set the verdict. Measured behavior on a twin, plus an exit-code gate, decides pass or fail.

Does this replace Stripe test mode?

No. Keep test mode. Add a hop that test mode will not volunteer: a named decline, a replayed event.id, a 429 mid-flow. Read application state after that hop.

Can Cursor, Claude Code, and Lovable share the same layer?

Yes. All three speak MCP. The twin URL and the scenario id do not change because the editor changed. Lovable needs a Bearer token from /keys. Cursor and Claude Code can use the local npx fetchsandbox-mcp server or the hosted /mcp/v1 endpoint.

Why must old code fail before new code can pass?

If you only run the patched tree, "pass" can mean the check never saw the bug. The old-code run is the negative control. Green is allowed only on a measured VIOLATED → HELD flip.

Is the twin watching live Stripe traffic?

No. A twin is a separate host that speaks the vendor's paths. Your Edge Function or server must call sandbox_base_url. Live api.stripe.com is unchanged.

What if the probe cannot boot my app?

The result is unproven, not green. FetchSandbox currently boots Node.js and Python for prove_fix. A harness error is not evidence that the invariant held.