---
title: "Update an app"
method: PUT
path: "/clients/{id_client}/apps/{id_app}"
tags: ["apps"]
---

# Update an app

`PUT /clients/{id_client}/apps/{id_app}`

## Request

- Base URL: `https://api.planvortex.com/v1.0.0`
- URL: `https://api.planvortex.com/v1.0.0/clients/{id_client}/apps/{id_app}`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (client credentials, token URL `https://api.planvortex.com/v1.0.0/oauth/token`)

Replaces the app's configuration. **Every field is overwritten with what you send**, so a `redirect_urls` you leave out becomes an empty list — send the whole object, not a patch.

Changing `webhook_url` takes effect on the next event; there is no verification handshake.

**It replaces every field with what the body carries.** `name`, `keycloak_client_idenfifier`, `allowed_domains`, `redirect_urls` and `webhook_url` are all written as sent, so omitting one erases it — sending an update without `webhook_url` turns the webhook off. Read the app first and send it back whole.

**`keycloak_client_idenfifier` is the one field that is NOT overwritten.** Sending a different one answers `ERROR_CODE_547` and nothing is written: it is the `client_id` your integration authenticates with, and renaming it would lock out everything already asking for tokens with the old one. Send it unchanged, or leave it out. If you need a different identifier, create another app.

**An app token works here.** This is the one part of `/apps` that does: an app can read and update its own record, but it cannot list, create, delete, or read the secret. **No plan is required**: apps are on all four plans, the free one included.

## Path parameters

- `id_client` string, required
- `id_app` string, required

## Request body

- AppsClientAppInput
  - `name` string, required: A name for the app. Cannot be blank (error 525).
  - `keycloak_client_idenfifier` string, required: The app's `client_id`, which is what you send to `POST /oauth/token`. **Format is enforced** (error 533): lowercase letters, numbers, `.`, `-` and `_`, starting with a letter or a number, between 3 and 64 characters — `shop-integration`, not `Shop Integration`. Keycloak itself accepts anything, so an identifier with a space in it used to create an app that could never get a token. It also has to be unique across PlanVortex (error 534), and **it cannot be changed once the app exists** (error 547): it is what your integration authenticates with, so renaming it would lock out everything already using the old one. Send it unchanged on an update, or leave it out. The spelling of the field is historical and kept for compatibility.
  - `allowed_domains` string[]: Origins allowed to call the API with this app's identity. Every entry has to be a valid URL (error 531).
  - `redirect_urls` string[]: URLs the connect flow is allowed to come back to. A `redirect_uri` that is not in this list is refused when issuing a temporal connect token (error 532).
  - `webhook_url` string: Where PlanVortex posts events. Has to be a valid URL (error 535). See `ClientApp.webhook_url` for what arrives and how it is signed.

## Response `200`

The updated app

- object
  - `client_app` AppsClientApp, required: An app: the credentials a third-party integration authenticates with. **The secret is not here.** It lives in Keycloak and is read with `GET /clients/{id_client}/apps/{id_app}/secret`, which needs a user token.
    - `_id` string, required
    - `id_client` string, required
    - `id_user` string: The user who created the app, when it was created from the panel.
    - `name` string, required
    - `keycloak_client_idenfifier` string, required: The app's `client_id`. Fixed for the life of the app: it cannot be changed once created (error 547).
    - `allowed_domains` string[], required
    - `redirect_urls` string[], required
    - `webhook_url` string: Where PlanVortex posts events, when one is configured. **The body is an array of changes, not a single object**, and it carries two signature headers computed with this app's secret over the **raw** body: `x-hub-signature` (`sha1=<hex>`) and `x-hub-signature-256` (`sha256=<hex>`). Verify against the bytes you received — parsing the JSON and re-serialising it changes them and the signature will not match. The events delivered today are `new_account`, `change_state_account`, `messages`, `messaging_postbacks`, `messaging_seen`, `messaging_error`, `comments`, `integration_error`, `ai_plan_generated` and `ai_plan_failed`. The payload is documented in the `comments` specification. **Every** app of the client that has a `webhook_url` receives every event, not only the app whose call caused it: with two apps, each event arrives twice. Delivery is best effort: PlanVortex does not retry a webhook that fails.
    - `creation_date` string, date-time, required
    - `deleted` boolean, required: Deleting an app marks it instead of removing it — the Keycloak client is gone, so it can no longer get a token — and the listing filters those out.
    - `deleted_date` string, date-time

## Other responses

- `400`: Error. Classify by `code` in the body, never by the HTTP status.

---

[API](https://skmtc.dev/planvortex/apis/planvortex-api.md) · [All operations](https://skmtc.dev/planvortex/apis/planvortex-api/llms.txt) · [OpenAPI document](https://skmtc.dev/planvortex/apis/planvortex-api/revisions/abedbbc1cd52?raw)
