Stripe

Lightweight, dependency-free, in-memory Stripe REST API fake for testing code that uses the real stripe SDK (and the language-agnostic Stripe REST API).

Default port: 4757

Quick start

Start the server:

import { StripeServer } from "./services/stripe/src/server.js";

const server = new StripeServer(4757);
await server.start();
// ... run your app/tests ...
await server.stop();

Point the real stripe client at it. The Stripe SDK reads its host from configuration, so override the base URL to the fake:

import Stripe from "stripe";

const stripe = new Stripe("sk_test_parlel", {
  host: "127.0.0.1",
  port: 4757,
  protocol: "http",
});

const customer = await stripe.customers.create({
  email: "jane@parlel.dev",
  metadata: { plan: "pro" },
});
// customer.id => cus_...

Stripe sends requests as application/x-www-form-urlencoded (including PHP-style bracket notation such as metadata[key]=value) and receives JSON. The fake parses both form-encoded and JSON bodies.

Implemented operations

All /v1/* routes require an Authorization: Bearer sk_test_... header (any non-empty bearer/basic token is accepted, matching a local test key). State is in-memory and ephemeral.

Customers

Charges

Payment intents

Refunds

Products & prices

Balance

Checkout sessions

Service & inspection operations (parlel extensions, not part of Stripe)

Access via MCP / preview URL

When run inside a parlel sandbox the service is reachable at its preview URL (the STRIPE_BASE_URL env var, e.g. http://127.0.0.1:4757). Point the stripe SDK host/port/protocol (or your STRIPE_BASE_URL) at that address. MCP-driven agents can call any documented endpoint directly; the /__parlel/reset control endpoint clears state between scenarios.

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
customers.* (create/list/get/update/delete)✅ Supported — response includes always-present fields (balance, delinquent, tax_exempt, default_source, invoice_settings, ...)
charges.* (create/list/get/update)◐ Always status: succeeded, paid: true; receipt_url/outcome/payment_method_details returned as null (no real card processing)
paymentIntents.* (create/list/get/update/confirm/cancel/capture)✅ Supported — create returns requires_payment_method; manual-capture flow (requires_capturecapture) supported
refunds.* (create/list/get/update)✅ Supported
products.* (create/list/get/update/delete)✅ Supported
prices.* (create/list/get/update)✅ Supported — create validates required currency/product/unit_amount
balance.retrieve✅ Supported — available/pending arrays (omits feature-gated instant_available/connect_reserved/issuing)
checkout.sessions.* (create/list/get/expire)line_items echoed verbatim; amount_total/amount_subtotal/payment_intent returned as null (no real session computation)
List cursor pagination (limit, starting_after, ending_before)✅ Supported
Form-encoded (bracket notation) + JSON request parsing✅ Supported
Deterministic prefixed ids (cus_, ch_, pi_, re_, prod_, price_, cs_)✅ Supported
Error envelope ({error:{type,code,doc_url,message,param}}) incl. 401 WWW-Authenticate header✅ Supported
Webhooks / signed events⟳ Roadmap — event emission planned
PaymentMethods / SetupIntents / Tokens (pm_/tok_ flows)⟳ Roadmap — these endpoints return 404
Subscriptions / invoices / billing schedules⟳ Roadmap
Real card processing / 3DS / SCA✓ By design — Always succeeds deterministically — no real funds move
Idempotency-Key 24h enforcement✓ By design — Not enforced
Rate limiting (429)✓ By design — Never throttles — local tests run at full speed, zero cost
Bearer/Basic-token validity / scope enforcement✓ By design — Any non-empty credential is accepted — invalid-format keys are NOT rejected, no real secrets needed

Error codes & shapes

Errors use the Stripe envelope (key order type, code, doc_url, message, param):

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

The 401 response additionally sets a WWW-Authenticate: Basic realm="Stripe" header and carries code: "authentication_required" plus a doc_url.

StatusWhen
400missing required param (e.g. amount, name, price currency/product/unit_amount), invalid body (code: parameter_missing)
401no Authorization header (code: authentication_required, WWW-Authenticate header)
404unknown resource id (code: resource_missing), unknown endpoint, or unsupported method on a path (matching real Stripe, which returns 404 Unrecognized request URL rather than 405)

Manifest

See services/stripe/manifest.json:

<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

STRIPE_API_KEY=sk_test_parlel
STRIPE_SECRET_KEY=sk_test_parlel
STRIPE_BASE_URL=http://parlel-bridge:4757
<!-- parlel:testenv:end -->