---
title: "Install a skill-platform skill into the tenant"
method: POST
path: "/v1/skill-installations"
tags: ["skill-hub"]
---

# Install a skill-platform skill into the tenant

`POST /v1/skill-installations`

## 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`
- Auth: HTTP bearer

Install a git-catalog skill by its catalog ``slug`` (e.g. ``celebrations``), pinned to the skill's active manifest version with a default config seeded from the manifest's config_fields. A portable skill (which already runs by default from the trusted catalog) comes up ACTIVE — the install is how a workspace customizes or later turns it off, never a prerequisite. A delivery (``sans``) skill is born PAUSED: the admin completes required settings + runs activation review before any delivery. Idempotent per skill: a second install of the same skill is a 409.

Every install here reaches the whole workspace (there is no personal catalog install), so this route additionally requires skills:install, not just skills:create.

## Headers

- `X-Tenant-Id` string, nullable

## Request body

- InstallSkillRequest: Install a git-catalog skill-platform skill into the tenant by its catalog ``slug``. The install is born ``paused`` and pinned to the skill's active manifest version, with a default config seeded from the manifest's ``config_fields``. The admin completes the required settings (channel/timezone) and runs activation review before anything is delivered.
  - `slug` string, required

## Response `201`

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)
- `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)
