Skip to content

Multi-tenancy

One Mockifyr host can serve several independent sets of stubs. A tenant is chosen per request with the X-Mockifyr-Tenant header, and a tenant can never see another tenant’s stubs.

Terminal window
curl -X POST http://localhost:8080/__admin/mappings \
-H 'X-Mockifyr-Tenant: team-payments' \
-d '{"request":{"method":"GET","url":"/hello"},"response":{"status":200,"body":"payments"}}'
curl http://localhost:8080/hello -H 'X-Mockifyr-Tenant: team-payments'
# → payments

The header is honoured on every /__admin/* route, on the mock-serving facade, in the gRPC middleware and in the WebSocket facade. When the header is absent the request goes to the default tenant — which is what a host that never sets the header uses for everything.

Isolation is structural, not a filter applied late: every store and engine entry point takes an explicit tenant, so a code path that forgot to scope itself would not compile.

Listing tenants

Terminal window
curl http://localhost:8080/__admin/tenants
{ "tenants": ["default", "team-payments"] }

This reports the tenants that currently hold stubs. A tenant is not created or registered up front — it exists because something was stored under it.

What is not tenant-scoped

Some admin surfaces are deliberately host-level: they configure the process, not a set of stubs. Sending X-Mockifyr-Tenant to these routes changes nothing.

RouteScope
/__admin/recordings/*Host-level
/__admin/git/*Host-level
/__admin/outbound-trust*Host-level
/__admin/ext/*Host-level
/__admin/healthHost-level
/__admin/tenantsHost-level

Loading stubs into a named tenant

Stub files read from disk at startup go into the default tenant. There is no per-directory tenant convention at load time.

To populate a named tenant, either use the dashboard’s Import while that tenant is selected, or post the bundle with the header:

Terminal window
curl -X POST http://localhost:8080/__admin/mappings/import \
-H 'X-Mockifyr-Tenant: team-payments' \
--data-binary @mappings.json

What follows the tenant

  • Scenario state is keyed by (tenant, scenario name), so two tenants running the same scenario name advance independently.
  • Environments are tenant-scoped — each tenant owns its own keys and active values.

In the dashboard

The sidebar has a tenant switcher. Selecting a tenant scopes the whole UI — stubs, scenarios, environments and imports all act on that tenant until you switch again.

No per-user identity

Tenancy separates stubs; it does not separate people. Authentication is a single host-level admin credential, so anyone who can log in can switch to any tenant. Tenants are an isolation boundary for data, not a security boundary between users — see securing the admin API.