For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
DashboardGet an API key
Get StartedGuidesAPI ReferenceSDKsChangelog
Get StartedGuidesAPI ReferenceSDKsChangelog
  • Common workflows
    • Create your first customer
    • Onboarding phases
    • Integration sync
    • display_id vs id
    • Bulk operations
    • Test mode
LogoLogo
DashboardGet an API key
On this page
  • What test mode does NOT do
  • Spotting test-mode behavior
  • A pattern for CI smoke tests
  • Tagging records
  • What if I want a fully separate workspace?
  • Promoting test code to live
Common workflows

Test mode

Live API surface. No outbound side effects.
|View as Markdown|Open in Claude|
Was this page helpful?
Previous

Bulk operations

Built with

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:

1{
2 "object": "api_key_identity",
3 "key_name": "ci-smoke",
4 "key_prefix": "pivotal_test_def4",
5 "org_id": "org_2pXh…",
6 "org_slug": "vml",
7 "mode": "test"
8}

The audit log at 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.
.github/scripts/smoke.ts
1const tag = process.env.GITHUB_SHA?.slice(0, 7) ?? `local-${Date.now()}`;
2const slug = `ci-${tag}`;
3
4const customer = await create("/customers", {
5 name: `CI ${tag}`,
6 slug,
7 status: "onboarding",
8 metadata: { ci_run_id: tag, test: true },
9});
10
11const contact = await create(`/customers/${customer.display_id}/contacts`, {
12 name: "CI Bot",
13 email: `ci+${tag}@example.com`,
14 is_primary: true,
15});
16
17const onb = await create("/onboardings", {
18 customer_id: customer.display_id.toString(),
19 phase: "before_getting_started",
20 state: "active",
21});
22
23await patch(`/onboardings/${onb.display_id}`, { phase: "program_design" });
24
25// teardown
26await del(`/onboardings/${onb.display_id}`);
27await del(`/contacts/${contact.display_id}`);
28await 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 — 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:

1const KEY = process.env.NODE_ENV === "production"
2 ? process.env.PIVOTAL_API_KEY!
3 : 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.