Guide

Workspaces and environments

A workspace holds its own transactions, disputes, people, synthetic accounts, API keys, webhooks and settings. Your account can own several and belong to others', so you can keep one workspace per environment and always see which one you are in.

One workspace per environment

Your test suites, your staging agents and the demo you show customers should not share data. Give each its own workspace, say Acme · DEVELOPMENT, Acme · STAGING and Acme · PRODUCTION: a reset or a flood of generated disputes in Development never touches Staging, and a CI key for Staging can never write into Production.

Create a workspace

Open the workspace menu at the top of the sidebar (on a phone, tap the workspace name in the top bar) and choose Create workspace…:

  • Name, up to 80 characters.
  • Environment label: one of the suggested labels below, a custom label of up to 24 characters with any colour, or no label. A custom label without a colour is shown in neutral slate, so it never looks like one of the suggested environments.
  • Copy settings from (optional): a workspace you own. Its default currency and time zone are copied; nothing else.

You become its owner and land on its empty dashboard. A new workspace starts with the defaults: no data, no people but you, no synthetic accounts, keys, webhooks, playbooks or flow profiles. Your own preferences (language, theme, page size) come along.

List your workspaces, create one
curl -s https://api.dispute.markets/v1/me/workspaces \
  -H "Authorization: Bearer $DM_SESSION"

curl -s https://api.dispute.markets/v1/workspaces \
  -H "Authorization: Bearer $DM_SESSION" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"name": "Acme", "environment_label": "Staging", "copy_settings_from": "tnt_…"}'

POST /v1/workspaces answers 201 with the workspace and a sessionalready switched into it. A suggested label sent without a colour gets that label's colour.

Limits

LimitValue
Workspaces you created and still own10, your sign-up sandbox included (workspace_limit_reached). Workspaces you joined, or were made owner of, do not count; one you handed over and left no longer counts.
Workspaces created per day5, deleted ones included (workspace_create_rate_limited, with retry_after_s)
Workspaces you belong to50 (membership_limit_reached)

limits in GET /v1/me/workspaces says where you stand. Only people create workspaces: a synthetic account gets synthetic_account_not_allowed, and an account whose e-mail is not verified email_not_verified.

The environment label

Suggested labelColour
Developmentteal #0d9488
Stagingamber #d97706
Productionred #dc2626
Sandboxviolet #7c3aed

The label is on every row of the workspace menu, on the menu itself, as a chip in the top bar, as a thin stripe in its colour across the top of every page, in the browser tab title, and in every confirm that destroys something (“Delete Acme · PRODUCTION?”, “Reset Acme · STAGING?”). Colour never stands alone: the text is always there. The menu and Settings > Workspaces sort in pipeline order: Development, Staging, Production, Sandbox, custom labels A to Z, then no label.

The label is cosmetic. No permission, key, flow or confirm depends on it, and any owner can change it in Settings > Workspace at any time (API), so never use it as a safety boundary. The dev panel's reset asks you to type the workspace's name whatever its label.

New sign-ups get a workspace called “<username>'s sandbox” labelled Sandbox. Existing workspaces keep the label they have.

Switching

Pick a workspace in the menu. Each row shows the label, the name and your role; Pending invites (N) and Manage workspaces… sit below them. Signing in lands you in the workspace you used last.

  • One workspace per browser. All tabs of a browser share it. Switching reloads the dashboard of the new workspace, so nothing from the old one stays on screen.
  • Other tabs notice.A tab still showing Staging after you switched to Production elsewhere is covered by a banner, “You switched to Acme · PRODUCTION in another tab.”, with Go to Acme · PRODUCTION or Switch back to Acme · STAGING. Such a tab cannot read or write anything until you choose.
  • Side by side, for example Staging and Production in two windows, needs two browser profiles (or a private window), each signed in on its own.
Switch a session
curl -s https://api.dispute.markets/v1/auth/switch-workspace \
  -H "Authorization: Bearer $DM_SESSION" \
  -H "Content-Type: application/json" \
  -d '{"workspace_id": "tnt_…"}'

The answer holds new tokens for the chosen workspace. Unknown ids and workspaces you are not in both answer workspace_not_found; synthetic accounts cannot switch (workspace_switch_not_allowed). A session that has no workspace (you left or lost your last one) reaches only your account and workspace routes; anything else answers no_active_workspace.

Pin a request to a workspace: X-DM-Workspace

Send X-DM-Workspace: tnt_… to make a request fail rather than act in the wrong workspace. When the session or key acts in another workspace the answer is workspace_mismatch (409, with details.current_workspace_id) and nothing happens. The header is optional; the portal sends it on every call.

Fails unless the key acts in tnt_…
curl -s https://api.dispute.markets/v1/whoami \
  -H "Authorization: Bearer $DM_API_KEY" \
  -H "X-DM-Workspace: tnt_…"

API keys and webhooks stay in their workspace

  • An API key belongs to the workspace it was created in and can never act in another: switching your session changes nothing for your keys. The one-time reveal says “This key works only in Acme · STAGING.” Create one key per workspace your CI talks to.
  • Webhooks, webhook sinks, playbooks, flow profiles, reports and scheduled jobs belong to one workspace and are never shared or copied, not even by Copy settings from.
  • GET /v1/whoami names the workspace a key or session acts in, with its label, so a test can check it is pointed at the right one. The E2E guide's “One workspace per environment” recipe does exactly that, and proves a key cannot reach another workspace.

Leave a workspace

Settings > Workspaces lists every workspace you belong to with its label, your role, its people and its owners. Leave ends your access at once; you need a new invite to come back. The last owner cannot leave (last_owner): make someone else an owner first, or delete the workspace. What you created there is handled as described in Team.

Leave
curl -s -X POST https://api.dispute.markets/v1/me/workspaces/tnt_…/leave \
  -H "Authorization: Bearer $DM_SESSION" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{}'

When your session was in that workspace, the answer carries a session for your next workspace, or null when you have none left.

Delete a workspace

Owners find Deletenext to Leave. The dialog lists what goes: transactions, disputes, people, synthetic accounts and API keys (and reports and webhooks when there are any). Type the workspace's name to confirm. Unless the workspace is empty and you are its only person, a second factor from the last 5 minutes is asked for too, so throwaway Development workspaces stay cheap to remove.

  • Everyone loses access at once, its keys stop working and its webhooks stop sending.
  • Every person in it gets a mail saying it was deleted.
  • The deletion is recorded in the workspace's audit trail.
  • Deleted workspaces are removed for good after 30 days. There is no undo in the portal.
Preview, then delete
curl -s https://api.dispute.markets/v1/workspaces/tnt_…/deletion-preview \
  -H "Authorization: Bearer $DM_SESSION"

curl -s -X DELETE https://api.dispute.markets/v1/workspaces/tnt_… \
  -H "Authorization: Bearer $DM_SESSION" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"confirm_name": "Acme"}'

The preview's step_up_required says whether the second factor will be asked for. A name that does not match is confirm_name_mismatch; without a recent second factor the answer is step_up_required. The delete answers 202, and deleting your only workspace is allowed: you land on the workspace chooser and can create a new one.

Reference

Every route, field and error code is in the API reference, and these routes take a signed-in session, never an API key (see Scripts).