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

# Go to production

> Move from your sandbox app to real customers: what changes, a launch checklist, and how billing works.

You've built against your sandbox app. Launching means pointing your production environment at your
**production app**, where your customers' connections live, and making sure your integration handles the
things real company files do.

```mermaid theme={null}
flowchart LR
  dev["<b>Sandbox app</b> · free<br/>simulated connections<br/>your test QuickBooks"] -- "same code, new key;<br/>promote workflows" --> live["<b>Production app</b><br/>your customers'<br/>company files"]
```

Your code doesn't change between the two. The API key, the webhook secret and the connection ids do.

## Launch checklist

**1. Configure production credentials**

Put the production app's API key and webhook secret into your production environment: an owner
generates a key on the production app's page and copies it when it's shown, the only time it is. Your sandbox
key can't reach production connections, and the other way round, so a mix-up fails with an error.

**2. Set up billing**

In the dashboard, a production app without a subscription shows **Set up billing to turn this app on**, and no
getting-started steps or **New connection** button until it has one. Add a
payment method before your first customer connects: until your organization has billing, its
production app can't have connections of any type, `simulated` included. Creating one, from the API,
the CLI or the dashboard, is refused with `402` and the code `billing_required`, and nothing is
saved. Your sandbox app needs no billing.

**3. Promote your workflows**

Production connections only run **published** workflow versions. Publish in your sandbox app, then
[promote](https://docs.qubesync.com/workflow-authoring.md#from-sandbox-to-production) to production, and fix any company-file
values the promotion warns about. Promotion publishes the version in production too: **Publish there as
well** is ticked in the **Promote to another app** window. Untick it to land the chart as that app's
working copy for a final look, then publish it there when you're happy.

Workflows run only on `realtime` connections in production, so make sure your app creates its
customers' connections with `"type": "realtime"` ([why](https://docs.qubesync.com/workflows.md#workflows-run-on-realtime-connections)).

**4. Harden your webhook endpoint**

[Verify every signature](https://docs.qubesync.com/webhooks.md#securing-your-endpoints), answer `2xx` within 5 seconds and do the work in
a job, and process each `page_request_id` and `state` once. A `retryable` webhook is followed by the answer
with the same `page_request_id`. Deliveries can repeat or arrive out of order.

**5. Handle every state**

Show your customer `error.user_message` for `error` and `retryable`. Don't resend a `retryable`
request. Decide what a `timed_out` create means for you. [Error handling](https://docs.qubesync.com/error_handling.md) has the full
list.

**6. Finish your onboarding flow**

Set each connection's `webhook_url`, and handle its events: `connection.connected` marks the account
connected, `connection.setup_cancelled` offers the button again, and `connection.stalled` and
`connection.resumed` tell your customer when their Web Connector has stopped and started again.
[Connect your customers](https://docs.qubesync.com/onboarding.md).

**7. Audit your code**

Have your coding agent check your integration against every rule on the
[integration checklist](https://docs.qubesync.com/integration-checklist.md), with the audit skill, and fix what it finds.

**8. Test against real QuickBooks**

Run your whole flow against a [not-for-resale copy of QuickBooks](https://docs.qubesync.com/nfr-quickbooks.md) on a real Web
Connector, with a sample company file.

## How billing works

| You use | You pay |
| - | - |
| Sandbox apps and simulated connections | Nothing, however much you use them |
| A `standard` production connection (Web Connector every 5 minutes) | Per active connection per month |
| A `realtime` production connection (Web Connector every 10 seconds) | Per active connection per month, at a higher rate than standard, with [workflows](https://docs.qubesync.com/workflows.md) and [name matching](https://docs.qubesync.com/matching.md) included: neither runs on a standard connection |
| Requests and webhooks | Nothing: there's no charge per request or per webhook |

A connection is active when its Web Connector has checked in during the past week. A customer who
disconnects stops counting.

See [pricing](https://qubesync.com/#pricing) for current rates. High volume or special requirements?
[Talk to us](https://qubesync.com/contact_us).

## Operating it

> [card] Watch connections, not just requests
>
> A connection whose `last_connected_at` is days old has a Web Connector that stopped, usually because the
> PC is off or QuickBooks moved. Its requests wait until it's back, and its `webhook_url` is sent
> `connection.stalled`, then `connection.resumed` once it's working again
> ([Connection events](https://docs.qubesync.com/webhooks.md#connection-events)).

> [card] Rotate secrets without downtime
>
> Webhook deliveries are signed with every active secret on the app, so you can
> [rotate](https://docs.qubesync.com/webhooks.md#rotate-your-webhook-secret) by adding a new one before expiring the old. API keys work
> the same way: create the new key, deploy it, then expire the old one. Expiring a key takes effect
> immediately. Making, expiring and copying keys and secrets is for your organization's owners.

> [card] Use the dashboard to investigate
>
> Every request shows what was sent, what QuickBooks answered, and each webhook attempt, with a
> **Resend webhook** button. Every workflow run shows its path on the canvas.

> [card] Invite your team
>
> Invite them from your organization's members page. Alerts go to owners, so make sure more than one
> person is an owner.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.