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

# Testing

> Test an integration safely, without billing a real customer

There is no sandbox yet. Every API key works against a real organisation, and a subscription you create raises a real invoice in that organisation's Xero.

The supported way to test is a second Saasybill organisation connected to a Xero Demo Company. It works today and bills nobody.

<Warning>
  Never test with your production key. A test subscription creates a real invoice for a real customer.
</Warning>

***

## Set up a test organisation

<Steps>
  <Step title="Create a second organisation">
    Create a new organisation in Saasybill, separate from your live one. It gets its own customers, plans and keys.
  </Step>

  <Step title="Connect it to a Xero Demo Company">
    Connect the new organisation to a Xero Demo Company and not to your real Xero organisation. Follow the same steps as in the [Quickstart](/quickstart).
  </Step>

  <Step title="Add a plan and a customer">
    Create a plan, and import or create a customer, so your requests have something to bill.
  </Step>

  <Step title="Create a key in the test organisation">
    Open **Developer Settings** in the test organisation and create an API key. Use that key in your test environment.
  </Step>
</Steps>

Keep the test key and the live key in separate environment variables, so a deployment can't mix them up.

***

## Setup Mode

While an organisation is in [Setup Mode](/settings/account), the API still creates subscriptions but doesn't raise invoices in Xero.

* `POST /v1/subscriptions` returns `invoice: null`.
* `POST /v1/subscriptions/{id}/units` is refused with `422 setup_mode_on`.
* `start_date` can't be in the future. It is the previous renewal date of a subscription that is already running.

Check `setup_mode` on [the organisation](/api-reference/organisation/retrieve-the-organisation). It lets your integration tell the difference between a live organisation and one that is still mirroring existing billing.

***

## Test checklist

<Check>Create a subscription, then send the same request again with the same `Idempotency-Key`. You get the same response and `Idempotent-Replayed: true`.</Check>

<Check>Send an unknown field. You get `422` and `param` names it.</Check>

<Check>Use a key without a scope and call an endpoint that needs it. You get `403 insufficient_scope`.</Check>

<Check>Increase units with proration, then decrease them. Confirm each `change` object matches what you expected.</Check>

<Check>Register a webhook endpoint, use <Badge>Send Test Event</Badge>, and confirm your signature check passes.</Check>

<Check>Let your webhook handler fail once. Confirm it copes with the retry, and with the same event arriving twice.</Check>
