> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.pivotal.app/llms.txt.
> For full documentation content, see https://docs.pivotal.app/llms-full.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.pivotal.app/_mcp/server.

# Test mode

A test key (`pivotal_test_…`) hits the same endpoints, against the same database, as a live key. The difference: **outbound integration side effects are suppressed**. Slack DMs don't go out. Resend emails don't send. Stripe webhook acks don't fire. The Pivotal app records the action and the audit log; no human gets paged.

This makes test keys useful for:

* **Local development** — run your integration against your real workspace without spamming the team Slack.
* **CI smoke tests** — verify the integration end-to-end on every push without polluting customer-facing channels.
* **Migration dry runs** — script a backfill in test mode, eyeball the result inside Pivotal, then re-run with a live key.

## What test mode does NOT do

* **It does NOT create a sandbox copy of your workspace.** Records created by a test key sit in your live database alongside everything else. Deleting them means calling `DELETE` (soft delete) or filtering them out by setting `metadata.test: true` on creation.
* **It does NOT exempt you from rate limits.** Test keys have a *separate* bucket (30/min by default), but they're still rate-limited.
* **It does NOT bypass validation.** Bad payloads still get 4xx.
* **It does NOT prevent UI changes.** Customers, contacts, and onboardings created by a test key show up in the regular UI.

If you need a fully isolated environment, create a second workspace (the Pivotal app supports multiple orgs per Clerk user) and create live keys against that.

## Spotting test-mode behavior

The `/me` endpoint reports the mode:

```json
{
  "object": "api_key_identity",
  "key_name": "ci-smoke",
  "key_prefix": "pivotal_test_def4",
  "org_id": "org_2pXh…",
  "org_slug": "vml",
  "mode": "test"
}
```

The audit log at [Admin > Logs](https://my.pivotal.app/admin/logs) tags each request with the mode. Filter by `mode=test` to see only test-key activity. The activity feed on a customer page surfaces the same thing.

## A pattern for CI smoke tests

In CI, set up a test key once and store it as a repo secret. The smoke test:

1. Creates a throwaway customer with `metadata.ci_run_id = <commit_sha>`.
2. Attaches a contact.
3. Opens an onboarding, advances it through one phase change.
4. Soft-deletes everything it created.

```typescript title=".github/scripts/smoke.ts"
const tag = process.env.GITHUB_SHA?.slice(0, 7) ?? `local-${Date.now()}`;
const slug = `ci-${tag}`;

const customer = await create("/customers", {
  name: `CI ${tag}`,
  slug,
  status: "onboarding",
  metadata: { ci_run_id: tag, test: true },
});

const contact = await create(`/customers/${customer.display_id}/contacts`, {
  name: "CI Bot",
  email: `ci+${tag}@example.com`,
  is_primary: true,
});

const onb = await create("/onboardings", {
  customer_id: customer.display_id.toString(),
  phase: "before_getting_started",
  state: "active",
});

await patch(`/onboardings/${onb.display_id}`, { phase: "program_design" });

// teardown
await del(`/onboardings/${onb.display_id}`);
await del(`/contacts/${contact.display_id}`);
await del(`/customers/${customer.display_id}`);
```

The teardown step is what keeps your workspace tidy. Skip it and you accumulate one stale customer per CI run.

## Tagging records

We strongly suggest tagging every test-mode record with `metadata.test: true`. Reasons:

* Filtering the customer list in the UI is straightforward (admins can collapse `test=true` rows).
* A separate "cleanup all test-mode records" admin action can be written against the API in a single pass.
* It makes the difference visible to humans who didn't write the integration.

Pivotal doesn't enforce this — it's a convention.

## What if I want a fully separate workspace?

Two options:

* **Personal sandbox workspace.** Create a second Clerk org from inside the app. Create live keys against it. Your real workspace's data is untouched.
* **Whitelabel sandbox.** Pivotal can spin up a dedicated demo workspace for partners and integrators. Email [help@pivotal.app](mailto:help@pivotal.app) — useful when you're building an integration to distribute and want a clean staging env.

## Promoting test code to live

When the test-mode integration is working, the **only** change to flip to live is the API key. Same endpoints, same payloads, same response shapes. Many teams keep both keys configured and toggle based on an env var:

```typescript
const KEY = process.env.NODE_ENV === "production"
  ? process.env.PIVOTAL_API_KEY!
  : process.env.PIVOTAL_API_KEY_TEST!;
```

Once you flip live, monitor `/me` on startup to confirm the mode — easy way to catch a misconfigured env.