Programmatic API

Use emulators as libraries in your tests and scripts. There are two approaches: the api-emulator CLI package (which wraps all services) and the individual @api-emulator/* scoped packages.

CLI package

The api-emulator package provides a createEmulator helper that starts any service by name.

npm install api-emulator
import { createEmulator } from "api-emulator";

const github = await createEmulator({ service: "github", port: 4001 });
const vercel = await createEmulator({ service: "vercel", port: 4002 });

github.url; // 'http://localhost:4001'
vercel.url; // 'http://localhost:4002'

await github.close();
await vercel.close();

Vitest / Jest setup

// vitest.setup.ts
import { createEmulator, type Emulator } from "api-emulator";

let github: Emulator;
let vercel: Emulator;

beforeAll(async () => {
  [github, vercel] = await Promise.all([
    createEmulator({ service: "github", port: 4001 }),
    createEmulator({ service: "vercel", port: 4002 }),
  ]);
  process.env.GITHUB_EMULATOR_URL = github.url;
  process.env.VERCEL_EMULATOR_URL = vercel.url;
});

afterEach(() => {
  github.reset();
  vercel.reset();
});
afterAll(() => Promise.all([github.close(), vercel.close()]));

createEmulator options

OptionDefaultDescription
service(required)

Service name: 'vercel', 'github', 'google', 'slack', 'apple', 'microsoft', 'aws', 'okta', 'mongoatlas', 'resend', or 'stripe'

port4000Port for the HTTP server
seednoneInline seed data (same shape as YAML config)
grpcPortHTTP port + 10000Native gRPC port for a gRPC-capable plugin
baseUrlnone

Override the advertised base URL (used in OAuth redirects, webhook URLs, etc.). Per-service baseUrl in seed config takes highest priority, then this option, then the API_EMULATOR_BASE_URL env var (supports {service} template), then PORTLESS_URL (supports {service}, automatically set by the portless CLI wrapper), then http://localhost:<port>.

latencyMs0Delay each HTTP response by this many milliseconds.

Instance methods

MethodDescription
urlBase URL of the running server
grpcUrlNative gRPC address when the plugin declares gRPC services
snapshot()Capture the current store snapshot
restore(fixture)Restore a store snapshot or exported fixture
exportFixture(options?)Export a fixture envelope with store state and recorded interactions
resetToFixture(fixture)Reset state to a captured fixture
reset()Wipe the store and replay seed data
close()Shut down the HTTP server, returns a Promise

Fixtures

Use fixtures to stabilize a stochastic or stateful run:

const fixture = github.exportFixture({ metadata: { name: "pull-request-flow" } });

github.resetToFixture(fixture);

Scoped packages

Each emulator is published as its own @api-emulator/* package. Install only the ones you need:

npm install @api-emulator/github @api-emulator/google @api-emulator/stripe

Available packages

PackageService
@api-emulator/vercelVercel API
@api-emulator/githubGitHub API
@api-emulator/googleGoogle OAuth, Gmail, Calendar, Drive
@api-emulator/slackSlack Web API, OAuth v2, webhooks
@api-emulator/appleApple Sign In / OIDC
@api-emulator/microsoftMicrosoft Entra ID, Graph API
@api-emulator/awsAWS S3, SQS, IAM, STS
@api-emulator/oktaOkta identity provider / OIDC
@api-emulator/mongoatlasMongoDB Atlas Admin API + Data API
@api-emulator/resendResend email API
@api-emulator/stripeStripe billing and payments API
@api-emulator/coreShared store, middleware, and utilities
@api-emulator/adapter-nextNext.js App Router integration

Direct usage

Each scoped package exports its Hono app and seed function, so you can compose emulators however you like:

import * as github from "@api-emulator/github";
import * as stripe from "@api-emulator/stripe";

These are the same modules used internally by the CLI and the Next.js adapter. See the Next.js Integration page for a full example of using scoped packages with createApiEmulatorHandler.