QuickBooks Online

Lightweight, dependency-free, in-memory fake of the QuickBooks Online Accounting v3 API for testing accounting integrations.

Default port: 4762

Quick start

import { QuickbooksServer } from "./services/quickbooks/src/server.js";

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

Call the API with a Bearer token and your realm id:

const realm = "parlel-realm";
const customer = await fetch(`http://127.0.0.1:4762/v3/company/${realm}/customer`, {
  method: "POST",
  headers: { Authorization: "Bearer parlel-qbo-token", "Content-Type": "application/json", Accept: "application/json" },
  body: JSON.stringify({ DisplayName: "Jane Co" }),
}).then((r) => r.json());
// customer.Customer.Id => "1"

Implemented operations

All /v3/company/:realmId/* routes require an Authorization: Bearer header (any non-empty token). Entities are wrapped (e.g. { Customer: {...} }). State is in-memory and ephemeral.

Customer — /v3/company/:realmId/customer

Invoice — /v3/company/:realmId/invoice

Query — /v3/company/:realmId/query

Supported entities for query/CRUD: Customer, Invoice, Item, Payment.

Service & inspection operations (parlel extensions)

Access via MCP / preview URL

Inside a parlel sandbox the service is reachable at its preview URL (QUICKBOOKS_BASE_URL, e.g. http://127.0.0.1:4762). Use any QUICKBOOKS_REALM_ID in the path and pass Authorization: Bearer. MCP agents can call any documented endpoint; /__parlel/reset clears state.

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
Customer create / get / sparse-update✅ Supported
Invoice create / get✅ Supported
query (GET ?query / POST raw)✅ Supported
Entity wrapping + SyncToken / MetaData✅ Supported
Item / Payment query✅ Supported (created via generic POST)
Full SQL grammar (WHERE / ORDER BY / paging)◐ Parses FROM <entity>; returns all rows
Batch operations / CDC / reports⟳ Roadmap
OAuth2 token refresh✓ By design — Out of scope (token assumed valid)
Webhooks✓ By design — Not emitted
Token validity / minor-version handling✓ By design — Any non-empty credential is accepted — no real secrets needed

Error codes & shapes

Errors use the QBO Fault envelope:

{ "Fault": { "Error": [{ "Message": "...", "code": "610", "Detail": "..." }], "type": "ValidationFault" }, "time": "..." }
StatusWhen
401missing Bearer token
404unknown entity id (Object Not Found) or unsupported resource

Manifest

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

QUICKBOOKS_ACCESS_TOKEN=parlel-qbo-token
QUICKBOOKS_REALM_ID=parlel-realm
QUICKBOOKS_BASE_URL=http://parlel-bridge:4762
<!-- parlel:testenv:end -->