A NestJS-based high-fidelity simulator for building and testing integrations with Romanian ANAF APIs, including OAuth2, e-Factura, and VAT lookup workflows.
This service is designed for local development and CI environments where you want realistic API behavior without requiring a physical digital certificate, live ANAF credentials, or an actual ANAF developer account.
- Full OAuth2 Flow: Authorization Code grant flow, Token exchange, and Refresh support.
- e-Factura Simulation: 100% OpenAPI compliant implementations of
/upload,/uploadb2c,/stareMesaj,/listaMesajeFactura,/listaMesajePaginatieFactura, and/descarcare. - ANAF-Specific Rate Limiting: Enforces official daily quotas (e.g., 1000 RASP/day, 100,000 paginated list queries/day) with exact ANAF error messages.
- Strict Validation: Replicates ANAF's unique HTTP 200 XML/JSON error responses for file sizes (>10MB), invalid timestamps (60-day limits), and missing parameters.
- Swagger API Documentation: Interactive Swagger UI at
/swaggercross-referencing official ANAF URLs and fully documenting all simulation cheat headers. - MCP (Model Context Protocol) Server: Built-in MCP server at
/mcp(Streamable HTTP transport) turning the mock into an AI-native tool. AI agents (Claude, Gemini, Cursor, Windsurf) can dynamically read ANAF schemas, understand cheat headers, and execute tools to generate valid integration code. - Fault Injection: Configurable latency, random 500/504 errors, and generic 429 rate-limiting modes for edge-case testing.
- Traffic Generation: Background tasks to simulate active SPV inboxes with realistic inter-company invoice flow.
- VAT Registry Simulation: Mock VAT lookup (v9 standard) with deterministic company data.
- Developer Portal UI: Built-in dashboard at
/consolefor app registration and identity management. - Flexible Storage: In-memory state by default, or Redis-backed for persistent simulation across restarts.
- Install Dependencies:
npm install
- Run in Watch Mode:
Open
npm run start:dev
http://localhost:3003/consoleto manage the mock environment.
The project is published as a multi-stage lightweight Docker image (Alpine-based) to GitHub Container Registry (GHCR).
Run the latest stable release directly from GHCR:
docker run -p 3003:3003 ghcr.io/aperta-sync/anaf-api-simulator:latestIf you want to build the image locally from source:
docker build -t anaf-mock-server:latest .
docker run -p 3003:3003 anaf-mock-server:latestYou can customize the simulation behavior via environment variables:
docker run -p 3003:3003 \
-e ANAF_MOCK_LATENCY_MS=500 \
-e ANAF_MOCK_ERROR_RATE=5 \
-e ANAF_MOCK_STRICT_OWNERSHIP=true \
ghcr.io/aperta-sync/anaf-api-simulator:latestThis mock server includes a built-in Model Context Protocol (MCP) server that turns the entire ANAF API simulation into a set of tools for AI agents. This allows LLMs (like Claude or Gemini) to dynamically generate, test, and debug your ANAF integration.
The server uses the Streamable HTTP transport (the current MCP standard) at a single endpoint: http://localhost:3003/mcp.
claude mcp add --transport http anaf-mock-server http://localhost:3003/mcpTo verify the server was added:
claude mcp listTo remove it:
claude mcp remove anaf-mock-serverAdd the following to ~/.gemini/settings.json:
{
"mcpServers": {
"anaf-mock-server": {
"httpUrl": "http://localhost:3003/mcp",
"timeout": 30000
}
}
}Note: The
httpUrlkey targets the Streamable HTTP transport. If your Gemini CLI version does not yet supporthttpUrl, try"url": "http://localhost:3003/mcp"instead — some tools accept both keys for the same transport.
For any IDE or tool that reads a generic MCP JSON config:
{
"mcpServers": {
"anaf-mock-server": {
"url": "http://localhost:3003/mcp",
"timeout": 30000
}
}
}Once connected, your AI agent can perform tasks like:
- "Check if my upload request matches the official ANAF schema." (Uses
get_swagger_spec) - "Generate a valid UBL XML for testing." (Uses
generate_ubl_xml) - "List all available simulation headers." (Uses
list_cheat_headers) - "Verify my rate-limit consumption for today." (Uses
check_quota_usage)
This drastically reduces the time needed to build robust e-Factura integrations by letting the AI "know" the API better than a human.
The project maintains a high-fidelity sync with official ANAF documentation.
- Manual Guides: Human-readable summaries of API endpoints, OAuth2 registration, and the complete e-Factura integration workflow.
- Scraped Assets:
- Swagger JSONs:
docs/anaf/scraped/technical/swagger/contains automated OpenAPI extractions. - Technical Specs:
docs/anaf/scraped/technical/contains text limit files.
- Swagger JSONs:
To keep the repository lean, our scraper automatically offloads heavy ANAF assets (>200MB of PDFs and ZIPs) and its execution state directly to a Backblaze B2 bucket.
Our daily GitHub Action Check ANAF Documentation Parity (docs-sync.yml) runs the scraper. If ANAF updates their API, the action uses gh issue create to automatically open a tracked Issue alerting maintainers to update the mock code. Furthermore, any Pull Request (ci.yml) will fail if code is pushed that is out-of-sync with ANAF's documentation.
To update the scraped documentation locally, run:
node scripts/anaf-scraper.mjsYou can trigger specific ANAF error responses by sending custom HTTP headers with your requests. This is useful for testing your application's error-handling logic.
| Header | Value | Description |
|---|---|---|
X-Simulate-Upload-Error |
true |
Returns a generic upload validation error XML. |
X-Simulate-Xml-Validation |
true |
Returns a SAXParseException (invalid XML) error XML. |
X-Simulate-No-Spv |
true |
Returns "Nu exista niciun CIF pentru care sa aveti drept in SPV". |
X-Simulate-Wrong-Certificate |
true |
Returns an ANAF_CUI_MISMATCH 403 error. |
X-Simulate-Technical-Error |
true |
Returns a "Cod: SIM-001" technical error XML. |
The server behavior is controlled by environment variables. These can be set in a .env file or passed directly to Docker.
| Variable | Default | Description |
|---|---|---|
ANAF_MOCK_PORT |
3003 |
HTTP port the server listens on. |
ANAF_MOCK_STORE |
memory |
State backend: memory or redis. |
ANAF_MOCK_VERSION |
0.1.0 |
Injected version string shown in the UI. |
| Variable | Default | Description |
|---|---|---|
ANAF_MOCK_LATENCY_MS |
200 |
Artificial delay (ms) for every API response. |
ANAF_MOCK_ERROR_RATE |
0 |
Probability (0-100) of random 500/504 failures. |
ANAF_MOCK_RATE_LIMIT_MODE |
off |
Throttle strategy: off, deterministic, or windowed. |
ANAF_MOCK_STRICT_OWNERSHIP |
true |
When enabled, OAuth tokens must "own" the target CIF to download invoices. |
ANAF_MOCK_STRICT_VAT |
false |
When enabled, only explicitly seeded companies are found. |
ANAF_MOCK_AUTO_TRAFFIC |
false |
Automatically generates random invoices every minute. |
| Variable | Default | Description |
|---|---|---|
REDIS_URL |
Full connection string (e.g. redis://user:pass@host:port). |
|
REDIS_HOST |
127.0.0.1 |
Fallback host if REDIS_URL is missing. |
REDIS_PORT |
6379 |
Fallback port if REDIS_URL is missing. |
| Variable | Default | Description |
|---|---|---|
ANAF_MOCK_BOOTSTRAP_PRESET |
anaf-core |
Startup seed dataset: anaf-core, anaf-large, or none. |
ANAF_MOCK_BOOTSTRAP_CUIS |
Comma-separated Romanian CUIs to seed on startup. |
You can change the simulation behavior on the fly without restarting:
curl -X PATCH http://localhost:3003/simulation/config \
-H "Content-Type: application/json" \
-d '{ "latencyMs": 500, "errorRate": 10 }'- Unit Tests:
npm run test - E2E Tests:
npm run test:e2e(Uses an in-memory server to verify full flows).
We welcome contributions from the community to make this simulator more robust! To maintain stability, our master branch is protected. Please follow this standard workflow:
- Open an Issue: Before writing code, please open an issue using our Bug Report or Feature Request templates to discuss your proposed changes.
- Create a Branch: Check out a new feature branch from
master(e.g.,git checkout -b feat/new-spv-endpoint). - Commit & Push: Make your changes and push them to your branch. Ensure your code passes all linting and local tests (
npm run test). - Open a Pull Request: Submit a PR against the
masterbranch using the provided PR template. - CI/CD Validation: Our automated CI pipeline will trigger to run tests and validate the Docker build. The CI status must be green before a maintainer can review and merge your PR.
This tool is intended for development and testing only.
