Chargebee

Lightweight, dependency-free, in-memory fake of the Chargebee v2 API for testing subscription billing integrations.

Default port: 4764

Quick start

import { ChargebeeServer } from "./services/chargebee/src/server.js";

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

Chargebee uses Basic auth (API key as the username, blank password) and application/x-www-form-urlencoded request bodies (including bracket notation such as subscription[plan_id]=basic). Responses are JSON wrapped in the resource name:

const basic = Buffer.from("test_parlel:").toString("base64");
const res = await fetch("http://127.0.0.1:4764/api/v2/customers", {
  method: "POST",
  headers: { Authorization: `Basic ${basic}`, "Content-Type": "application/x-www-form-urlencoded" },
  body: "first_name=Jane&email=jane@parlel.dev",
}).then((r) => r.json());
// res.customer.id => cust_...

Implemented operations

All /api/v2/* routes require Basic auth (any non-empty API key). Request bodies are form-encoded (bracket notation supported); responses are wrapped as { customer: {...} } and lists as { list: [{ customer: {...} }], next_offset }. State is in-memory and ephemeral.

Customers — /api/v2/customers

Subscriptions — /api/v2/subscriptions

Invoices — /api/v2/invoices

Plans — /api/v2/plans

Service & inspection operations (parlel extensions)

Access via MCP / preview URL

Inside a parlel sandbox the service is reachable at its preview URL (CHARGEBEE_BASE_URL, e.g. http://127.0.0.1:4764). Pass Basic auth with any API key as the username. MCP agents can call any documented endpoint; /__parlel/reset 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✅ Supported
subscriptions create / list / get / update / cancel✅ Supported
invoices create / list / get / update✅ Supported
plans create / list / get / update✅ Supported
Form-encoded (bracket notation) request parsing✅ Supported
{ resource: {...} } wrap / { list: [...] } list shape✅ Supported
Proration / billing cycles / dunning✓ By design — Not computed
Hosted pages / portal sessions⟳ Roadmap
Coupons / addons / item-model entities⟳ Roadmap
Webhooks✓ By design — Not emitted
Offset/limit paginationnext_offset returned but all rows listed
API-key validity✓ By design — Intentional for a local, zero-cost test emulator

Error codes & shapes

{ "message": "...", "type": "invalid_request", "api_error_code": "resource_not_found", "http_status_code": 404 }
StatusWhen
400malformed body / missing param
401missing Basic auth
404unknown resource id / route
405method not allowed

Manifest

See services/chargebee/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.

CHARGEBEE_API_KEY=test_parlel
CHARGEBEE_SITE=parlel-test
CHARGEBEE_BASE_URL=http://parlel-bridge:4764
<!-- parlel:testenv:end -->