---
title: "Update an installed skill to its newest published version"
method: POST
path: "/v1/skill-installations/{installation_id}/upgrade"
tags: ["skill-hub"]
---

# Update an installed skill to its newest published version

`POST /v1/skill-installations/{installation_id}/upgrade`

## Request

- Base URL: `https://api.patricia.app` (the document declares no server; this is the origin it was published from)
- URL: `https://api.patricia.app/v1/skill-installations/{installation_id}/upgrade`
- Auth: HTTP bearer

Move one installed skill onto the newest published version of that same skill, carrying its settings forward. The install itself is untouched: same skill, same sharing scope, same owner, and a skill that was running stays running while a paused one stays paused. There is no version to pick — the newest published one is the only destination, and going back to an older one is not offered here. ``expected_version_id`` is an optional compare-and-set guard: send back the ``available_version_id`` the page showed, and a version published in the meantime returns 409 rather than applying a different update. A skill that is already up to date is a 409. A LIVE delivery skill whose settings would not carry onto the newer version is a 409 that says so, rather than an upgrade that silently stops it posting.

## Path parameters

- `installation_id` string, uuid, required

## Headers

- `X-Tenant-Id` string, nullable

## Request body

- UpgradeInstallationRequest: Move an installed skill onto the newest published version of that same skill. There is no version to choose: the route resolves the skill's currently ACTIVE version inside the caller's tenant. ``expected_version_id`` is a compare-and-set guard over that resolution — the id the dashboard showed the person as "the update" — so a version published while they were reading the page surfaces a conflict instead of silently applying a different upgrade than the one they saw. It is never used AS the target, so it cannot pin another skill's or another tenant's version.
  - `expected_version_id` string, uuid, nullable

## Response `200`

Successful Response

- InstallationSummary: A tenant's skill installation: the Hub card + settings header (no PII). Carries the installed skill's display metadata (``title``/``slug``/``description``) resolved from the pinned manifest version's ``SkillDefinition`` so the Hub can name the card + page header without a second lookup. These are display labels, never a personal fact (G4). Every response uses the shared installation-summary builder, which also supplies the definition's listing state.
  - `id` string, uuid, required
  - `skill_id` string, uuid, required
  - `manifest_version_id` string, uuid, required
  - `status_code` string, required
  - `config_version` integer, required
  - `projection_generation` integer, required
  - `activated_at` string, date-time, nullable, required
  - `first_live_at` string, date-time, nullable, required
  - `killed_at` string, date-time, nullable, required
  - `kill_reason` string, nullable, required
  - `title` string, nullable
  - `slug` string, nullable
  - `description` string, nullable
  - `listing_state` 'unlisted' | 'testing' | 'listed': Who can discover and install a global skill.
  - `is_portable` boolean, nullable
  - `archetype_code` string, nullable
  - `can_edit_definition` boolean, nullable
  - `removable` boolean: Whether this installation may be removed from the workspace.
  - `visibility_code` 'team' | 'personal', required: Who, within a tenant, an installed skill is visible to (``skill_installation.visibility_code``). The skill-side counterpart of ``IntegrationVisibility``: ``TEAM`` is any actor in the tenant, ``PERSONAL`` is only the actor who installed it (``owner_actor_id``). A TEAM install is safe to surface in the shared, per-tenant prompt cache; a PERSONAL install is surfaced only through the per-run, actor-scoped progressive-disclosure loader (never the shared prompt, which would leak it across actors).
  - `is_mine` boolean, nullable
  - `can_change_visibility` boolean
  - `has_settings` boolean, nullable
  - `is_catalog_default` boolean
  - `effectively_enabled` boolean
  - `update_available` boolean
  - `available_version_id` string, uuid, nullable
  - `outdated_config` boolean
  - `outdated_config_reasons` string[]
  - `about` SkillAboutSummary: What a skill IS, projected from its pinned manifest: the Hub's plain-language overview. The Hub renders a skill's feature from its compiled ``feature_surface`` rows, but a skill whose manifest declares no surfaces (every ``skill``/``instructions`` archetype today) compiles none, so that path alone leaves the page blank. The manifest still describes the skill perfectly well (what it is for, what to say to reach it, what it wants connected), and this projects exactly that, generically: no per-skill branching, one shape for every archetype. Display labels only, never a personal fact (G4). Every field is optional-or-empty so a manifest that omits one simply renders one section fewer.
    - `category` string, nullable
    - `taxonomy` string, nullable
    - `example_phrases` string[]
    - `requires_connected` string[]
    - `works_with` string[]
    - `needs_skills` string[]
    - `credits_per_run` integer, nullable
    - `instructions_body` string, nullable
    - `has_settings` boolean

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden. Inspect response body `code` for the specific reason (for example: PERMISSION_DENIED, EMAIL_NOT_VERIFIED, TENANT_ACCESS_REQUIRED, ROLE_UNRESOLVED)
- `404`: Not found
- `409`: Conflict
- `422`: Validation error

---

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