# Promotion (/docs/concepts/promotion)



A **promotion** makes live match test. When your new quiz, reward and leaderboard are ready in test, you prepare a promotion, check the list of what will change, and approve it. Your members then see the new version, all at once.

It covers everything that defines your program: quests from code and from Quest Studio, their settings and archive state, quest types, collections, point ledgers, badges, tiered rewards and their archive state, offers, stock items, pickup policy, leaderboards and their exclusion-group binding, referral programs, trackers, engagement rules, images, dashboards, the project calendar and profile settings. When the project hosts an app, it also carries the version of the app on staging. A promotion always takes everything: you can't pick a subset.

Definitions change only in test, and a person approves every promotion. See [test and live](/docs/concepts/environments).

```mermaid
flowchart LR
    Edit["Change definitions in test"] --> Prepare["Prepare a promotion"]
    Prepare --> Review["Review its changes and warnings"]
    Review --> Approve["Approve in Console"] --> Live["Live matches test"]
    Review --> Reject["Reject with a reason"]
```

## What a promotion holds [#what-a-promotion-holds]

| Part     | What it is                                                                                                                                                                                                       |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Changes  | Each definition live would change: added, changed, archived or unarchived. Definitions that already match are left out.                                                                                          |
| Warnings | What approval leaves as it is: a connection test uses that live hasn't set up, such as Discord or a webhook, and anything live has that test doesn't. A separate list names the groups approval creates in live. |
| Build    | The hosted app version on staging when the promotion was prepared, or none. Approval puts it [live](#the-hosted-app).                                                                                            |
| Source   | Prepared from test, a rollback of an earlier promotion, or prepared by your developer's deploy command.                                                                                                          |
| Status   | Pending until decided, then applied, rejected (with the reason), or replaced by a newer promotion.                                                                                                               |

> [!DEV]
> Changes carry the kind, the authoring key and `added`, `changed`, `archived` or `unarchived`. `binding-missing` names an integration, webhook endpoint, sign-in method or app secret test uses and live has not set up; `live-only` names a definition live has and test does not; `group-created` names a group approval creates in live. Source is `test`; `rollback` and the promotion it repeats; or `deployment` when the deprecated [`domino deploy --promote`](/docs/build/publishing#publish-behavior-to-live) or `management.deployments.promote` prepared it. Status is `pending`, `applied`, `rejected` or `superseded`.

## How resources match [#how-resources-match]

Each resource has an **authoring key** that is the same in test and live: the `key` declared in code, or the ID a resource created in Console was given. A promotion matches resources by that key. Live keeps its own resource IDs, and every reference inside a definition, such as a quest's reward ledger or a leaderboard's balance, points at live's resource.

Nothing is deleted. A definition that test archived is archived in live; one that live has and test does not stays as it is, with a warning. Text of a definition's own, such as a description, is copied as written.

## What never moves [#what-never-moves]

Some settings belong to each environment, and an organization admin sets them up there: connections such as Discord, Telegram and X, webhook endpoints, member sign-in, and hosted-app secrets. A promotion lists the ones live lacks as warnings and approves anyway; until they are set up, live behaves as it would without them. A [custom domain](/docs/concepts/hosting#custom-domains) exists only in live, with nothing in test to compare, so a promotion neither copies it nor warns about it.

Day-to-day state stays in each environment too. Members, points, attempts, stock quantities, pauses and groups are never copied. When a quest, offer, leaderboard or referral program names a group, such as one that rewards [group membership](/docs/concepts/groups#add-members-with-a-quest-reward), and live has no group with that key, approval creates it in live with no members. A group archived in live is never unarchived: if a quest rewards membership in it, or a leaderboard binds it as its exclusion group, approval refuses, naming the quest and the group, until you unarchive the group in live.

## Approval [#approval]

A person signed in to Console with publish permission approves or rejects a pending promotion in **Live → Deployments**, where **Promote to live** opens it after preparing. Approval applies every change at once, so live never shows half a promotion.

If test or live changed after the promotion was prepared, approval refuses and nothing changes in live. Choose **Prepare again** in Console and review the new list. Approval also refuses when the project needs a plan to go live; see [Going live needs a plan](#going-live-needs-a-plan). Preparing a promotion replaces any older pending one, so only the newest can be approved.

> [!DEV]
> Approval applies every change in one transaction. A changed environment refuses with `promotion-changed`, and a project that needs a plan with `plan-required`.

## Going live needs a plan [#going-live-needs-a-plan]

Building and testing are free. Serving members in live needs a plan for the project. Where plans apply to your organization, this is how approval and live behave:

| When                                                                            | What happens                                                                                                                                                                                                                 |
| ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| The project has a paid plan                                                     | Approval works as described above.                                                                                                                                                                                           |
| The project has no plan, and the organization hasn't used its live trial        | Approval starts the trial for this project: 14 days on Launch, no card needed. Console says so beside the promotion before you approve. Preparing a promotion doesn't start it.                                              |
| The project has no plan, and the trial is running on another project or used up | Approval is refused and live doesn't change. Console says where the trial is and shows the plans beside the promotion: an organization administrator who can buy plans subscribes there through Stripe, then approves again. |
| The trial ended without a plan                                                  | Live keeps serving for a 7-day grace period. Approving another promotion needs a plan.                                                                                                                                       |
| The grace period ended                                                          | Live goes offline: the app shows "This app is offline" on its `domino.page` address and custom domain, and members can't use it.                                                                                             |
| A paid plan's subscription ends                                                 | Live goes offline when the paid period ends.                                                                                                                                                                                 |
| A payment for one of the organization's plans has been overdue 14 days          | Approving any of the organization's promotions is refused until it is paid. Live keeps serving.                                                                                                                              |
| The payment is 38 days overdue                                                  | Live keeps serving, and you get a notice that it goes offline a week later.                                                                                                                                                  |
| The payment is 45 days overdue                                                  | That project's live goes offline until it is paid.                                                                                                                                                                           |
| The project gets a plan, or the payment is made                                 | Live serves again within about a minute, with the same build and no redeploy.                                                                                                                                                |

Each organization gets one live trial. It stays used after its project is moved or deleted. Going offline keeps everything: definitions, members, points and history stay, and test is never affected. Projects that served live before plans were introduced keep serving on a plan Domino assigned. Domino support sets a project's plan.

To see where a project stands, open **Settings → Plan & usage**. Everyone who can open the project sees its plan, the trial, this month's [active members](/docs/concepts/participants#active-members) against the plan's limit, and the AI builder's balance. Organization administrators who can buy plans also subscribe, change or cancel the plan, buy AI credit and open **Manage billing** there.

To see every project at once, open **Billing** under **Organization** in the sidebar, or from **Manage** in the organization menu. Everyone in the organization sees the plan, status and renewal date of each project they can open, with a link to its Plan & usage page, how many of the organization's 10 Free projects are used, what's left of the free AI allowance, and where the trial stands. An organization administrator who can buy plans opens **Invoices and payment method** there for every invoice, the card and the billing details.

> [!DEV]
> The `plan-required` refusal's `trial` field says where the trial is; with an overdue payment it carries `reason: "unpaid"` and `unpaidSince` instead. While live is offline, member requests to live are refused with `live-offline`. `management.usage.plan()` or `domino usage plan` (`GET /management/v1/usage/plan`, `read` permission) returns what the Plan & usage page shows: the plan and its `source`, `live` and `liveState`, the organization's `trial`, `customDomain`, the AI balance in `ai`, the Stripe `subscription` and whether limits are enforced.
>
> `management.billing.organization()` or `domino billing organization` (`GET /management/v1/organization/billing`) returns what the Billing page shows, for any member of the organization and without selecting a project: each `projects` entry's `plan`, `source`, `live`, `liveState` and `subscription`, `freeProjects` against its limit, the shared free AI allowance in `freeAi`, the `trial`, and in `billing` whether you may open the customer portal. `management.billing.organizationPortal()` opens the portal and returns to the Billing page.
>
> The `management.billing` methods and `domino billing` commands are experimental while billing is open to Domino staff only: their results and plan names can change in a minor release. `management.usage.plan()` and `domino usage plan` are stable.

## The hosted app [#the-hosted-app]

When a promotion carries an app version that live doesn't serve yet, it shows as a change. Approval applies the definitions first, then Domino puts that version up as your [live app](/docs/concepts/hosting#how-test-and-live-hosting-relate), at `<project-slug>.domino.page`. This typically takes a couple of minutes. Until then, the version live already serves keeps serving.

If that fails, the previous version keeps serving. The next promotion shows the app as changed again; approving it tries again.

> [!DEV]
> Once approval commits, Domino deploys the build again with live's own key, secrets, stores, and schedule signing key, then switches the live app to it.

## Rollback [#rollback]

To undo a promotion, choose **Prepare rollback** in Console's promotion history. It prepares a promotion of the definitions and app version an earlier promotion made live, and you review and approve it like any other. It adds to the history rather than rewriting it.

* **Newer definitions are archived, not deleted.** Every live definition that promotion did not carry is archived, including one that was already live-only then.
* **Pickup policy resets.** A pickup policy the earlier promotion did not have goes back to untracked.
* **The earlier app returns.** Approving it puts the earlier app version live, as approval does for any version live does not serve.
* **Test is untouched.** The next promotion from test carries its changes again.

## Related [#related]

- [Publish behavior to live](/docs/build/publishing#publish-behavior-to-live) — the commands and client calls.
- [Test and live](/docs/concepts/environments) — which changes live accepts directly.
- [Hosted apps](/docs/concepts/hosting#how-test-and-live-hosting-relate) — how a promoted app version becomes the live app.
