Skip to content

App installation

Flow overview

The diagram below shows every call involved in the installation, including the server-to-server call that Appmax makes to your validation URL during the health check.

INFO

Step 4 combines two actions in a single request:

  1. You call POST /app/client/generate with the authorized hash.
  2. While processing that call, Appmax makes a server-to-server POST to the validation URL you configured.
  3. Your validation URL must respond with HTTP 200 and an external_id (UUID) — only then will Appmax return the merchant credentials.

The external_id you return here is not throwaway — it becomes the current identifier for that store and is used as the external-id header on every CDN call from the front-end. Every new installation requires a new value from Appmax, and the previous one stops being valid. See external-id to understand where this value is consumed later.

Installation flow

Obtain the app token

Before making any request, obtain the access token using the app credentials.

Endpoint: POST https://auth.appmax.com.br/oauth2/token

bash
curl --location 'https://auth.appmax.com.br/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=CLIENT_ID' \
--data-urlencode 'client_secret=CLIENT_SECRET'

Response:

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...",
  "token_type": "Bearer",
  "expires_in": 3600
}
Authorize the installation

With the app access token, generate an authorization hash to redirect the merchant.

Endpoint: POST https://api.appmax.com.br/app/authorize

bash
curl --location 'https://api.appmax.com.br/app/authorize' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--data '{
  "app_id": "APP_ID",
  "external_key": "EXTERNAL_KEY",
  "url_callback": "URL_CALLBACK",
  "domain_name": "subdomain.yourdomain.com"
}'

Response:

json
{
  "data": {
    "token": "12083w36219d223f33ecf48f2a7f5ccf143b0bc554"
  }
}

Request parameters:

app_idstringobrigatorio

App UUID of the application. Use the UUID, not the Numerical ID (see warning below).

external_keystringobrigatorio

Key provided by the partner platform to identify the origin of the installation (e.g., store_id, merchant_id).

url_callbackstringobrigatorio

URL where the user will be redirected after authorization.

domain_namestringopcional

The store's domain (subdomain + domain, e.g. mystore.myintegration.com). To send more than one domain in the same installation, use domain_names (array) instead of domain_name.

domain_name is essential if you're going to use Apple Pay

Not required for the installation itself, but it's essential if the store will process Apple Pay payments: it's from this domain, informed here, that Appmax registers the domain with Apple — part of enabling Apple Pay on the customer's device. Without it, the Apple Pay button won't work for that store, even if the rest of the integration is correct. You still need to publish the .well-known file on the domain — see Domain configuration for Apple Pay and Apple Pay payment.

App UUID vs App Numerical ID

Your application has two identifiers in the panel:

  • App UUID — e.g., 8f2c1d3e-5a4b-4c7d-9e1f-2a3b4c5d6e7f
  • App Numerical ID — e.g., 699

Use the App UUID in all endpoints of the official documentation (including this POST /app/authorize), except in POST /app/client/generate — or whenever a field is explicitly marked as "Numerical ID".

Confusing the two is one of the most common causes of 422 Unprocessable Entity at this stage. If you're receiving this error, check which of the two IDs you're sending.

Redirect the merchant

Redirect the user to the authorization URL, replacing HASH with the generated token.

EnvironmentRedirect URL
Sandboxhttps://breakingcode.sandboxappmax.com.br/appstore/integration/HASH
Productionhttps://admin.appmax.com.br/appstore/integration/HASH

WARNING

The redirect is essential for the merchant to authorize the installation. Without this step, the merchant credentials will not be generated.

The merchant can pick a store that already exists

On this screen the merchant can select an existing store from their account instead of creating a new one. The API contract does not change, but the store bound to the installation may be one that already existed — including one where your app was installed before. See Reusing an existing store on installation.

Generate merchant credentials (+ health check)

After the merchant authorizes the installation, use the hash to generate the credentials.

Endpoint: POST https://api.appmax.com.br/app/client/generate

bash
curl --location 'https://api.appmax.com.br/app/client/generate' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_TOKEN' \
--data '{
  "token": "12083w36219d223f33ecf48f2a7f5ccf143b0bc554"
}'

Response:

