# Migrate from Sandbox to Production

Sandbox and production are fully separate environments: separate content, separate internal IDs, separate webhooks and keys. Nothing moves automatically — you build the hub in sandbox, then migrate the configuration to production yourself using the tools below.

**The one rule that makes migration painless:** entities reference each other by internal IDs, and internal IDs are always different between environments. What survives the move are the keys _you_ control — item **SKU**, store **key**, page and article **slug**, price template and reward **keys**. The migration tooling re-links everything by these keys.

* * *

## Stage 1 — Prepare your hub in sandbox

Switch to the sandbox environment using the environment selector in the top-right corner of the dashboard (it stays locked until the initial AI content generation finishes).

Both environments are created with the same AI-generated demo content: a default store, demo items, sample news, leaderboards with test participants. In sandbox, archive or delete this seed first, then build your real catalog and hub on a clean slate — don't reshape demo entities into real ones.

> **WARNING:** Archiving does not free an entity's SKU or key. Production holds the same demo seed, and the transfer matches objects by key **including archived ones** — so a real item that shares a SKU with a demo item will collide with it in production. Assign your own SKUs and keys; never reuse ones from the demo seed.

Everything you configure in sandbox uses test data only: no real players, no live payments (see [Test payments](https://docs.aghanim.com/checkout/test-payments.md)).

* * *

## Stage 2 — Migrate to production

### Before transferring: archive the production starter content

Production still holds its untouched demo seed, and the transfer never removes anything — it only creates and updates by key. Archive the seed **before** transferring, all of it, so demo content and migrated content don't end up mixed in one catalog. Catalog entities (items, bundles, lootboxes, subscriptions) and campaigns support archiving; demo news, leaderboards and daily rewards can only be deleted  — delete them. Keyed system entities you can't remove (the `default` store, system pages) are safe: the transfer overwrites them with your sandbox versions.

### Three ways to move content

| Method | Covers | Notes |
| --- | --- | --- |
| **Transfer tool** — the _Transfer_ button on entity lists in the dashboard | Items (SKUs), bundles, lootboxes, subscriptions, stores and store contents, offers, store promotions, daily rewards, loyalty program, progression programs, campaigns, website (theme, card templates, hub customization, login form and social media, pages with leaderboards and achievements), website promos, news, articles and article folders | Re-maps internal IDs by SKU/key automatically. Virtual currencies and other dependencies travel along with the items that use them |
| **File export / import** (Google Sheets or XLSX; translations: Sheets or JSON) | Glossary, translations, price templates, coupons, creators | Export from sandbox → import into production. Import applies immediately — only creator import supports a validation dry-run. Stores and store contents can be _exported_ to a file, but not imported back: use the Transfer tool for them |
| **Configure fresh** in the dashboard | Webhooks, API keys, Aghanim Connect connectors, custom domain | Environment-specific by design — see below |

### How the Transfer tool works

*   **Run it from sandbox.** Open the entity list in your sandbox environment, select the rows, click **Transfer**, and choose the production game as the destination.
*   **It transfers your selection**, not the whole list — a page shows up to 100 entries, so a large catalog takes several passes.
*   **Dependencies come along automatically.** Nested bundle items, lootbox drop tables, fallback items, virtual currencies referenced by prices — all pulled in and re-linked by SKU. If a referenced item can't be resolved in the destination, the transfer reports an error for that object instead of creating it broken.
*   **Review the preview.** Every transfer shows a diff before applying. Use the _exclude object types_ selector to protect entities you've already fine-tuned in production from being overwritten on repeat runs.
*   **It's repeatable.** The transfer is an upsert by key — running it again is the normal way to top up changes, not a risk.
*   **Partial failures are safe.** Objects that failed are listed in the result; fix the cause and run the transfer again.

> **WARNING:** The store transfer has an optional checkbox to delete destination store items that aren't in the source. It's off by default — leave it off unless you deliberately want production stores mirrored to sandbox exactly.

### Transferring the website

The website transfer asks which parts to copy. All of them are selected by default; clear the ones you want to leave untouched in the destination, and keep at least one selected.

| Part | Covers |
| --- | --- |
| **Theme** | Colors, fonts and styles of the game hub |
| **Card templates** | Card templates, linked to item categories with the same slug in the destination game |
| **Hub customization** | Favicon, background, product images ratio, section header alignment, leaderboard icons and player avatars |
| **Login form and social media** | Login form background and welcome images, social media links |
| **Pages** | Pages with blocks and their dependencies (offers, stores, items), leaderboards and achievements |

Clearing a part is the way to protect work you've already done in production: re-run the transfer with only **Pages** selected, for instance, and a theme you've since tuned in production stays as it is.

### Transferring articles

The **Articles** section transfers a selection rather than the whole section.

*   **Pick what moves.** Select individual articles, or pick a single folder to move it together with its subfolders and every article they hold.
*   **Pick where the articles land.** Transferred articles can go into copies of their source folders (the default, which rebuilds the folder tree in the destination), outside any folder, into a folder the destination game already has, or into a new root folder you name. Transferring a whole folder always rebuilds the folder tree.
*   An article that already exists in the destination and is transferred outside any folder stays in the folder it currently sits in.
*   **Folders match by slug**, and folders without a slug match by name. Articles match by slug, like the rest of the Transfer tool.

> **WARNING:** An article and a folder can't share a slug in the destination game. When a transferred article's slug is already taken by a folder there, or a folder's slug by an article, the preview flags that object and the transfer won't run until you rename one of them.

### Recommended order

Order matters _between_ entity types (a store references items); within the catalog the tooling resolves dependencies itself:

1.  **Price templates** — file import (store contents reference them).
2.  **Catalog** — items, bundles, lootboxes, subscriptions via the Transfer tool. **Pity (guaranteed drop) steps are the exception** to automatic re-linking: after transferring a lootbox with pity configured, re-select the guaranteed items in production.
3.  **Stores, store contents, offers, promotions** — Transfer tool.
4.  **Daily rewards, loyalty, progression, campaigns** — Transfer tool. Campaign transfer doesn't carry linked pages — move the website first, then verify campaign page references.
5.  **Glossary, translations, coupons, creators** — file import.
6.  **Website: theme, pages, news, articles** — Transfer tool, selecting the website parts you want to move.
7.  **Webhooks, API keys, connectors** — configure fresh (next section).
8.  **Custom domain → final checks → publish.**

Media doesn't need re-uploading: asset URLs are environment-independent, transferred content keeps working images.

### Never copy these — configure them fresh

These are environment-specific by design. Copying sandbox values into production will break things:

*   **Webhook endpoints and secrets** — production has its own signing secrets (`whsec_…` vs `whsec_sandbox_…`). Register your production webhook URLs in [**Integration** → **Webhooks**](https://dashboard.aghanim.com/go/integration/webhooks); never point production at your test endpoints.
*   **API keys** — issued per environment; generate production keys in [**Integration** → **API keys**](https://dashboard.aghanim.com/go/integration/api-keys).
*   **Aghanim Connect connectors** — reinstall in [**Aghanim Connect**](https://dashboard.aghanim.com/go/app-connect) with production credentials (real Measurement ID, production MMP tokens), not test apps.
*   **Custom domain and publish state** — set up on production directly (see [Custom domain](https://docs.aghanim.com/advanced/custom-domain-name.md)).

* * *

## Verify before publishing

*   Open every hub page in preview: blocks that reference stores, items or articles render correctly.
*   No demo content is left visible: sample news, demo items, and especially leaderboards with test participants — they look like live data and will be visible to real players.
*   Lootboxes with pity: confirm the guaranteed drop items point at production items.
*   Production **webhooks** respond. Publishing runs a live check on `player.verify` — the hub won't publish if it fails. Make sure `item.add` and `item.remove` are registered too, or purchases won't be delivered.
*   Make a test purchase and confirm the item is delivered and your analytics connectors receive the event.
*   A deep link from a production game build lands in the hub and auto-authorizes the player.

Then publish the hub — and hold announcements until the cache propagates.

* * *

**Need help?** Contact us at [integration@aghanim.com](mailto:integration@aghanim.com) — we can review your migration plan or walk through the Transfer tool with you.

---
Source: https://docs.aghanim.com/advanced/migrate-to-production