Skip to content

codeforge-tech/strimulator

Repository files navigation

Strimulator

A local Stripe emulator for development and testing

DocumentationGetting StartedResourcesSDK UsageDashboardDemoDockerAPI Reference


Strimulator is a drop-in local replacement for the Stripe API. It runs as a single process, stores everything in SQLite, and is compatible with the official stripe Node SDK. Use it to develop and test payment flows entirely offline — no Stripe account or network access required.

Think of it as LocalStack, but for Stripe.

Why Strimulator?

  • Offline development — No internet, no Stripe test mode, no rate limits
  • Fast feedback — Instant responses, no network latency
  • Full control — Trigger payment failures, advance subscriptions, simulate edge cases from the dashboard
  • SDK-compatible — Point the official stripe package at localhost and it just works
  • Docker-ready — Drop it into your docker-compose alongside Postgres, Redis, Firebase emulator, etc.
  • 3,500+ tests — Strict fidelity to Stripe's API shapes, state machines, and error formats

Getting Started

Prerequisites

Install and run

git clone https://github.com/codeforge-tech/strimulator.git
cd strimulator
bun install
bun run dev

Strimulator is now running:

Quick smoke test

# Create a customer
curl -X POST http://localhost:12111/v1/customers \
  -H "Authorization: Bearer sk_test_123" \
  -d "email=hello@example.com"

# Create a product and price
curl -X POST http://localhost:12111/v1/products \
  -H "Authorization: Bearer sk_test_123" \
  -d "name=Pro Plan"

# List customers
curl http://localhost:12111/v1/customers \
  -H "Authorization: Bearer sk_test_123"

SDK Usage

Point the official Stripe SDK at Strimulator — no code changes needed beyond the configuration:

import Stripe from "stripe";

const stripe = new Stripe("sk_test_strimulator", {
  host: "localhost",
  port: 12111,
  protocol: "http",
});

// Use exactly like real Stripe
const customer = await stripe.customers.create({ email: "dev@example.com" });
const product = await stripe.products.create({ name: "Pro Plan" });
const price = await stripe.prices.create({
  product: product.id,
  unit_amount: 2000,
  currency: "usd",
  recurring: { interval: "month" },
});
const subscription = await stripe.subscriptions.create({
  customer: customer.id,
  items: [{ price: price.id }],
});

console.log(subscription.status); // "active"

Environment variable approach

If your app reads STRIPE_SECRET_KEY, you can switch to Strimulator without touching code:

STRIPE_SECRET_KEY=sk_test_strimulator \
STRIPE_API_BASE=http://localhost:12111 \
  npm run dev

Supported Resources

Resource Endpoints State Machine
Customers CRUD + list + search
Products CRUD + list + search
Prices create, retrieve, update, list
Payment Methods create, retrieve, attach, detach, list
Payment Intents create, retrieve, confirm, capture, cancel, list, search requires_payment_method → requires_confirmation → succeeded
Setup Intents create, retrieve, confirm, cancel, list requires_payment_method → requires_confirmation → succeeded
Charges retrieve, list
Refunds create, retrieve, list
Subscriptions create, retrieve, cancel, list, search active / trialing / canceled / past_due
Invoices create, retrieve, finalize, pay, void, list, search draft → open → paid / void
Events retrieve, list
Webhook Endpoints CRUD + list
Test Clocks create, retrieve, advance, delete, list

Additional features

  • Webhook delivery — Registers endpoints via the API, delivers events with Stripe-Signature HMAC-SHA256 headers (compatible with stripe.webhooks.constructEvent()), retries on failure
  • Search API/v1/customers/search, /v1/payment_intents/search, etc. with Stripe's query language (email:"foo@bar.com", status:"active", metadata["key"]:"value")
  • expand[] — One-level and nested expansion (expand[]=customer, expand[]=latest_invoice.payment_intent)
  • Idempotency-Key — POST requests with the same key return cached responses
  • 3D Secure simulationtok_threeDSecureRequired triggers requires_action on confirm, re-confirm completes the challenge; tok_threeDSecureOptional also supported
  • Magic test tokenstok_visa, tok_mastercard, tok_amex, tok_visa_debit, tok_chargeDeclined, tok_threeDSecureRequired, tok_threeDSecureOptional — all produce deterministic card details

Dashboard

Open http://localhost:12111/dashboard for a real-time debug interface:

Activity Feed

Live stream of all API requests — method, path, status code, timing.