json
{
  "data": {
    "client": {
      "client_id": "MERCHANT_CLIENT_ID",
      "client_secret": "MERCHANT_CLIENT_SECRET"
    }
  }
}

WARNING

The hash can only be used once. The generated credentials are valid indefinitely until the app is uninstalled.

Health check

During this request, Appmax performs a health check to complete the installation. Appmax sends a POST to the validation URL specified in the "Validation URL" field when creating the application.

Payload sent:

json
{
  "app_id": 123,
  "client_id": "MERCHANT_CLIENT_ID",
  "client_secret": "MERCHANT_CLIENT_SECRET",
  "client_key": "EXTERNAL_KEY",
  "external_key": "EXTERNAL_KEY"
}

Payload fields:

app_idintegerobrigatorio

The application's App Numerical ID (numeric ID, e.g. 123). Note: this is the Numerical ID, not the UUID — unlike POST /app/authorize. It is the only required field in the payload: it is always present in every health check call.

client_idstringopcional

Optional. Client ID generated for the merchant (API credential). May not be sent — do not treat its absence as an error.

client_secretstringopcional

Optional. Client Secret generated for the merchant (API credential). May not be sent — do not treat its absence as an error.

client_keystringopcional

Optional. Same value as external_key (kept for backwards compatibility). May not be sent — do not treat its absence as an error.

external_keystringopcional

Optional. Key provided by the merchant during installation for identification. May not be sent — do not treat its absence as an error.

app_id: Numerical ID, and the only required field

In the health check payload, only app_id is required — all other fields are optional and may be absent. The app_id sent is the App Numerical ID (e.g. 123), not the UUID. Your handler should only validate the presence of app_id and treat the other fields as optional.

Expected response — HTTP 200:

json
{
  "external_id": "37bb0791-ee0b-457d-860c-186e32978bcd",
  "alias": "My Store"
}

You are the one who generates this external_id — Appmax only persists it, bound to the store. The same UUID later comes back as the external-id header on every front-end call (tokenization, Apple Pay) — it is the identifier for that store on the CDN. Generate a new UUID on every health check request: repeated values are rejected by Appmax — if the external_id it receives already exists in the database, it is discarded and automatically replaced by the installation's client_id. Store it in your database the moment you generate it and, whenever a new health check happens, always keep the latest value and discard the previous one. Full reference at external-id.

FieldTypeRequiredDescription
external_idstring (UUID)YesUnique installation ID in your system. Must be a valid UUID (v1 through v5) and unique across all installations. This same value is later sent as the external-id header on CDN calls from the front-end.
aliasstringNoSite/store name. If provided, it will be used as the display name in Appmax.

WARNING

The health check is mandatory to complete the installation. If your URL is not reachable, returns a status other than 200, or fails to return a valid UUID external_id in the body, the installation is considered failed — /app/client/generate aborts with 500 and no credentials are issued. Test your URL at Validate your validation URL before starting the installation flow.

DANGER

The external_id must be a valid UUID (e.g., 37bb0791-ee0b-457d-860c-186e32978bcd). For apps in the Payments and Security category, the external_id is strictly required — the installation will fail if it is not sent.

INFO

Store the external_id in your database to identify the binding between the merchant and your application. Each installation must generate a different external_id — duplicate values will be rejected.

Same value, from generation to front-end use

The external_id you return on the health check is exactly the same value that goes as the external-id header on every front-end call via CDN. Generate a new UUID on every health check request — repeated values are rejected by Appmax and automatically replaced by the installation's client_id. Store it the moment you generate it and, on every new health check, replace the stored value with the most recent one, discarding the previous. Usage details, AppCheckout.init parameter, and error diagnosis at external-id.

Authenticate with the merchant credentials

