---
title: "Create a new user-defined block."
method: POST
path: "/api/blocks"
tags: ["blocks"]
---

# Create a new user-defined block.

`POST /api/blocks`

## Request body

- CreateBlockRequest — Request to create a new block definition (currently not supported for user-defined blocks)
  - `category` string, required
  - `description` string, required
  - `exposed_properties` ExposedProperty[], required
    - `default_value` union — Property value that can be various types. GStreamer properties can be strings, numbers, booleans, enums, etc.
      - string
      - integer
      - integer
      - number, double
      - boolean
    - `description` string, required — Description for users
    - `label` string, required — Human-readable label for display in UI (e.g., "Auth Token" instead of "auth_token")
    - `live` boolean — Whether this property updates the pipeline in real-time without requiring a flow save. Live properties show a LIVE badge in the UI and send updates directly to running elements.
    - `mapping` PropertyMapping, required — Maps an exposed property to one or more internal element properties
      - `element_id` string, required — Which internal element's property to set
      - `property_name` string, required — Property name on that element
      - `transform` string, nullable — Optional transformation (for future use)
    - `name` string, required — Name of the exposed property (used as key)
    - `persist` boolean, nullable — Whether live writes to this property should also be persisted to the block instance's properties map (so they survive pipeline restart). `None` (default) means persist. Set explicitly to `Some(false)` for transient properties — e.g. solo states like `chN_pfl`/`chN_afl` — that should reset on restart and not dirty the flow on every toggle. `Option` is used here (rather than a bare `bool` with a serde default) to keep existing struct-literal call sites compiling — they get the default behaviour without an added field. Read via `persist()`.
    - `property_type` union, required — Property type enumeration for exposed properties
      - 'string'
      - 'multiline'
      - 'int'
      - 'uint'
      - 'float'
      - 'bool'
      - object
        - `enum` object, required
          - `values` EnumValue[], required
            - `label` string, nullable — Optional human-readable label for UI display
            - `value` string, required — The actual value stored/used
      - 'networkinterface' — Network interface selector - frontend fetches available interfaces from API
      - object — Local capture/playback device selector. Frontend fetches the live device list from `/api/discovery/devices?category=<category>` and renders a dropdown of `DeviceResponse`s.
        - `device` object, required — Local capture/playback device selector. Frontend fetches the live device list from `/api/discovery/devices?category=<category>` and renders a dropdown of `DeviceResponse`s.
          - `category` 'audiosource' | 'audiosink' | 'videosource' | 'networksource' | 'other', required — Device category for filtering.
  - `external_pads` ExternalPads, required — External pads that the block exposes
    - `inputs` ExternalPad[], required — Input pads (mapped to internal element pads)
      - `internal_element_id` string, required — Which internal element and pad this maps to
      - `internal_pad_name` string, required
      - `label` string, nullable — Optional display label (shown in graph editor)
      - `media_type` 'Generic' | 'Audio' | 'Video', required — Media type classification for pads.
      - `name` string, required — External name for this pad
    - `outputs` ExternalPad[], required — Output pads (mapped to internal element pads)
      - `internal_element_id` string, required — Which internal element and pad this maps to
      - `internal_pad_name` string, required
      - `label` string, nullable — Optional display label (shown in graph editor)
      - `media_type` 'Generic' | 'Audio' | 'Video', required — Media type classification for pads.
      - `name` string, required — External name for this pad
  - `name` string, required
  - `ui_metadata` BlockUIMetadata — UI metadata for block rendering
    - `dark_fill_color` string, nullable — Fill/background color in dark mode (hex color)
    - `dark_stroke_color` string, nullable — Stroke/border color in dark mode (hex color)
    - `dark_text_color` string, nullable — Text color in dark mode (hex color)
    - `height` number, float, nullable — Height in the editor (in grid units)
    - `icon` string, nullable — Icon or visual identifier (emoji or name)
    - `light_fill_color` string, nullable — Fill/background color in light mode (hex color)
    - `light_stroke_color` string, nullable — Stroke/border color in light mode (hex color)
    - `light_text_color` string, nullable — Text color in light mode (hex color)
    - `width` number, float, nullable — Width in the editor (in grid units)

## Response `201`

Block created

