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)
baseUrlnoneOverride 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>.

Instance methods

MethodDescription
urlBase URL of the running server
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.