# Test mode & sandbox

> Simulate payments, billing, and engagement flows with no real money.

Every VINR account ships with an isolated sandbox: test keys, simulated payment rails, and deterministic test data across Payments, Billing, and Engagement. Nothing in the sandbox touches real money, real cards, or live customers — so you can build and break things freely before going live.

## Sandbox vs. live

The sandbox is a complete, parallel copy of the VINR platform. It runs the same API, the same SDK, and the same webhook delivery — only the underlying rails are simulated. The two environments are fully separated by the key you authenticate with.

| Aspect                | Sandbox                        | Live                        |
| --------------------- | ------------------------------ | --------------------------- |
| Base URL              | `https://sandbox.api.vinr.com` | `https://api.vinr.com`      |
| Key prefix            | `sk_test_…` / `pk_test_…`      | `sk_live_…` / `pk_live_…`   |
| Card rails            | Simulated (test cards only)    | Real card networks          |
| Payouts & settlements | Generated, not transferred     | Transferred to your bank    |
| Data                  | Resettable, isolated           | Permanent                   |
| Webhooks              | Delivered to test endpoints    | Delivered to live endpoints |

> Objects never cross the boundary. A `cust_…` created in the sandbox does not exist in live, and a test key cannot read or mutate live data. Migrate by re-creating products, prices, and programs in live — there is no copy step.

## Test API keys

Find your sandbox keys in the [VINR Dashboard](https://dashboard.vinr.com) under **Settings → API Keys**, toggled to **Test mode**. They are prefixed `sk_test_` and `pk_test_` so they are easy to spot in logs and config.

##### SDK

```ts
import { Vinr } from '@vinr/sdk';

// Point the SDK at the sandbox by using a test secret key.
const vinr = new Vinr({
  secretKey: process.env.VINR_SECRET_KEY, // sk_test_… in your test env
});
```

##### REST

```bash
curl https://sandbox.api.vinr.com/v1/payments \
  -H "X-Api-Key: sk_test_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 1000, "currency": "EUR", "description": "Sandbox test" }'
```

The SDK selects the environment from the key prefix automatically — you do not set a separate `baseUrl`. Keep test and live keys in separate environment files so a test key never ships to production.

## Simulating payments

Create a payment exactly as you would in live, then complete it with a sandbox test card. The card number you choose deterministically controls the outcome.

```ts
const payment = await vinr.payments.create({
  amount: 2500, // €25.00
  currency: 'EUR',
  description: 'Sandbox order #4242',
  returnUrl: 'https://yoursite.com/payment/complete',
});

// Open payment.checkoutUrl and pay with a test card below.
console.log(payment.id, payment.checkoutUrl);
```

| Card number           | Outcome                                  |
| --------------------- | ---------------------------------------- |
| `4242 4242 4242 4242` | Successful payment (`payment.completed`) |
| `4000 0000 0000 0002` | Declined (`payment.failed`)              |
| `4000 0000 0000 3220` | Triggers 3D Secure authentication        |

Use any future expiry date, any 3-digit CVC, and any postal code. To simulate a refund, call `vinr.refunds.create({ payment: pay_… })` — the refund settles instantly in the sandbox instead of taking the usual rail timing.

## Simulating billing cycles

Subscriptions in the sandbox would normally wait days or months to renew. Instead, advance a subscription's clock to generate the next invoice on demand — no waiting for real time to pass.

```ts
const sub = await vinr.subscriptions.create({
  customer: 'cust_test_8Hx2',
  price: 'price_monthly_pro',
});

// Jump the billing clock forward to the next renewal.
const result = await vinr.testClock.advance({
  subscription: sub.id,
  to: 'next_period', // or an ISO timestamp
});

console.log(result.invoice); // inv_… generated for the new period
```

> Advancing the clock fires the same events live billing would: `invoice.created`, `invoice.paid` (or `invoice.payment_failed`), and `subscription.updated`. Use this to test dunning, proration, and trial-end behavior in seconds.

## Triggering webhook events

You can drive webhook flows two ways: organically, by performing the action (paying, advancing a clock), or directly, by asking VINR to emit a specific event to your endpoint.

```bash
# Emit a specific event to all registered sandbox endpoints.
curl https://sandbox.api.vinr.com/v1/test/events \
  -H "X-Api-Key: sk_test_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "type": "loyalty.points.earned", "object": "loy_test_default" }'
```

Verify the delivery in your handler exactly as in production — the test signature is real and signed with your test secret:

```ts
export async function POST(req: Request) {
  const payload = await req.text();
  const signature = req.headers.get('x-vinr-signature');

  const event = vinr.webhooks.verify(payload, signature);
  console.log('Received', event.type);

  return new Response('OK', { status: 200 });
}
```

For local development, the VINR CLI forwards sandbox events to `localhost` so you do not need a public URL. See [Webhooks](/docs/integration/webhooks) for the listen-and-forward setup.

## Test data reference

The sandbox seeds deterministic fixtures so examples and CI runs are reproducible. These IDs always resolve in test mode:

To wipe everything you created and return to the seeded baseline, reset the sandbox from **Settings → Test mode → Reset data**, or call `vinr.testClock.reset()` to clear simulated clocks only. Resets are irreversible but only affect test data.

> Never send real cardholder data to the sandbox. Simulated rails do not authorize real cards, and submitting live PAN to a test endpoint is a compliance violation. Use the test cards above.

## Next steps

[Quick Start](/docs/getting-started/quick-start) — Make your first sandbox payment in 5 minutes.

[Webhooks](/docs/integration/webhooks) — Forward sandbox events to localhost and verify signatures.

[Going live](/docs/operations) — Swap test keys for live keys and ship to production.