- BlockResponse — Response containing a block definition
  - `block` BlockDefinition, required — Block definition - metadata for creating block instances. Note: Built-in blocks use the BlockBuilder trait to create GStreamer elements directly. User-defined blocks are not yet supported.
    - `built_in` boolean, required — Whether this is a built-in block (read-only) or user-defined
    - `category` string, required — Category for organization (e.g., "Inputs", "Outputs", "Codecs")
    - `description` string, required — Description of what this block does
    - `exposed_properties` ExposedProperty[], required — Exposed properties that users can configure
      - `default_value` union — Property value that can be various types. GStreamer properties can be strings, numbers, booleans, enums, etc.
        - string
        - integer
        - integer
        - number, double
        - boolean
      - `description` string, required — Description for users
      - `label` string, required — Human-readable label for display in UI (e.g., "Auth Token" instead of "auth_token")
      - `live` boolean — Whether this property updates the pipeline in real-time without requiring a flow save. Live properties show a LIVE badge in the UI and send updates directly to running elements.
      - `mapping` PropertyMapping, required — Maps an exposed property to one or more internal element properties
        - `element_id` string, required — Which internal element's property to set
        - `property_name` string, required — Property name on that element
        - `transform` string, nullable — Optional transformation (for future use)
      - `name` string, required — Name of the exposed property (used as key)
      - `persist` boolean, nullable — Whether live writes to this property should also be persisted to the block instance's properties map (so they survive pipeline restart). `None` (default) means persist. Set explicitly to `Some(false)` for transient properties — e.g. solo states like `chN_pfl`/`chN_afl` — that should reset on restart and not dirty the flow on every toggle. `Option` is used here (rather than a bare `bool` with a serde default) to keep existing struct-literal call sites compiling — they get the default behaviour without an added field. Read via `persist()`.
      - `property_type` union, required — Property type enumeration for exposed properties
        - 'string'
        - 'multiline'
        - 'int'
        - 'uint'
        - 'float'
        - 'bool'
        - object
          - `enum` object, required
            - `values` EnumValue[], required
              - …
        - 'networkinterface' — Network interface selector - frontend fetches available interfaces from API
        - object — Local capture/playback device selector. Frontend fetches the live device list from `/api/discovery/devices?category=<category>` and renders a dropdown of `DeviceResponse`s.
          - `device` object, required — Local capture/playback device selector. Frontend fetches the live device list from `/api/discovery/devices?category=<category>` and renders a dropdown of `DeviceResponse`s.
            - `category` 'audiosource' | 'audiosink' | 'videosource' | 'networksource' | 'other', required — Device category for filtering.
    - `external_pads` ExternalPads, required — External pads that the block exposes
      - `inputs` ExternalPad[], required — Input pads (mapped to internal element pads)
        - `internal_element_id` string, required — Which internal element and pad this maps to
        - `internal_pad_name` string, required
        - `label` string, nullable — Optional display label (shown in graph editor)
        - `media_type` 'Generic' | 'Audio' | 'Video', required — Media type classification for pads.
        - `name` string, required — External name for this pad
      - `outputs` ExternalPad[], required — Output pads (mapped to internal element pads)
        - `internal_element_id` string, required — Which internal element and pad this maps to
        - `internal_pad_name` string, required
        - `label` string, nullable — Optional display label (shown in graph editor)
        - `media_type` 'Generic' | 'Audio' | 'Video', required — Media type classification for pads.
        - `name` string, required — External name for this pad
    - `id` string, required — Unique identifier for this block definition
    - `name` string, required — Human-readable name (e.g., "AES67 Input")
    - `ui_metadata` BlockUIMetadata — UI metadata for block rendering
      - `dark_fill_color` string, nullable — Fill/background color in dark mode (hex color)
      - `dark_stroke_color` string, nullable — Stroke/border color in dark mode (hex color)
      - `dark_text_color` string, nullable — Text color in dark mode (hex color)
      - `height` number, float, nullable — Height in the editor (in grid units)
      - `icon` string, nullable — Icon or visual identifier (emoji or name)
      - `light_fill_color` string, nullable — Fill/background color in light mode (hex color)
      - `light_stroke_color` string, nullable — Stroke/border color in light mode (hex color)
      - `light_text_color` string, nullable — Text color in light mode (hex color)
      - `width` number, float, nullable — Width in the editor (in grid units)

## Other responses

- `400` — Bad request
- `500` — Internal server error

## Changes

> 25 revisions in range; 17 could not be searched.

- **2026-04-07** `1e67862a080e` — 1 breaking, 2 warning, 1 info
  - removed `subschema #9` from the `exposed_properties/items/property_type` request property `oneOf` list
  - removed the request property `exposed_properties/items/persist`
  - removed the optional property `block/exposed_properties/items/persist` from the response with the `201` status
  - removed `subschema #9` from the `block/exposed_properties/items/property_type` response property `oneOf` list for the response status `201`

[Change history](https://skmtc.dev/eyevinn/apis/strom-api/changes/api/blocks/post.md)

---

[API](https://skmtc.dev/eyevinn/apis/strom-api.md) · [All operations](https://skmtc.dev/eyevinn/apis/strom-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/eyevinn/strom-api/revisions/0df7ca64263f/schema)
