Register and install
Register app definitions with the API, how names are namespaced, installing into an org and tracking progress, disabling and enabling, the read endpoints, and every registration error with its fix.
Registering makes a version of your app available. Installing creates its components in an org. You register once per version; each org installs separately.
Diagram source
flowchart LR
A[acme_orders.json] -->|POST /v1/apps/available| B{Validate every component}
B -->|fails| X[400 / 409, nothing created]
B -->|passes| C[Registered version]
C -->|POST /v1/apps/install| D{Validate in the org}
D -->|fails| Y[install_failed, previous version kept]
D -->|passes| E[Components created]
E --> F[Admin configures settings and OAuth]Before you start
- Use a sandbox org. Registered versions are permanent and installed apps can't be fully uninstalled, so iterate somewhere disposable.
- Create an API key in Settings › Security › API Keys with the
org.admin.appsrole. Registration and installs run as that key. - Use the starter repo.
kustomer/kustomer-apps-starter-configshas example definitions and annpm run register-new-versionscript. PutAPI_BASE_URLandAPI_TOKENin.env.
Register a version
/v1/apps/availableThe body is the whole app definition.
curl -X POST "https://acme.api.kustomerapp.com/v1/apps/available" \
-H "Authorization: Bearer $KUSTOMER_API_KEY" \
-H "Content-Type: application/json" \
--data @dist/acme_orders.jsonKustomer validates the definition against its schema, then dry-runs every component against the service that will own it: each workflow, KView, Klass and hook. If anything fails, nothing is registered. The 201 response is an available_app whose id is <app>-<version>, with the final name in attributes.name and the OAuth client ID in attributes.clientId.
Names are namespaced
Kustomer rewrites component names so apps can't collide with each other or with an org's own configuration. You can write the full names yourself or leave them short; registration applies the scheme either way.
Private apps get your org ID
Private app names must be unique across Kustomer, so registration appends your org ID: acme_orders becomes acme_orders_<orgId>, and every rewritten name above uses the suffixed form, such as kustomer.app.acme_orders_<orgId>.refund.
Keep writing the short name in your definition and read the final one from attributes.name in the registration response. Use the final name in API calls that take an app name: installs, version IDs (acme_orders_<orgId>-1.5.0) and the redirect URI for third-party OAuth.
The identifier
identifier is a short, lowercase code (2 to 8 characters, a-z, 0-9, _) used to prefix your attributes on standard objects. Kustomer generates one if you leave it out. It can't change after your first registration, so pick it deliberately if you add attributes to customers or conversations.
Install in an org
Admins install from Settings › Apps › App Directory. To install with the API, use a key from the target org:
/v1/apps/installcurl -X POST "https://acme.api.kustomerapp.com/v1/apps/install" \
-H "Authorization: Bearer $KUSTOMER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"app": "acme_orders_<orgId>", "version": "1.5.0"}'appstringrequired- The registered app name.
versionstring- The version to install. Defaults to the latest.
The response is an app_install_state with status: "installing". Installs run in the background, so poll until they finish:
/v1/apps/install-state/{app}-{version}{
"data": {
"type": "app_install_state",
"attributes": {
"app": "acme_orders_<orgId>",
"version": "1.5.0",
"previousVersion": "1.4.3",
"status": "installed",
"startedAt": "2026-10-21T15:02:11.204Z",
"endedAt": "2026-10-21T15:02:19.871Z"
}
}
}Installing runs the same dry-run as registration, this time in the org. It catches conflicts the org brings, such as a Klass or KView name the org already uses.
After installing, admins fill in settings and connect any OAuth account. Upgrades use the same endpoint with a newer version; see Versioning and updates.
Read apps
Disable and enable
Disabling an app turns it off in the org without removing it.
/v1/apps/{app}/disable/v1/apps/{app}/enableThe response is 204, or 200 with data.warning when revoking a third-party token failed. The disable still succeeded.
Uninstalling
There's no API to fully uninstall an app. Disable it to turn it off; its Klasses and their records stay in the org. That's the main reason to develop in a sandbox org, and to iterate on a definition there before you install it anywhere that matters.