Skip to main content

Sandbox (nex_test_ keys)

Requests authenticated with a nex_test_ API key use the same production database as live traffic, but only see and mutate rows marked is_sandbox = true. Live keys (nex_live_), personal access tokens (nex_pat_), and normal browser sessions only see rows where is_sandbox is false (legacy rows without the flag are treated as live).
You cannot create a nex_test_ key on api.nexspace365.com. The prefix is not something you pick — the server derives it from its own environment: an instance running with NODE_ENV=production mints nex_live_, any other instance mints nex_test_. The only choice on the create form (and in the create payload) is the Personal access token toggle, which mints nex_pat_. There is no environment field.So sandbox keys are issued only by non-production NexSpace deployments (a local dev instance, or any deployment not running with NODE_ENV=production) — and everything on this page describes how the platform behaves for traffic authenticated with one. The row-level isolation below is real and is why there is no separate sandbox hostname; the credential to exercise it is what you can’t self-serve in production. Key creation is separately restricted to NexSpace 365 operators — see Authentication → API Keys.
For the full rationale and migration notes, see ADR 0003 in the repository (docs/decisions/0003-sandbox-environment.md).

Isolation rules

New rows created while handling a sandbox request are stored with is_sandbox = true. Updates and deletes apply only within that partition, so test keys cannot modify production shift/staff/credential/payroll rows and production traffic cannot touch sandbox copies.

Tables in Phase 1 scope

Row-level isolation is enforced today on the highest-traffic transactional surfaces, including:
  • Shifts (related assignments and shift-linked flows follow shift visibility)
  • Staff
  • Credentials
  • Payroll runs
  • API key usage events (each request log carries is_sandbox)
Other domains may not yet filter on is_sandbox everywhere. If you call an endpoint outside this scope, assume isolation is not guaranteed until covered by the same pattern.

Side effects

Sandbox requests do not deliver real user notifications (push, SMS, email); attempts are skipped and logged. Outbound platform webhooks are not emitted for sandbox-key traffic.

Usage analytics and outcomes

All GET /api/api-usage/* aggregates (summary, timeseries, by-agent, by-tool, by-key, outcomes) include production traffic only: rows with is_sandbox = true are excluded so outcome counts align with billing-oriented views.

Retention (TTL) and reset

Two independent mechanisms keep the sandbox tidy:
  • Retention purge (global safety net). Sandbox rows older than 30 days are deleted by a daily background job. Purge order favors dependents (e.g. shifts first where cascading applies), then staff, credentials, payroll runs, and sandbox usage-event rows.
  • On-demand reset (immediate, facility-scoped). POST /api/sandbox/reset clears a single facility’s sandbox rows and re-seeds a small synthetic dataset (5 workers, 10 open shifts) so you can start from a predictable slate.
Via CLI (same session constraint — login with device-code / browser session, not an API key):
Reset is a dashboard/session operation restricted to NexSpace 365 administrators. It cannot be called with an API key (including a nex_test_ key) — this prevents a low-scope token from wiping data. Sign in and call it with your session, use nexspace fixtures sandbox-reset, or trigger it from the developer settings UI.
The response reports what was cleared and re-seeded: