Skip to main content
A sandbox is a separate copy of your organisation for testing an integration. It has its own test API keys and webhook endpoints, and it invoices a Xero Demo Company instead of your real Xero organisation. A sandbox sends no emails, is never billed, and doesn’t count toward your plan’s limits.
Never test with a live key. A subscription created with a live key raises a real invoice for a real customer. Use a saasybill_test_ key from a sandbox.

How a sandbox differs from a live organisation

Each live organisation can have one sandbox. Only an owner or admin of the live organisation can open it.

Set up a sandbox

1

Create a Xero Demo Company

In Xero, create a Demo Company, or reset your existing one. Saasybill can’t do this for you. A sandbox accepts only a Demo Company, so it can never write to real books.
2

Create the sandbox

Go to Organisation Settings, then Developer Settings, then Configuration. In the Sandbox section, click Create Sandbox and choose what to copy from your live organisation. See What you can copy.
3

Connect the Demo Company

Saasybill switches you into the sandbox. Go to Integrations and click Connect Demo Company, then complete the Xero sign-in.
4

Copy your accounts

If you copied plans, go to Organisation Settings in the sandbox and click Copy accounts under Account Mappings. Saasybill finds or creates your live revenue accounts in the Demo Company and maps the sandbox’s plans to them.
5

Create a test key

Still in the sandbox, go to Developer Settings, then API Keys, and create a key. Keys created in a sandbox are test keys. Use it in your test environment.
A red bar across every page tells you when you are in the sandbox. Click Back to your organisation’s name in the bar to return to your live organisation.
A sandbox with no Demo Company connected behaves like a live organisation with no Xero connection. Subscriptions work, but invoices fail to reach Xero and show on the Error tab.

What you can copy

When you create or reset a sandbox, choose which data to copy from your live organisation. Ticking an option also ticks the ones it needs.
Copying customers copies their names and email addresses. Leave it off unless you need your real customer codes.

Customers and contacts

Xero is the source of truth for contacts, and a Demo Company has its own.
  • Copied customers get a Demo Company contact the first time they are invoiced. Saasybill reuses a contact that has the customer’s code as its contact number, or creates one. The contact is created with the customer’s name and code, not their email address.
  • Customers created through the API follow the same rules as in a live organisation. An owner or admin must have allowed the API to create Xero contacts. See Customers and Xero.

Advance the test clock

A sandbox’s clock can stand still and move only when you advance it, so you can test a renewal without waiting a month.
1

Open the Test Clock

In the sandbox, go to Developer Settings, then Configuration, and click Advance Clock on the Test Clock row.
2

Choose a date

Pick the date to advance to. The clock moves to midday on that date in the sandbox’s timezone, so every renewal due that day is included. You can advance by up to 366 days at a time.
3

Wait for it to finish

Saasybill steps through each renewal, start and end in order, and pushes the invoices to the Demo Company. Advancing a long way takes longer. You can’t start another advance, or reset the sandbox, until it arrives.
Once the clock is set, everything in the sandbox happens at the clock’s time. That includes subscriptions and unit changes you make through the API and in the app. The scheduled renewal run leaves a sandbox with a clock alone, so it renews only when you advance it. To test usage-based billing, report events with a test key, then advance the clock past the end of the billing period. Saasybill closes the period and raises its usage invoice into the Demo Company, as it does in a live organisation. Reported usage is never copied from your live organisation.
You advance the clock in the app, not through the API. A sandbox that has never been advanced runs on real time.

Reset the sandbox

A reset empties the sandbox and lets you copy fresh data from your live organisation. Go to Developer Settings, then Configuration, in the sandbox, and click Reset Sandbox. A reset also puts the test clock back to real time. To change what the sandbox holds, reset it. Saasybill never merges new copies into existing data.

If your Demo Company is reset

Xero wipes a Demo Company every 28 days, and you can reset it at any time. Saasybill sees this as a new Xero tenant. It doesn’t delete the sandbox. Reset your Demo Company in Xero, then connect it again in the sandbox’s Integrations. Saasybill clears every Xero id it holds, such as contacts, invoices and account mappings, so nothing points into the old Demo Company. Your records stay. Copy your accounts again to re-map the plans.

Test webhooks

Add webhook endpoints inside the sandbox in the same way as in a live organisation. Events from a sandbox have livemode set to false.

Not available in a sandbox

Billing, users and invitations, deleting the organisation, removing the Xero connection, Setup Mode and automated customer emails are not available in a sandbox.

Setup Mode

While a live organisation is in Setup Mode, the API still creates subscriptions but doesn’t raise invoices in Xero. A sandbox is never in Setup Mode.
  • 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 and livemode on the organisation. They let your integration tell a live organisation, one that is still mirroring existing billing, and a sandbox apart.

Test checklist

Call GET /v1/organisation with your test key. livemode is false.
Use a test key against a live organisation, or a live key against the sandbox. You get 403 api_key_mode_mismatch.
Create a subscription, then send the same request again with the same Idempotency-Key. You get the same response and Idempotent-Replayed: true.
Send an unknown field. You get 422 and param names it.
Use a key without a scope and call an endpoint that needs it. You get 403 insufficient_scope.
Increase units with proration, then decrease them. Confirm each change object matches what you expected.
Advance the test clock past a renewal. Confirm your integration sees the renewal invoice and the subscription.updated event.
Register a webhook endpoint, use Send Test Event, and confirm your signature check passes.
Let your webhook handler fail once. Confirm it copes with the retry, and with the same event arriving twice.
Before you go live, swap in your live key and confirm GET /v1/organisation returns livemode: true.