Skip to main content
A deterministic, in-process simulation of Stripe’s crypto-deposit PaymentIntent flow and the x402 paywall protocol. Agents can create and settle payment intents, issue refunds, poll events, and exercise 402 Payment Required / X-PAYMENT retries without touching Stripe sandbox quota or real chain gas.

By use case

The twin’s surface has grown well past its original PaymentIntent-only scope, so a short bullet list can’t tell you whether your specific flow is covered. These are the use cases agents actually exercise against it, each naming the MCP tools and REST routes involved. For whether the fidelity check is currently passing and how recently it ran, see status.pome.sh.

Create and settle a crypto PaymentIntent

Create a PaymentIntent, drive it through requires_action, and settle it with the test-helper deposit tool. MCP: create_payment_intent, confirm_payment_intent, retrieve_payment_intent, simulate_crypto_deposit. REST: POST /v1/payment_intents, POST .../confirm, POST /v1/test_helpers/payment_intents/:id/simulate_crypto_deposit.

Reconcile a refund

Issue a refund against a settled charge, then confirm it against the event log and balance. MCP: create_refund, retrieve_refund, list_refunds, retrieve_charge, list_events, retrieve_balance. REST: POST /v1/refunds, GET /v1/refunds/:id, GET /v1/events, GET /v1/balance.

Manage a customer and their payment methods

Create a customer record, attach a payment method to it, and look up what’s on file before charging again. MCP: create_customer, retrieve_customer, update_customer, delete_customer, list_customers, create_payment_method, attach_payment_method, detach_payment_method, list_customer_payment_methods. REST: POST/GET/DELETE /v1/customers, GET .../customers/:id/payment_methods, POST .../payment_methods/:id/attach.

Inspect a subscription and its billing objects

Read products, prices, subscriptions, and invoices. REST: GET/POST /v1/products, /v1/prices, /v1/subscriptions (products, prices, and subscriptions support POST); /v1/invoices is GET-only — nothing mints an invoice, so GET /v1/invoices always returns an empty list and GET /v1/invoices/:id always 404s. These routes are shape-tier, not semantic — there’s no billing engine behind them running actual billing-cycle math, so responses match Stripe’s shape but the numbers inside aren’t computed the way real Stripe computes them. Don’t build a task that asserts on invoice amounts, invoice creation, or subscription period math yet.

Gate a resource behind x402

Protect a route with paymentMiddleware(), return a 402 challenge, and accept a retried request carrying an X-PAYMENT header once the agent pays.

Simulate failures for idempotency testing

Inject a lost-response failure on a refund or PaymentIntent call and confirm the agent retries with the same idempotency key instead of double-charging.

What’s out of scope

Checkout, Connect, webhook delivery loops, and most of the full Stripe surface beyond what’s listed above. Unsupported routes return 501 with fidelity: "unsupported".

Fidelity

Every surface above is tiered — semantic (a full behavioral contract, checked by an automated weekly capture), shape (the response shape matches but values aren’t asserted, as with the billing objects above), or unsupported (a loud 501 instead of a faked success). Only part of the semantic surface is captured by the weekly check today; the rest is rolling out. The Stripe row on status.pome.sh shows whether the check is passing and how recently it last ran — it does not list individual surfaces, so check the tiers above before you rely on a specific tool or route in a task.

Quickstart

That task boots the Stripe twin in-process, seeds it from the task’s ## Seed State block, hands your agent a session URL and token, and scores the run when the agent exits.

Point your agent at it

During a local pome run, Pome injects these environment variables into the agent process:
Hosted sessions may instead set POME_STRIPE_API_BASE and POME_STRIPE_API_KEY. It also accepts Stripe-style API keys. Tasks seed a default test key:
Point a Stripe SDK at the session REST URL with that key, or send the JWT as Authorization: Bearer <token> — both resolve to the same session.
Replace host and port with the values from your run’s POME_STRIPE_REST_URL. To check whether the twin process is alive during a run:
Stripe also runs standalone via pome twin start stripe, in-process via pome run, or through pome session create --twin stripe on hosted.

Task seed shape

Stripe tasks use a flat seed block with api_keys, and optionally payment_intents, charges, refunds, and failure_injection rules:
Set twins: ["stripe"] in the task’s ## Config block.

Example tasks

Ready-made examples you can run or copy to see the twin in action:

Catalog

Run one