Getting started
Run a signup app against a local Stripe twin, using Stripe's real SDK. Create a customer, read it back, check the result, and return to the same starting state for another run.
A twin answers one vendor's API. A World runs the twins you select for your app, with their data, scripted behavior and environment. This walkthrough uses local simulated execution: no Stripe account, real API key or Volter platform account is needed. Your app keeps its SDK.
What you need
Use Node 22.6 or newer and npm for this walkthrough. Installing packages needs registry access. The example pins its CLI, twin and SDK. See installation for supported runtimes and other package managers.
Start in a new, empty directory. Save each file under the filename shown and run commands from that directory. To start directly in an existing app, use manual setup or ask your coding agent to set up its World.
1. Save the app
Save package.json:
{
"name": "acme-web",
"private": true,
"type": "module",
"dependencies": { "stripe": "17.7.0" },
"devDependencies": {
"@volter/world": "3.0.69",
"@volter/twin-stripe": "3.0.2"
}
}Save .env.example. These names tell World which credentials the app reads; leave values empty:
STRIPE_SECRET_KEY=Save signup.mjs. It creates and retrieves a customer with the same SDK calls used in production:
import assert from 'node:assert/strict';
import Stripe from 'stripe';
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
const customer = await stripe.customers.create({ email: '[email protected]', name: 'Ada' });
const saved = await stripe.customers.retrieve(customer.id);
assert.equal(saved.email, '[email protected]');
assert.equal(saved.name, 'Ada');
console.log(`created ${customer.id}`);
console.log('customer read-back passed');There is no twin URL or mocked client in the app. The assertion checks stored behavior, rather than just whether a request returned a success status.
2. Install and select the twin
npm installThis example deliberately substitutes Stripe. For your app, choose a twin that serves the operations you need. Catalog vendor names identify APIs; npm package names identify implementations, which may come from different publishers.
Create the World with the locally installed, pinned CLI:
npx volter world init --name acme-webstripe
COVERED:Read the detected vendors and their reasons before keeping them. This app names only Stripe's SDK and credential. Finding a twin does not establish support for every Stripe operation; the coverage guide explains the distinction.
init writes .volter/world.json, recording the selected package and version, and prepares
fake credentials. Keep real credentials out of the World. Commit the config, project-owned
seeds and handlers with package.json and package-lock.json. The generated ignore file keeps
running state out of Git.
3. Start the World
npx volter world upacme-web 1 twin up, story loadedA fresh branch loads its default data. Ordinary up later resumes retained state; it does
not reset data on every start.
Freeze the World clock so vendor timestamps have the same starting instant:
npx volter world clock set 2026-01-15T12:00:00ZThe twin answers selected Stripe requests locally. Routing alone is not a network isolation boundary for arbitrary programs; Worlds explains sandbox mode and its limits.
4. Run the app and check its result
npx volter world run -- node signup.mjscreated cus_twin_1
customer read-back passedrun supplies a fake credential and routes the SDK's normal api.stripe.com requests to the
twin. The assertion passed: the created record was visible on the next read. Run your
development server or test runner the same way, with its usual command after --.
5. Inspect what happened
npx volter world logcustomer.create
event.recordThe log records the customer write and the event Stripe records for it. Reads do not add stored mutations. There is no staging or commit step in a World.
npx volter world statusWorld acme-web on branch acme-web: running
default data (no remote)For a browser view, inspect a World opens its dashboard and vendor screens. The CLI log and SDK assertions already let you inspect this run.
6. Reset and repeat
The World retains writes between runs. Reset before repeating this example:
npx volter world reset
npx volter world clock set 2026-01-15T12:00:00Z
npx volter world log(no changes yet)Reset discards this branch's changes and reloads default data. Set the clock explicitly for each replay. A parent with dependent branches cannot be reset; branching explains their lifetime.
npx volter world run -- node signup.mjscreated cus_twin_1
customer read-back passedThe customer is created from the same starting state and the assertion passes again. This example checks those outcomes; it is not a claim about complete Stripe fidelity.
7. Stop
npx volter world downStopped acme-webdown stops compute and retains branch state. reset returns it to default data.
down --purge removes retained state when no dependent branch references it.
Choose your next task
- Continue tomorrow with the same records: resume your World.
- Bring your own application: use an existing app.
- Choose an implementation or understand its assessment: choose a twin.
- Go from a catalog release to an SDK call: use a catalog twin.
- Open the dashboard: inspect a World.
- Add records: seed and reset.
- Script an answer or failure: shape the World for a test.
- Run your own assertions: run your test suite.
- Run app, database and browser tests: run a full stack.
- Use an agent: use World with a coding agent.
- Repeat on pull requests: use in CI.
- Collaborate: share a World.
Shared Worlds, changesets and deployment build on this local workflow. The model explains how push moves history between Worlds and deployment performs changes at a real-system root.