> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getpalm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Test mode

> Build and validate your entire integration in an isolated sandbox — no cost, no real filings, and the same responses and webhooks you get in production.

export const iconProps = (variant = "default") => {
  const iconVariants = {
    default: "palm-icon-default",
    horizontal: "palm-icon-horizontal",
    stack: "palm-icon-stack",
    navigation: "palm-icon-navigation",
    darkHorizontal: "palm-icon-dark-horizontal",
    dark_stack: "palm-icon-dark-stack",
    getStarted: "palm-icon-get-started"
  };
  return iconVariants[variant] ?? iconVariants.default;
};

export const PalmCard = ({title, description, icon, variant = "default", href, items}) => {
  if (variant === "getStarted") {
    return <div data-card className="pc-wrapper-get-started flex flex-col gap-4 border border-[rgba(4,44,47,0.1)] rounded-2xl p-6">
        <div className="pc-wrapper-inner-get-started">
          {icon !== undefined && <div className="pc-icon-container-get-started">{icon}</div>}
          {title !== undefined && <span className="pc-title-get-started">{title}</span>}
        </div>
        {items && items.length > 0 && <ul className="pc-items-get-started">
            {items.map((item, i) => <li key={i}>
                <a href={item.href} className="pc-item-link-get-started">{item.label}</a>
              </li>)}
          </ul>}
      </div>;
  }
  const variants = {
    default: {
      wrapper: "pc-wrapper-default",
      title: "pc-title",
      description: "pc-description"
    },
    horizontal: {
      wrapper: "pc-wrapper-card",
      title: "pc-title-horizontal",
      description: "pc-description"
    },
    stack: {
      wrapper: "pc-wrapper-stack",
      title: "pc-title-stack",
      description: "pc-description"
    },
    darkHorizontal: {
      wrapper: "pc-wrapper-dark-horizontal",
      title: "pc-title-dark-horizontal",
      description: "pc-description-dark-horizontal"
    },
    navigation: {
      wrapper: "pc-wrapper-navigation",
      title: "pc-title-navigation",
      description: "pc-description-navigation"
    },
    dark_stack: {
      icon: "pc-icon-card",
      title: "pc-title",
      description: "pc-description"
    }
  };
  const styles = variants[variant] ?? variants.default;
  const inner = <a data-card href={href ? href : '#'} className={`no-underline flex flex-col h-full items-start gap-4 p-6 rounded-2xl hover:opacity-80 transition-opacity ${styles.wrapper}`}>
      {icon !== undefined && <span className="icon-wrapper">{icon}</span>}
      {(title !== undefined || description !== undefined) && <div className="flex flex-col min-w-0">
          {title !== undefined && <span className={styles.title}>{title}</span>}
          {description !== undefined && <span className={styles.description}>{description}</span>}
        </div>}
    </a>;
  return inner;
};

Test mode is a full sandbox. Anything you create with a test API key — businesses, verifications, filings, documents, and webhooks — lives in an isolated test environment that mirrors production behavior, never incurs cost, and never creates real filings or operations. You can build and verify an entire integration end to end on a test key before you ever go live.

***

## How mode is set

Every request runs in exactly one mode, determined by the API key you authenticate with:

| Prefix                                                    | Mode              | Billing      |
| --------------------------------------------------------- | ----------------- | ------------ |
| <span className="initial-bold--success">`sk_test_`</span> | Test (sandbox)    | Never billed |
| <span className="initial-bold--success">`sk_live_`</span> | Live (production) | Billed       |

