# Test & live modes

TicketConnect gives you two fully separate environments, selected entirely by
**which key you use**. There is no separate sandbox URL and no flag to flip — the
key's prefix decides the mode.

| Mode | Key prefix | What it is |
| --- | --- | --- |
| **Test** | `sk_test_…` | A sandbox that mirrors production behaviour with completely isolated data and simulated payments. |
| **Live** | `sk_live_…` | Production. Real events, real customers, real card charges, real payouts. |

> **Note:** Live mode must be activated on your account before it can be used. Until it
> is, `sk_live_` keys cannot be created, and any live key presented to the API is
> rejected with a `403` — never silently downgraded to test. Test mode is always
> available.

```text
https://api.ticketconnect.example/v1
```

The base URL is the same for both. Send a test key and you're in the sandbox;
send a live key and you're in production.

## Same code paths, isolated data

A test key exercises **the same endpoints and the same logic** as a live key — so
if your integration works in test, it works in production. The difference is
isolation:

* Test events, tiers, customers, tickets, payments, and payouts live in a
  **separate sandbox** and never appear in your live data (and vice versa).
* Payments in test mode are **simulated** — use the standard test card numbers to
  trigger success or failure. No real money ever moves.
* Webhooks, reports, balances, and scanning all work the same way in test, scoped
  to your test data only.

> **Warning:** The two worlds never cross. A `sk_test_` key cannot read or modify live data, and
> a `sk_live_` key cannot see anything you created in test. An id created in one
> mode is meaningless in the other.


## Telling which mode a key is in

There are two reliable ways:

1. **The prefix.** `sk_test_…` is test; `sk_live_…` is live.
2. **Ask the API.** `GET /v1/account` returns a `mode` field:

**cURL**

```bash
curl https://api.ticketconnect.example/v1/account \
  -H "Authorization: Bearer sk_test_your_key_here"
```

**Node (fetch)**

```javascript
const res = await fetch("https://api.ticketconnect.example/v1/account", {
  headers: { Authorization: "Bearer sk_test_your_key_here" },
});
const { mode } = await res.json();
console.log(mode); // "test"
```

```json
{
  "id": "ten_8a1f...",
  "name": "Acme Tickets",
  "mode": "test",
  "status": "active",
  "currency": "USD"
}
```

## Best practices

* **Build in test first.** Wire up your entire flow — create an event, take a
  payment, issue a ticket, scan it — using a `sk_test_` key before you touch live.
  Run the [Quickstart](#quickstart) end-to-end in test.
* **Key your config by mode.** Store `sk_test_` and `sk_live_` keys in separate
  environment variables and select the right one per deployment. Never hardcode a
  key or let a live key leak into a staging build.
* **Test the unhappy paths too.** Use test cards to simulate declined payments,
  and exercise refunds, already-used scans, and missing-scope errors so your error
  handling is solid before launch.
* **Verify webhooks in test.** Register a test webhook endpoint and confirm you
  receive and verify signed events before relying on them in production. See the
  [Webhooks guide](#webhooks).
* **Flip to live by swapping the key.** When you're confident, change the key
  from `sk_test_` to `sk_live_` — no code changes required. Double-check
  `GET /v1/account` reports `"mode": "live"` before going live for real.

> **Tip:** Because test and live share the same code and contract, "it works in test" is a
> real guarantee about the API surface. The only things you can't fully exercise in
> the sandbox are real-money settlement and bank payouts — validate those carefully
> on your first live transactions.


## Next steps

* [Quickstart](#quickstart) — run the full flow in test mode.
* [Authentication](#authentication) — key formats, the `Bearer` transport, and scopes.
* [API reference](#api-overview) — every endpoint in detail.
