---
title: "Update, publish or unpublish a component"
method: PATCH
path: "/api/admin/components/{id}"
tags: ["admin-components"]
---

# Update, publish or unpublish a component

`PATCH /api/admin/components/{id}`

## Request

- Base URL: `https://voltplan.app`
- URL: `https://voltplan.app/api/admin/components/{id}`
- Auth: HTTP bearer

Partial update. Only the keys of `AdminComponentPatch` are taken from the body; any other key is ignored. Values are passed to PocketBase without further validation, so anything PocketBase rejects (and invalid JSON) answers 500.

- `brand` is a brand **name**: it is matched or created in `component_brands`; an empty or non-string value clears the relation.
- `published: true` enforces the publication gate: `summary` (sent, or else stored) must be non-empty, otherwise 400. A sent non-empty `slug` is used; without a sent or stored slug one is derived from name and brand and made unique with `-2` … `-50` (500 when none is free); a stored slug is kept when none is sent. `published_at` is set to now when neither sent nor stored.
- `affiliate_links` (when an array) replaces the link set: stored links whose `id` is missing from the array are deleted, entries with `id` are updated (`url`, `country`), entries without `id` are created; entries lacking `url` or `country` are skipped.

Afterwards the cached component reads and the public pages `/components` and `/components/<slug>` are revalidated.

## Request body

- AdminComponentPatch: Partial update; only keys present are written. Any other key is ignored.
  - `name` string
  - `type` string: Component type: battery, charger, inverter, transformer, load, power, fuse, shunt, switch, disconnect, bridge or tool; `""` when unset.
  - `description` string
  - `image` string
  - `icon` string
  - `watt` number, nullable
  - `voltage_in` number, nullable
  - `voltage_in_type` string: `ac`, `dc`, or `""` when unset.
  - `voltage_out` number, nullable
  - `voltage_out_type` string: `ac`, `dc`, or `""` when unset.
  - `estd_price_euro` number, nullable
  - `duty_cycle` number, nullable: Share of time a load cycles on. Percentage 0–100.
  - `default_utilization_factor` number, nullable: Default share of time a load is used. Percentage 0–100.
  - `usage_hours_per_day` number, nullable
  - `amperage` number, nullable
  - `cutoff_voltage` number, nullable
  - `fuse_type` string
  - `wire_gauge` string
  - `preferred_suggestion` boolean
  - `published` boolean: `true` runs the publication gate described on the operation.
  - `published_at` string: PocketBase datetime; set to now on first publication when empty.
  - `slug` string: Public URL segment of /components/<slug>; unique among non-empty values.
  - `summary` string: Lead paragraph of the public page.
  - `safety_notes` string[], nullable: Wiring hazards shown in the amber callout of the public page.
  - `specs` AdminComponentSpecRow[], nullable: Technical-data table of the public page.
    - `k` string, required
    - `v` string, required
  - `downloads` AdminComponentDownload[], nullable: Datasheets and manuals.
    - `ext` string, required: Badge text, e.g. `PDF`.
    - `name` string, required
    - `meta` string: E.g. `1.2 MB · rev. 2026-03`.
    - `url` string, uri, required
  - `works_with` string[]: Ids of curated companion components.
  - `works_with_notes` object, nullable: Component id → short pairing note.
  - `brand` string, nullable: Brand name, matched or created in `component_brands`; empty or non-string clears the brand.
  - `affiliate_links` AdminComponentAffiliateLinkInput[]: Complete desired link set; stored links missing here are deleted.
    - `id` string: Id of an existing `affiliate_links` record to update.
    - `url` string
    - `country` 'universal' | 'de' | 'us' | 'uk' | 'fr' | 'es' | 'it' | 'au'

## Response `200`

Updated record (without `expand`).

- AdminComponentUpdateResult
  - `success` unknown, required
  - `component` AdminComponent, required: A `components` record. It carries every column of the live collection; the properties below are the ones the app reads. Empty text fields are `""`, empty numbers `0`, empty JSON fields `null`.
    - `id` string, required
    - `collectionId` string, required
    - `collectionName` string, required
    - `created` string: Creation time. PocketBase datetime `YYYY-MM-DD HH:MM:SS.sssZ`; `""` when unset.
    - `updated` string: Last update. PocketBase datetime `YYYY-MM-DD HH:MM:SS.sssZ`; `""` when unset.
    - `name` string
    - `type` string: Component type: battery, charger, inverter, transformer, load, power, fuse, shunt, switch, disconnect, bridge or tool; `""` when unset.
    - `description` string
    - `image` string: Product image URL.
    - `icon` string: Filename in the `icon` file field.
    - `watt` number, nullable
    - `voltage_in` number, nullable
    - `voltage_in_type` string: `ac`, `dc`, or `""` when unset.
    - `voltage_out` number, nullable
    - `voltage_out_type` string: `ac`, `dc`, or `""` when unset.
    - `estd_price_euro` number, nullable
    - `duty_cycle` number, nullable: Share of time a load cycles on. Percentage 0–100.
    - `default_utilization_factor` number, nullable: Default share of time a load is used. Percentage 0–100.
    - `usage_hours_per_day` number, nullable: Hours per day, 0–24.
    - `amperage` number, nullable
    - `cutoff_voltage` number, nullable
    - `surge_watt` number, nullable
    - `pure_sine` boolean, nullable
    - `load_category` string
    - `fuse_type` string
    - `wire_gauge` string
    - `source_url` string
    - `preferred_suggestion` boolean
    - `published` boolean: Manual release gate of the public page.
    - `published_at` string: First publication. PocketBase datetime `YYYY-MM-DD HH:MM:SS.sssZ`; `""` when unset.
    - `slug` string: Public URL segment of /components/<slug>; unique among non-empty values.
    - `summary` string: Lead paragraph of the public page.
    - `safety_notes` string[], nullable: Wiring hazards shown in the amber callout of the public page.
    - `specs` AdminComponentSpecRow[], nullable: Technical-data table of the public page.
      - `k` string, required
      - `v` string, required
    - `downloads` AdminComponentDownload[], nullable: Datasheets and manuals.
      - `ext` string, required: Badge text, e.g. `PDF`.
      - `name` string, required
      - `meta` string: E.g. `1.2 MB · rev. 2026-03`.
      - `url` string, uri, required
    - `gallery` string[]: Filenames in the `gallery` file field.
    - `works_with` string[]: Ids of curated companion components.
    - `works_with_notes` object, nullable: Component id → short pairing note.
    - `requires_any` string[]
    - `brand` string: Id of the `component_brands` record; `""` when none.
    - `component_category` string
    - `review_count` number
    - `review_avg` number
    - `review_dist` object, nullable
    - `expand` AdminComponentExpand: Expanded relations; `brand` is present only when the component has a brand and it was loaded with `expand`.
      - `brand` AdminComponentBrand: A `component_brands` record (expanded relation).
        - `id` string, required
        - `name` string, required
        - `description` string
        - `price_range` number
        - `color` string: Hex colour code.
        - `created` string: Creation time. PocketBase datetime `YYYY-MM-DD HH:MM:SS.sssZ`; `""` when unset.
        - `updated` string: Last update. PocketBase datetime `YYYY-MM-DD HH:MM:SS.sssZ`; `""` when unset.

## Other responses

- `400`: Publishing without a summary.
- `403`: Admin access required. Returned for a missing, invalid or expired bearer token as well as for a valid token whose user lacks `is_admin=true`; admin endpoints never answer 401.
- `500`: Invalid JSON, unknown `id`, PocketBase validation error or no free slug.

---

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