Resource Explorer

Browse all stored objects by type. Click any object to view its full JSON representation.

Actions Panel

Trigger simulated scenarios without writing code:

Action Description
Fail Next Payment Force the next PaymentIntent confirmation to fail (card_declined, insufficient_funds, expired_card)
Advance Test Clock Move a test clock forward in time, triggering subscription transitions
Retry Webhook Re-deliver an event to a webhook endpoint
Expire Payment Intent Force a PaymentIntent into canceled state
Cycle Subscription Advance a subscription to the next billing period

Demo App

An Astro SSR demo shop is included in demo/ to showcase the full payment flow — product listing, checkout with card selection, 3D Secure challenge, and success page. It uses the official Stripe Node SDK pointed at Strimulator.

# Start both Strimulator and the demo app with one command
bun run demo

Docker

Published to GitHub Container Registry on every version tag.

docker pull ghcr.io/codeforge-tech/strimulator:latest

Docker Compose (recommended)

Add to your project's docker-compose.yml:

services:
  strimulator:
    image: ghcr.io/codeforge-tech/strimulator:0.1.0
    ports:
      - "12111:12111"
    volumes:
      - strimulator-data:/data

  your-app:
    build: .
    environment:
      STRIPE_SECRET_KEY: sk_test_strimulator
      STRIPE_API_BASE: http://strimulator:12111
    depends_on:
      - strimulator

volumes:
  strimulator-data:

Build locally

docker build -t strimulator .
docker run -p 12111:12111 strimulator

Configuration

Environment Variable Default Description
STRIMULATOR_PORT 12111 Server port
STRIMULATOR_DB_PATH :memory: SQLite file path. Use :memory: for ephemeral storage or a file path for persistence across restarts
STRIMULATOR_LOG_LEVEL info Log verbosity
STRIMULATOR_API_VERSION 2024-12-18 Stripe API version returned in responses

API Reference

All endpoints live under /v1/ and follow Stripe's exact URL structure:

POST   /v1/customers
GET    /v1/customers/:id
POST   /v1/customers/:id
DELETE /v1/customers/:id
GET    /v1/customers
GET    /v1/customers/search?query=email:"foo@bar.com"

Authentication

All /v1/ requests require a bearer token starting with sk_test_:

Authorization: Bearer sk_test_anything

The actual key value doesn't matter — Strimulator accepts any sk_test_* key.

Request format

Like real Stripe, requests use application/x-www-form-urlencoded (not JSON):

curl -X POST http://localhost:12111/v1/customers \
  -H "Authorization: Bearer sk_test_123" \
  -d "email=test@example.com" \
  -d "metadata[plan]=pro"

Error format

Errors match Stripe's exact shape:

{
  "error": {
    "type": "invalid_request_error",
    "message": "No such customer: 'cus_nonexistent'",
    "param": "id",
    "code": "resource_missing"
  }
}

Development

# Install dependencies
bun install

# Run in development mode (auto-reload)
bun run dev

# Run tests
bun test

# Run specific test file
bun test tests/sdk/payment-flow.test.ts

Project structure

src/
  routes/        # ElysiaJS route plugins (one per Stripe resource)
  services/      # Business logic and state machines
  db/schema/     # Drizzle ORM table definitions
  middleware/    # Auth, idempotency, form parsing, request logging
  dashboard/    # Debug dashboard (API + Preact SPA)
  lib/          # Shared utilities (IDs, pagination, expand, search)
  errors/       # Stripe-compatible error factory
tests/
  unit/         # Service-layer tests
  integration/  # HTTP request/response tests
  sdk/          # Tests using the official stripe npm package
demo/            # Astro SSR demo e-commerce app
scripts/         # Orchestration scripts (demo launcher)
docs/            # Fumadocs documentation site (Next.js)

Documentation

Full documentation is available in the docs/ directory. To run it locally:

cd docs
bun install
bun run dev

Then open http://localhost:3000 for the docs site with Getting Started guides, API reference, and architecture documentation.

Tech Stack

  • Runtime: Bun
  • Framework: ElysiaJS
  • Database: SQLite via Drizzle ORM + bun:sqlite
  • Types: Imported from the stripe npm package
  • Dashboard: Preact + HTM (loaded from CDN)
  • Testing: bun:test (3,500+ tests)
  • Documentation: Fumadocs + OpenAPI

License

MIT

About

A Stripe local emulator for development purposes. Test your app money flows offline

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors