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

# Test mode and live mode

> How Tally partitions test from live, and what 'live' actually means.

Every account-scoped resource in Tally — every wallet, agent, API key, transaction, webhook — carries a **mode**: either `test` or `live`. The two are fully partitioned. A test API key cannot touch a live wallet; a live agent does not appear in a test list; a live payment cannot leave a test wallet. The model is borrowed from Stripe's developer UX, for the same reason: you should be able to ship code against a sandbox and run the same code against production by flipping one variable.

## What differs between modes

| Aspect                | Test mode                    | Live mode                                |
| --------------------- | ---------------------------- | ---------------------------------------- |
| Network               | Base Sepolia                 | Base mainnet                             |
| USDC                  | Testnet USDC (no real value) | Production USDC                          |
| Privy app             | Tally's test Privy app       | Tally's live Privy app (separate config) |
| API key prefix        | `tly_test_…`                 | `tly_live_…`                             |
| Webhook secret prefix | `whsec_test_…`               | `whsec_live_…`                           |
| Cost of mistakes      | Zero                         | Real money                               |

Everything else — the SDK surface, the dashboard UX, the policy model, the webhook events — is identical. The whole point is that your code shouldn't care which mode it's running in. If it works in test, it works in live.

## How partitioning works

Every account has both a test side and a live side. They share:

* The same dashboard URL (resources are filtered by the mode badge in the sidebar)
* The same team members and roles
* The same billing account

They do **not** share:

* Wallets — a test wallet's address is different from any live wallet
* Agents — registering `research-bot` in test mode doesn't create a live `research-bot`
* API keys — keys are stamped with mode at creation; you can't change a key's mode
* Transactions, webhooks, audit log entries — every row carries its mode and queries only see its own side

Mixing modes in code is impossible without explicit intent: the SDK rejects API keys without the `tly_test_` or `tly_live_` prefix before sending a request, and the server rejects any attempt to act on a mismatched-mode resource with a `forbidden` error.

## Working in test mode

Test mode is the default for every new account, and the only mode that's fully wired up today (see "Live mode availability" below).

A few things to lean on while you're developing:

* **Get test USDC from a Base Sepolia faucet.** [Circle's faucet](https://faucet.circle.com) drops test USDC into any Base Sepolia address. Use it to fund agent wallets without spending real money.
* **Use the dashboard's mode badge.** The sidebar shows which mode you're viewing. It's the fastest way to confirm you're not about to grant a permission on the wrong network.
* **Webhooks fire in test mode.** All the events listed in [Webhooks](/webhooks) fire on Base Sepolia activity — useful for integration testing.

## Switching between modes

In code, switching modes is one variable:

```ts theme={null}
const tally = new Tally({
  apiKey: process.env.TALLY_API_KEY!, // tly_test_… in staging, tly_live_… in prod
});
```

In the dashboard, the mode selector lives in the sidebar; toggling it filters every list to the chosen mode.

## Live mode availability

Live mode is **partially built**. The schema, key prefix, resource partitioning, and Privy configuration scaffolding are all in place — but the customer-facing flow to opt an account into live mode isn't wired up yet. Today, `getDashboardMode()` returns `"test"` for every session, and no `tly_live_` keys are issued.

The plan: live mode lights up after testnet hardening is done — production Privy app, mainnet RPC, KMS, observability, a one-time per-account opt-in ("I want to handle real USDC") with the appropriate confirmations. Code paths are already mode-aware so the cutover is configuration, not refactoring.

If you have a use case that needs live-mode access soon, reach out.

## Best practices

* **Treat test and live as separate environments**, with separate API keys, separate webhook endpoints, and separate secret stores. Don't share `TALLY_API_KEY` across staging and production.
* **Validate the prefix at boot.** A tiny startup check that `process.env.TALLY_API_KEY!.startsWith("tly_test_")` (or `tly_live_`) for the environment catches misconfigured deploys before the first request.
* **Never run automated tests against live mode.** The two-prefix split is precisely so you don't accidentally fire integration tests at real USDC. Pin tests to `tly_test_` keys.
* **Use deterministic agent IDs across modes.** The same `id` can exist in test and live independently; if you make them match (`research-bot` in both), you can reuse code paths without conditional logic.
