Sandbox / test mode
Mint a sfy_wsp_test_* key to build and debug an integration without accidentally emailing or texting your real customers. Pattern is modelled on Stripe test-mode keys.
How to create one
- Open your workspace at
/caller/settings→ API keys. - Click Create API key.
- Enable the Test mode (sandbox) checkbox.
- Pick scopes as usual and click create. The resulting key starts with
sfy_wsp_test_and shows a Test badge in the keys list.
What changes under test mode
- Blocked actions (return
403 TEST_MODE_BLOCKED):POST /invoices/:id/send— would email the invoice to the customer.POST /invoices/:id/send-reminder— would email a reminder.
- Every response carries
livemode: false. Live-key responses carrylivemode: true. - Every webhook event fired by a sandbox mutation includes
livemode: falseand__test__: true— handlers can filter test traffic cleanly. - Everything else is unchanged: real DB writes, real soft-delete, real webhooks (to your real endpoints), real search, real attachments, real activities. This matches Stripe test-mode behavior.
Example
# Create a sandbox key via the settings UI, then introspect it:
curl https://app.staffifyai.com/api/workspace/v1/me \
-H "Authorization: Bearer sfy_wsp_test_YOUR_SANDBOX_KEY"
# → 200 { object: "api_key", test_mode: true, livemode: false, ... }
# Normal mutations still write to the real DB (so you can inspect them in
# the workspace UI) — only outbound-to-customer actions are blocked:
curl -X POST https://app.staffifyai.com/api/workspace/v1/invoices/42/send \
-H "Authorization: Bearer sfy_wsp_test_YOUR_SANDBOX_KEY"
# → 403 { error: { code: "TEST_MODE_BLOCKED", ... } }Scopes & rate limits
Sandbox keys use the same scope catalog and the same rate limits as live keys. Scope-check and idempotency behave identically. Think of test mode as a filter, not a different tier.
Cleanup of test data
Test-mode mutations write to the real workspace DB — contacts, deals, invoices etc. show up alongside real data. To clean up: filter by the test records you created (use external_id prefixing or an obvious test name), then DELETE through the API. Soft-deletes flow through the normal 30-day recycle bin.
GET /me
The introspection endpoint reports whether the current key is a sandbox:
{
"object": "api_key",
"key_id": 42,
"key_prefix": "sfy_wsp_test_...",
"test_mode": true,
"livemode": false,
"scopes": [ ... ],
"tenant": { ... }
}