Local Emulator
The cPod emulator is a lightweight Node.js server that runs the full REST API locally with 100+ seed records across every EDM domain. No Docker. No external services. No credentials required — any Bearer token is accepted.
http://localhost:4000Works with every SDK language. Point CPOD_API_URL at http://localhost:4000 and the SDK works exactly as it does in production. No code changes required to switch environments.
Quickstart
Clone the repo and install dependencies
git clone https://github.com/cpod-ai/cpod-sdk.git
cd cpod-sdk/emulator
npm installStart the emulator
node src/index.jsYou should see:
cPod Emulator v1.0.0
Listening on http://localhost:4000
Seed data: 8 people, 4 groups, 6 technology assets, 6 vulnerabilities, ...
Auth: any Bearer token accepted (dev mode)Verify it’s running
curl http://localhost:4000/v1/health{
"status": "ok",
"version": "1.0.0",
"uptime": 3,
"edm": {
"people": 8,
"groups": 4,
"technology": 6,
"entitlements": 10,
"licenses": 4,
"vulnerabilities": 6,
"complianceControls": 5,
"riskItems": 3
}
}Set your environment variables
export CPOD_API_URL=http://localhost:4000
export CPOD_API_KEY=any-token-works-in-devThat’s it — the emulator accepts any non-empty Bearer token. No OAuth registration needed for local development.
Make your first call
With the emulator running, try this in each language:
import { CpodClient } from '@cpod/sdk'
const sdk = CpodClient.fromEnv()
// Reads CPOD_API_URL and CPOD_API_KEY from env
const people = await sdk.people.list({ limit: 5 })
console.log(people.items)
// → [ { id: 'per-001', displayName: 'Alice Chen', ... }, ... ]Seed Data
The emulator starts with real-looking seed data across every domain:
| Domain | Entities |
|---|---|
| People | 8 people (employees, contractors) |
| Groups | 4 groups (Engineering, Security, Compliance, IT) |
| Technology | 6 assets + 10 access entitlements |
| Licenses | 4 software licenses + 20 assignments |
| Assets | 5 physical assets + 5 cloud resources |
| Risk | 6 vulnerabilities, 5 controls, 3 risk items |
| Relationships | 8 graph edges |
| Data Sources | 4 connectors (Okta, GitHub, AWS, Jira) |
| Platform | 3 skills, 3 user profiles, 2 pods |
All IDs use the correct prefix format (per-, grp-, vuln-, etc.) so you can build and test ID-based lookups immediately.
Available Endpoints
Every endpoint in the API Contract is available on the emulator. Key groups:
| Prefix | Domain |
|---|---|
/v1/people | People |
/v1/groups | Groups |
/v1/technology/assets | Technology Assets |
/v1/technology/entitlements | Access Entitlements |
/v1/licenses | Software Licenses |
/v1/assets/physical | Physical Assets |
/v1/assets/cloud | Cloud Resources |
/v1/risk/vulnerabilities | Vulnerabilities |
/v1/risk/controls | Compliance Controls |
/v1/risk/items | Risk Items |
/v1/relationships | Graph Relationships |
/v1/datasources | Data Sources |
/v1/storage/files/* | Blob Storage |
/v1/storage/db/* | Document Storage |
/v1/storage/kv/* | Key-Value Storage |
/v1/telemetry/audit/* | Audit Events |
/v1/telemetry/traces | LLM Traces |
/v1/telemetry/events | App Events |
/v1/organizations/current | Organization |
/v1/oauth/token | Token endpoint (returns mock token) |
/v1/health | Health check |
Auth in Dev Mode
The emulator accepts any non-empty Bearer token:
curl -H "Authorization: Bearer literally-anything" http://localhost:4000/v1/people
# Works ✓The token is parsed but signature validation is skipped. The emulator injects a fixed tenantId, appId, and userId from the token’s claims if present, or uses sensible defaults.
To test the full OAuth flow (token issuance, scopes, refresh):
curl -X POST http://localhost:4000/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=emulator-client&client_secret=emulator-secret"{
"access_token": "eyJ...",
"token_type": "bearer",
"expires_in": 3600
}Interactive API Browser
With the emulator running, open Swagger UI to explore and call every endpoint interactively:
npx @redocly/cli preview-docs docs/api-contract/openapi.yaml \
--base-url http://localhost:4000Or use Stoplight Elements (if installed):
npx @stoplight/elements-cli serve docs/api-contract/openapi.yamlAuto-Instrumentation
The emulator mirrors production behaviour — every write operation (POST, PUT, PATCH, DELETE) automatically emits an audit event:
# Create a person
curl -X POST http://localhost:4000/v1/people \
-H "Authorization: Bearer dev-token" \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","displayName":"Test User","firstName":"Test","lastName":"User","type":"employee"}'
# Check the audit log — the event was auto-emitted
curl -H "Authorization: Bearer dev-token" \
http://localhost:4000/v1/telemetry/audit/eventsCI Integration
Use the emulator in GitHub Actions without Docker:
# .github/workflows/integration.yml
jobs:
integration:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '22'
- name: Start emulator
working-directory: emulator
run: |
npm install
node src/index.js &
sleep 2
curl -sf http://localhost:4000/v1/health
- name: Run integration tests
env:
CPOD_API_URL: http://localhost:4000
CPOD_API_KEY: ci-dev-token
run: pnpm test:integrationEnvironment Variables Reference
| Variable | Emulator value | Production value |
|---|---|---|
CPOD_API_URL | http://localhost:4000 | https://api.yourdomain.com |
CPOD_API_KEY | any string | real API key from dashboard |
CPOD_CLIENT_ID | emulator-client | your registered client_id |
CPOD_CLIENT_SECRET | emulator-secret | your registered client_secret |
The emulator stores data in memory only — all writes are lost when the process restarts. It is not a substitute for a real database in staging environments.