Create both key types in [Palm Console](https://platform.getpalm.com), and use the Console **test/live toggle** to view the matching data. There is nothing to configure beyond the key — swap the key and the same endpoints operate against the other mode.

## What test mode guarantees

* **Isolation.** Test data and live data are separate. Test records never appear in live API results or the live Console view, and live records never appear in test.
* **No cost.** Test requests are never metered or billed.
* **No real filings or operations.** Test-key filings are simulated: nothing is submitted to any state, no EIN application is actually filed, and no real operations work or monitoring is created.
* **Production-shaped responses.** Test responses use the same schema, the same IDs, and the same webhook payloads as live, so what you build against test works unchanged in live.

## Onboard

[Registry search](/onboard/registry-search) is available in test mode, so you can build and validate your search-driven onboarding flow before going live.

## Verify

Verifications in test mode use the same request and response shapes as live.

### Person verification

Person (KYC) verifications in test mode are deterministic, so you can build against a known outcome. Use a **reserved test SSN** to force a specific risk level; any other SSN returns a clean low-risk pass.

| Test SSN                                                     | Risk level | Notes                                              |
| ------------------------------------------------------------ | ---------- | -------------------------------------------------- |
| <span className="initial-bold--success">`111-11-1100`</span> | `low`      | Clean pass, all fields match.                      |
| <span className="initial-bold--success">`111-11-1300`</span> | `medium`   |                                                    |
| <span className="initial-bold--success">`111-11-1500`</span> | `high`     |                                                    |
| <span className="initial-bold--success">`111-11-1700`</span> | `critical` | Synthetic-identity indicators; SSN does not match. |
| Any other SSN                                                | `low`      | Default clean pass.                                |

The verification payload (risk, match results, synthetic, watchlist) is populated to match the outcome, so a `critical` result carries realistic `reasons` and match failures you can render and route on.

### Business verification

Business verification is available in test mode, so you can build and validate your business onboarding flow before going live. Each associate (beneficial owner) is verified as a person, so you can steer an associate's result with the reserved test SSNs above.

### Selecting an outcome directly

For both business and person verification you can also set the reserved `_simulate` key in the request `metadata` to force a specific result — a risk level (`low`, `medium`, `high`, `critical`), a named scenario (such as `no_match`), or `fail` for a system error. It takes precedence over the reserved test SSNs and is ignored in live mode. See the request reference for each endpoint's full list of values.

<Note>
  Without `_simulate`, business verification in test mode always returns a deterministic clean pass — it never queries live registry or IRS data.
</Note>

## Monitor: enrollment only

Enrolling a test business in [Monitor](/monitor/overview) works like it does in live — the monitoring subscription is created, so you can build and verify the enrollment flow. It is only a simulation, though: Palm does not watch any authoritative record for a test business, so no real monitoring is taking place and monitoring events (`business.registration.updated`, `business.filing.due`, `business.filing.overdue`) do not fire from real-world changes.

## Comply: filings auto-advance

In live mode, a filing progresses as Palm's operations team and the state process it. In test mode there is no one in the loop — a filing you create on a test key **advances through its lifecycle automatically**, firing the same `filing.*` webhooks at each transition, so you can watch `queued → ready_to_file → processing → filed → completed` play out in a few seconds and exercise your webhook handling.

Bundled filings behave like production: an EIN created under a formation stays `queued` until its parent formation reaches `completed`, then advances on its own. Registered-agent provisioning on a test formation activates automatically and fires `registered_agent.activated`.

### Simulating outcomes

By default a test filing runs the happy path to `completed`. Set the reserved `_simulate` key in the filing's `metadata` on the create request to drive a specific outcome. The value is `<terminal>[:case_<status>][:auto]`.

**Terminal outcome**

| `metadata._simulate`                                       | Result                                            |
| ---------------------------------------------------------- | ------------------------------------------------- |
| <span className="initial-bold--success">`completed`</span> | Default. Filing runs through to `completed`.      |
| <span className="initial-bold--success">`canceled`</span>  | Filing ends `canceled` — fires `filing.canceled`. |

**Simulating an information request**

Append `:case_<status>` to open a [case](/comply/cases) when the filing reaches that status — mirroring Palm needing more information from you before the filing can continue. `<status>` is any non-terminal filing status you receive: `case_queued`, `case_ready_to_file`, `case_processing`, or `case_filed`. The filing holds at that status and fires `case.opened`, then resumes to its terminal once you resolve the case by responding at `POST /v1/case/{case_id}/response`. Append `:auto` to have the case resolve itself after a short delay instead of waiting for your response.

| `metadata._simulate`                                                       | Result                                                                  |
| -------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| <span className="initial-bold--success">`completed:case_processing`</span> | Opens a case at `processing`; resumes to `completed` after you respond. |
| <span className="initial-bold--success">`canceled:case_filed:auto`</span>  | Opens a case at `filed`, auto-resolves, then ends `canceled`.           |

```json wrap JSON theme={null}
{
  "name": "Acme Holdings LLC",
  "jurisdiction": "US-NC",
  "metadata": {
    "_simulate": "completed:case_processing"
  }
}
```

<Note>
  `_simulate` is a test-only control; it is ignored in live mode. On a bundled formation + EIN it applies to the formation — to drive an EIN to its own outcome, submit a standalone EIN filing with its own `_simulate`.
</Note>

## Webhooks in test mode

Webhook endpoints are registered per mode: an endpoint you create with a test key (or while the Console is in test) is a **test endpoint**; one created in live is a **live endpoint**. Events are delivered only to endpoints of the same mode, so test traffic reaches your test endpoint and never your production one. Point them at different URLs to keep sandbox and production deliveries apart. Every event also carries a top-level `mode` field (`test` for sandbox events) so your handler can assert it.

See [Webhooks](/developer-guide/webhooks) for setup, signature verification, and retries.

## Going live

When your integration works end to end in test, moving to production is a key swap:

1. Replace your `sk_test_` key with an `sk_live_` key from Console.
2. Register your **live** webhook endpoints (test endpoints do not receive live events).
3. Expect real timelines and costs — live filings are processed by Palm operations and the state, not the simulator, so they progress on real-world schedules and are billed.

## Next steps

<div className="grid lg:grid-cols-2 gap-6 mt-6">
  <PalmCard variant="navigation" title="Authentication" description="API keys, the Authorization header, and key security." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/get-started/authentication" />

  <PalmCard variant="navigation" title="Webhooks" description="Register endpoints, verify signatures, and handle retries." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/developer-guide/webhooks" />

  <PalmCard variant="navigation" title="Form a business" description="Create a formation and watch it progress in test." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/comply/form-a-business" />

  <PalmCard variant="navigation" title="Verify a person" description="Run KYC with deterministic test outcomes." icon={<Icon className={iconProps("navigation")} icon="arrow-right" />} href="/verify/verify-a-person" />
</div>