With the merchant credentials (client_id and client_secret) generated in the previous step, authenticate to obtain the merchant access token. This is the token that authorizes transactional operations (/v1/customers, /v1/orders, /v1/payments/*).

Endpoint: POST https://auth.appmax.com.br/oauth2/token

bash
curl --location 'https://auth.appmax.com.br/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=MERCHANT_CLIENT_ID' \
--data-urlencode 'client_secret=MERCHANT_CLIENT_SECRET'

Response:

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Use the returned access_token as the Authorization: Bearer YOUR_TOKEN header on the API's transactional calls.

WARNING

This is the same endpoint used to authenticate the application (step 1) — the difference is sending the merchant's client_id/client_secret. Sending the app credentials here results in 401 on the /v1/* routes.

INFO

The token expires in 1 hour and the API does not use refresh tokens — when it expires, just repeat this same request. The merchant credentials, on the other hand, are permanent (until uninstallation). Understand both credential types at Authentication.

Summary

  1. Obtain the app token using the app credentials.
  2. Authorize the installation by generating a hash.
  3. Redirect the merchant to authorize.
  4. Generate credentials with POST /app/client/generateduring this request, Appmax sends the health check to your validation URL. Respond with HTTP 200 and the external_id to complete the installation.
  5. Authenticate with the merchant credentials at POST /oauth2/token to obtain the access token and transact on the API (/v1/*).

Troubleshooting

The most common errors during installation and how to fix them.

422 Unprocessable Entity on POST /app/authorize

Most likely cause: you're sending the App Numerical ID instead of the App UUID in the app_id field.

Fix: copy the App UUID from the panel (format 8f2c1d3e-5a4b-...) and send it in that field. The Numerical ID (integer) is only used in POST /app/client/generate, never here.

422 Unprocessable Entity on POST /app/client/generate

Possible causes:

  1. Invalid or already-used hash — each hash can only be used once. If you tried and it failed, you need to generate a new hash with POST /app/authorize.
  2. Merchant didn't go through the redirect — you skipped step 3. Without the redirect and authorization in the panel, the hash doesn't become valid for generating credentials.
  3. Expired hash — hashes have limited lifetime. Generate a new one and complete the flow immediately.

Fix: follow the full flow in order: authorize → redirect → authorization in the panel → client/generate.

500 Internal Server Error on POST /app/client/generate

Most likely cause: the health check failed. Appmax tried to call your validation URL and:

  • The URL didn't respond (timeout, DNS, firewall, or wrong URL in the panel).
  • The URL responded with a status other than 200.
  • The URL responded with 200 but without a valid external_id in UUID format in the JSON body.

Fix:

  1. Verify the validation URL is correct in the app panel.
  2. Test it manually with curl — it must respond to POST with HTTP 200 and JSON containing {"external_id": "<valid UUID>"}.
  3. Check your server logs for the POST that Appmax sent.
  4. Make sure you're not using localhost or a private URL — Appmax needs to reach the URL publicly.

I received the POST on the validation URL, but POST /app/client/generate returns an error

Cause: your validation URL received the payload but didn't respond correctly — most likely:

  • Responded with a status other than 200 (e.g., 204, 301, 500).
  • Returned 200 but without JSON containing external_id in the body.
  • Returned an external_id that is not a valid UUID or already used in another installation.

Fix: your validation URL handler must:

  1. Return HTTP 200 explicitly.
  2. Include a JSON body with {"external_id": "<UUID v1-v5>"}.
  3. Generate a unique external_id per installation (e.g., uuid.v4()).

The validation URL is on localhost (development)

Appmax cannot reach private URLs. During development:

  • Use a tunnel service like ngrok, beeceptor, or similar.
  • Configure the public URL in the app panel.
  • When publishing to production, update to the final URL.

App credentials (client_id/client_secret) don't work on /v1/* routes

Cause: app credentials only work on POST /app/authorize and POST /app/client/generate. For transactional routes (/v1/customers, /v1/orders, etc.), use the merchant credentials generated in step 4.

See Authentication to understand both credential types.

Errors using external_id on the front-end (CDN)

The errors on this page cover the generation of the external_id during the health check. If the installation completed successfully but the front-end (tokenization, Apple Pay) is returning 401 Missing Authorization token, 404 Merchant not found, 404 Client id not found, or External ID is required, those are usage errors of the external-id header — the full diagnosis table is at Common errors and diagnosis.

More help

If your error is not listed above:

  • Check the FAQ.
  • Review Rate Limit if you're getting 429.
  • Use the appmax-docs MCP server (diagnose_error tool) passing the status code and the endpoint for an automated diagnosis.