Reusing an existing store on installation
On the authorization screen the merchant reaches when installing your app — the redirect to /appstore/integration/HASH, step 3 of the installation — they can select a store that already exists in their account, instead of always creating a new one.
What changed
Previously, every installation necessarily created a new store. Whenever the merchant installed more than one app, or reinstalled the same one, the account piled up duplicate stores — each with its own external_id and its own credentials, with no obvious relationship between them.
Now the authorization screen offers a store selection field. The merchant chooses between reusing an existing store and creating a new one.
INFO
Nothing changes in the API contract. The four installation steps, the validation URL contract, and the credentials/tokens process remain exactly the same. No new parameter is required from the partner app.
Store and site are the same thing
This is the main source of confusion, so it's worth spelling out:
| Where you see it | Term used |
|---|---|
| Merchant-facing screens (Appmax panel, authorization screen) | store ("loja") |
| API and webhooks | site (site_id) |
It is the same entity with two names. When this page says "existing store", the API equivalent is a site that already has a site_id. If a webhook arrives with a site_id you already know, it's because the installation was bound to a store that already existed.
What the merchant sees
The screen's behavior depends on what the merchant picks:
| Scenario | "Store name" field | "Select Company" field | Domain | Store created? |
|---|---|---|---|---|
| Picked an existing store | Not shown (the store already has a name) | Pre-filled and locked with that store's company | Pre-filled with the store's registered domain | No |
| Picked "Create new store" | Shown, the merchant fills it in | The merchant chooses | The merchant fills it in | Yes |
| Merchant has no stores | Shown, the merchant fills it in | The merchant chooses | The merchant fills it in | Yes |
When the merchant does not have any store yet, the selection field does not appear — the flow is the previous one, unchanged.
Only eligible stores show up in the list: active, belonging to the merchant themselves, and with a company in good standing at Appmax. A store that does not meet these criteria is simply not offered.
What changes for your integration
In the contract, nothing. The implication is conceptual: the store bound to the installation may be one that already existed — including one where your app was installed before.
Revisit the "one installation = one new store" assumption
If your system creates local records assuming each installation corresponds to a freshly created store, that assumption no longer holds. Treat the installation as idempotent per store: when the health check arrives, check whether you already have a record for that store and update it instead of inserting a new row.
Without that, you accumulate orphan records pointing at the same store, holding old external_id values that Appmax no longer recognizes.
Reinstalling at the same store
When the merchant reinstalls your app picking the same store:
| What happens | Detail |
|---|---|
| The app ↔ store binding is updated | Not duplicated — there is still a single binding between your app and that store. |
The external_id replaces the previous one | The value your validation URL returns on the new health check becomes the store's. The old value ceases to exist. |
A new client_id is generated | Every installation generates new credentials. The store accumulates credentials over time — always use the most recent one. |
Always persist the latest external_id
If your front-end keeps sending the old external_id in the external-id header, the requests answer 404 Merchant not found.
On every health check, store the new value and discard the previous one. And remember: you must generate a new UUID on every health check request — repeated values are rejected by Appmax. Full life cycle at external-id.
The usual recommendation still applies: read the external_id from your database on every checkout render, keyed by the store. If you cache that value in session state or in an environment variable, invalidate the cache when a new health check arrives.
Availability
The feature is rolled out gradually. While it is not active for an account, the authorization screen keeps the previous behavior — every installation creates a new store — and nothing changes for existing integrations.
In other words: you don't need to wait for the rollout to adjust your code. An integration that already treats the installation as idempotent per store works in both modes.
See also
- Installation flow — the four steps, including the redirect where the selection happens.
- Installation callback — redirect handler that receives the token.
external-id— identifier life cycle and when it changes.- Validate your validation URL — tool to check the health check contract.
- Webhooks — where the store appears as
site_id.