# Organize API

Groups, folders, notes, favorites and other ways to keep overlays tidy.

Authenticate with a [personal token](/docs/api#personal-tokens) as `Authorization: Bearer pxp_...`; the operations are also [MCP tools](/docs/connect-ai) unless noted. The full machine-readable definition is in the [OpenAPI specification](https://pxstudio.cloud/api/v1/openapi.json).

| Operation | Method and path | Scope |
| --- | --- | --- |
| [List spots](#list-spots) | `GET /overlays/{overlayId}/spots` | `overlays:read` |
| [Create spot](#create-spot) | `POST /overlays/{overlayId}/spots` | `overlays:write` |
| [Update spot](#update-spot) | `PATCH /overlays/{overlayId}/spots/{spotId}` | `overlays:write` |
| [Move a layer into a spot](#move-a-layer-into-a-spot) | `POST /overlays/{overlayId}/spots/{spotId}/apply` | `overlays:write` |
| [Delete spot](#delete-spot) | `DELETE /overlays/{overlayId}/spots/{spotId}` | `overlays:write` |
| [Set saved positions of a layer](#set-saved-positions-of-a-layer) | `PUT /overlays/{overlayId}/members/{memberId}/position-presets` | `overlays:write` |
| [Move a layer to a saved position](#move-a-layer-to-a-saved-position) | `POST /overlays/{overlayId}/members/{memberId}/position-presets/apply` | `overlays:write` |
| [Create deck button](#create-deck-button) | `POST /overlays/{overlayId}/deck-macros` | `overlays:write` |
| [Update deck button](#update-deck-button) | `PATCH /overlays/{overlayId}/deck-macros/{macroId}` | `overlays:write` |
| [Reorder deck buttons](#reorder-deck-buttons) | `PUT /overlays/{overlayId}/deck-macros/order` | `overlays:write` |
| [Delete deck button](#delete-deck-button) | `DELETE /overlays/{overlayId}/deck-macros/{macroId}` | `overlays:write` |
| [Get starred deck buttons](#get-starred-deck-buttons) | `GET /overlays/{overlayId}/deck-favorites` | `overlays:read` |
| [Set starred deck buttons](#set-starred-deck-buttons) | `PUT /overlays/{overlayId}/deck-favorites` | `overlays:write` |
| [List notes](#list-notes) | `GET /overlays/{overlayId}/notes` | `overlays:read` |
| [Create note](#create-note) | `POST /overlays/{overlayId}/notes` | `overlays:write` |
| [Update note](#update-note) | `PATCH /overlays/{overlayId}/notes/{noteId}` | `overlays:write` |
| [Delete note](#delete-note) | `DELETE /overlays/{overlayId}/notes/{noteId}` | `overlays:write` |
| [Comment on a note](#comment-on-a-note) | `POST /overlays/{overlayId}/notes/{noteId}/comments` | `overlays:write` |
| [Delete note comment](#delete-note-comment) | `DELETE /overlays/{overlayId}/notes/{noteId}/comments/{commentId}` | `overlays:write` |
| [React to a note](#react-to-a-note) | `PUT /overlays/{overlayId}/notes/{noteId}/reactions` | `overlays:write` |
| [Restore look scenes](#restore-look-scenes) | `POST /overlays/{overlayId}/look-scenes/restore` | `scenes:write` |
| [List templates](#list-templates) | `GET /templates` | `overlays:read` |
| [Add a linked layer](#add-a-linked-layer) | `POST /overlays/{overlayId}/members/linked` | `members:write` |
| [List OBS scene mappings](#list-obs-scene-mappings) | `GET /overlays/{overlayId}/obs-mappings` | `overlays:read` |
| [Map an OBS scene](#map-an-obs-scene) | `POST /overlays/{overlayId}/obs-mappings` | `overlays:write` |
| [Delete OBS scene mapping](#delete-obs-scene-mapping) | `DELETE /overlays/{overlayId}/obs-mappings/{mappingId}` | `overlays:write` |

## Operations

### List spots

```http Endpoint
GET /api/v1/overlays/{overlayId}/spots
```

Lists the saved spots (named places on the canvas in design pixels: x, y from the top left, w, h) of an overlay. Spots are used by apply_spot and the member-to-spot automation.

**Scope:** `overlays:read` (Read overlays) · **MCP tool:** `list_spots` · **Notes:** read only

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |

::: tabs
@@ cURL
```bash
curl -X GET "https://pxstudio.cloud/api/v1/overlays/<overlayId>/spots" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/spots`, {
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Create spot

```http Endpoint
POST /api/v1/overlays/{overlayId}/spots
```

Saves a named spot (up to 12 per overlay). Send fromMemberId to save where that layer is now (like "Save as spot" in the editor; x, y, w, h are then ignored), or x, y, w, h in design pixels from the top left. Nothing changes on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `create_spot`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `name` | body | string | required | Up to 40 characters |
| `fromMemberId` | body | integer | optional | Save the current box of this layer. At least 1 |
| `x` | body | number | optional | -10000 to 10000 |
| `y` | body | number | optional | -10000 to 10000 |
| `w` | body | number | optional | 1 to 10000 |
| `h` | body | number | optional | 1 to 10000 |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/spots" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "..." }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/spots`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: "..." }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Update spot

```http Endpoint
PATCH /api/v1/overlays/{overlayId}/spots/{spotId}
```

Renames a spot or changes its box (send only what changes). Layers already in the spot do not move. Nothing changes on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `update_spot`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `spotId` | path | string | required | Spot id (from list_spots). Up to 64 characters |
| `name` | body | string | optional | Up to 40 characters |
| `x` | body | number | optional | -10000 to 10000 |
| `y` | body | number | optional | -10000 to 10000 |
| `w` | body | number | optional | 1 to 10000 |
| `h` | body | number | optional | 1 to 10000 |

::: tabs
@@ cURL
```bash
curl -X PATCH "https://pxstudio.cloud/api/v1/overlays/<overlayId>/spots/<spotId>" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "...", "x": 1 }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const spotId = '<spotId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/spots/${spotId}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: "...", x: 1 }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Move a layer into a spot

```http Endpoint
POST /api/v1/overlays/{overlayId}/spots/{spotId}/apply
```

Fits a layer (memberId) or a whole group (groupId) into a saved spot. In the live scene the layers move on air. Locked layers do not move.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `apply_spot`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `spotId` | path | string | required | Spot id (from list_spots). Up to 64 characters |
| `memberId` | body | integer | optional | Layer (member) id (from get_overlay or list_members). At least 1 |
| `groupId` | body | string | optional | Layer group id (from get_overlay groups). Up to 64 characters |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/spots/<spotId>/apply" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "memberId": 1, "groupId": "..." }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const spotId = '<spotId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/spots/${spotId}/apply`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ memberId: 1, groupId: "..." }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Delete spot

```http Endpoint
DELETE /api/v1/overlays/{overlayId}/spots/{spotId}
```

DESTRUCTIVE: deletes a saved spot. Automations that move layers to it stop working. Cannot be undone.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `delete_spot` · **Notes:** destructive, needs confirmation in MCP

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `spotId` | path | string | required | Spot id (from list_spots). Up to 64 characters |

::: tabs
@@ cURL
```bash
curl -X DELETE "https://pxstudio.cloud/api/v1/overlays/<overlayId>/spots/<spotId>" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const spotId = '<spotId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/spots/${spotId}`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Set saved positions of a layer

```http Endpoint
PUT /api/v1/overlays/{overlayId}/members/{memberId}/position-presets
```

Replaces the saved positions of one layer (up to 8, unique names up to 24 characters, layout in design pixels like update_member). Send the full list: read the current list first (get_overlay members[].positionPresets) to add one. Nothing changes on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `set_position_presets`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `memberId` | path | integer | required | Layer (member) id (from get_overlay or list_members). At least 1 |
| `presets` | body | array of object | required | Up to 8 items |

::: tabs
@@ cURL
```bash
curl -X PUT "https://pxstudio.cloud/api/v1/overlays/<overlayId>/members/<memberId>/position-presets" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "presets": [] }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const memberId = '<memberId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/members/${memberId}/position-presets`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ presets: [] }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Move a layer to a saved position

```http Endpoint
POST /api/v1/overlays/{overlayId}/members/{memberId}/position-presets/apply
```

Moves a layer to one of its saved positions (by name). In the live scene the layer moves on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `apply_position_preset`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `memberId` | path | integer | required | Layer (member) id (from get_overlay or list_members). At least 1 |
| `name` | body | string | required | Up to 24 characters |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/members/<memberId>/position-presets/apply" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "..." }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const memberId = '<memberId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/members/${memberId}/position-presets/apply`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: "..." }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Create deck button

```http Endpoint
POST /api/v1/overlays/{overlayId}/deck-macros
```

Creates a deck button (macro) with up to 20 steps that run in order when it is pressed (scene switch, widget command, media favorite, saved position, layout, YouTube video, delay). Creating it changes nothing on air; pressing it does (fire_deck_macro).

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `create_deck_macro`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `name` | body | string | required | Up to 40 characters |
| `color` | body | string or null | optional | Button color as #rrggbb (null removes it) |
| `icon` | body | string or null | optional | Icon name from the deck icon set, e.g. "star" (null removes it) |
| `steps` | body | array of object | required | Up to 20 items |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/deck-macros" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "...", "steps": [] }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/deck-macros`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: "...", steps: [] }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Update deck button

```http Endpoint
PATCH /api/v1/overlays/{overlayId}/deck-macros/{macroId}
```

Changes a deck button: name, color, icon and/or the full list of steps (send only what changes). Nothing changes on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `update_deck_macro`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `macroId` | path | integer | required | Deck button id (from list_deck_macros). At least 1 |
| `name` | body | string | optional | Up to 40 characters |
| `color` | body | string or null | optional | Button color as #rrggbb (null removes it) |
| `icon` | body | string or null | optional | Icon name from the deck icon set, e.g. "star" (null removes it) |
| `steps` | body | array of object | optional | Up to 20 items |

::: tabs
@@ cURL
```bash
curl -X PATCH "https://pxstudio.cloud/api/v1/overlays/<overlayId>/deck-macros/<macroId>" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "...", "color": "..." }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const macroId = '<macroId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/deck-macros/${macroId}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: "...", color: "..." }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Reorder deck buttons

```http Endpoint
PUT /api/v1/overlays/{overlayId}/deck-macros/order
```

Sets the order of the deck buttons. order must contain every deck button id of the overlay exactly once. Nothing changes on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `reorder_deck_macros`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `order` | body | array of integer | required | Up to 30 items |

::: tabs
@@ cURL
```bash
curl -X PUT "https://pxstudio.cloud/api/v1/overlays/<overlayId>/deck-macros/order" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "order": [] }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/deck-macros/order`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ order: [] }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Delete deck button

```http Endpoint
DELETE /api/v1/overlays/{overlayId}/deck-macros/{macroId}
```

DESTRUCTIVE: deletes a deck button. Cannot be undone.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `delete_deck_macro` · **Notes:** destructive, needs confirmation in MCP

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `macroId` | path | integer | required | Deck button id (from list_deck_macros). At least 1 |

::: tabs
@@ cURL
```bash
curl -X DELETE "https://pxstudio.cloud/api/v1/overlays/<overlayId>/deck-macros/<macroId>" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const macroId = '<macroId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/deck-macros/${macroId}`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Get starred deck buttons

```http Endpoint
GET /api/v1/overlays/{overlayId}/deck-favorites
```

Returns the starred deck buttons of an overlay as button ids: "scene:<sceneId>", "macro:<macroId>", "<memberId>:<action>" for a widget action, "effect:<slug>:<action>", "pixbot:<op>".

**Scope:** `overlays:read` (Read overlays) · **MCP tool:** `get_deck_favorites` · **Notes:** read only

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |

::: tabs
@@ cURL
```bash
curl -X GET "https://pxstudio.cloud/api/v1/overlays/<overlayId>/deck-favorites" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/deck-favorites`, {
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Set starred deck buttons

```http Endpoint
PUT /api/v1/overlays/{overlayId}/deck-favorites
```

Replaces the starred deck buttons of an overlay (full list, same id format as get_deck_favorites, e.g. "scene:12" or "macro:3"). Nothing changes on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `set_deck_favorites`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `buttonIds` | body | array of string | required | Up to 200 items |

::: tabs
@@ cURL
```bash
curl -X PUT "https://pxstudio.cloud/api/v1/overlays/<overlayId>/deck-favorites" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "buttonIds": [] }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/deck-favorites`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ buttonIds: [] }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### List notes

```http Endpoint
GET /api/v1/overlays/{overlayId}/notes
```

Lists the editor notes of an overlay with comments and reactions (up, down, your own).

**Scope:** `overlays:read` (Read overlays) · **MCP tool:** `list_notes` · **Notes:** read only

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |

::: tabs
@@ cURL
```bash
curl -X GET "https://pxstudio.cloud/api/v1/overlays/<overlayId>/notes" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/notes`, {
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Create note

```http Endpoint
POST /api/v1/overlays/{overlayId}/notes
```

Adds an editor note for the team (up to 500 characters), optionally pinned at x, y on the canvas and linked to a scene or layer. Never visible on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `create_note`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `text` | body | string | required | Up to 500 characters |
| `x` | body | number | optional | 0 to 10000 |
| `y` | body | number | optional | 0 to 10000 |
| `sceneId` | body | integer | optional | Scene id (from list_scenes). At least 1 |
| `memberId` | body | integer | optional | Layer (member) id (from get_overlay or list_members). At least 1 |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/notes" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "text": "..." }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/notes`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ text: "..." }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Update note

```http Endpoint
PATCH /api/v1/overlays/{overlayId}/notes/{noteId}
```

Changes a note: text (author or owner), resolved (done or open again), locked (pin cannot move) or the pin position x, y. Send only what changes.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `update_note`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `noteId` | path | integer | required | Note id (from list_notes). At least 1 |
| `text` | body | string | optional | Up to 500 characters |
| `resolved` | body | boolean | optional |  |
| `locked` | body | boolean | optional |  |
| `x` | body | number | optional | 0 to 10000 |
| `y` | body | number | optional | 0 to 10000 |

::: tabs
@@ cURL
```bash
curl -X PATCH "https://pxstudio.cloud/api/v1/overlays/<overlayId>/notes/<noteId>" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "text": "...", "resolved": true }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const noteId = '<noteId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/notes/${noteId}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ text: "...", resolved: true }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Delete note

```http Endpoint
DELETE /api/v1/overlays/{overlayId}/notes/{noteId}
```

DESTRUCTIVE: deletes a note with all its comments (author or owner). Cannot be undone.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `delete_note` · **Notes:** destructive, needs confirmation in MCP

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `noteId` | path | integer | required | Note id (from list_notes). At least 1 |

::: tabs
@@ cURL
```bash
curl -X DELETE "https://pxstudio.cloud/api/v1/overlays/<overlayId>/notes/<noteId>" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const noteId = '<noteId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/notes/${noteId}`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Comment on a note

```http Endpoint
POST /api/v1/overlays/{overlayId}/notes/{noteId}/comments
```

Adds a comment (up to 1000 characters) to a note thread. Never visible on air.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `add_note_comment`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `noteId` | path | integer | required | Note id (from list_notes). At least 1 |
| `text` | body | string | required | Up to 1000 characters |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/notes/<noteId>/comments" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "text": "..." }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const noteId = '<noteId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/notes/${noteId}/comments`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ text: "..." }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Delete note comment

```http Endpoint
DELETE /api/v1/overlays/{overlayId}/notes/{noteId}/comments/{commentId}
```

DESTRUCTIVE: deletes a comment of a note (author or owner). Cannot be undone.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `delete_note_comment` · **Notes:** destructive, needs confirmation in MCP

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `noteId` | path | integer | required | Note id (from list_notes). At least 1 |
| `commentId` | path | integer | required | Comment id (from list_notes). At least 1 |

::: tabs
@@ cURL
```bash
curl -X DELETE "https://pxstudio.cloud/api/v1/overlays/<overlayId>/notes/<noteId>/comments/<commentId>" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const noteId = '<noteId>';
const commentId = '<commentId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/notes/${noteId}/comments/${commentId}`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### React to a note

```http Endpoint
PUT /api/v1/overlays/{overlayId}/notes/{noteId}/reactions
```

Sets your reaction to a note: 1 (thumbs up), -1 (thumbs down) or 0 (remove).

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `react_to_note`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `noteId` | path | integer | required | Note id (from list_notes). At least 1 |
| `value` | body | `1`, `0`, `-1` | required |  |

::: tabs
@@ cURL
```bash
curl -X PUT "https://pxstudio.cloud/api/v1/overlays/<overlayId>/notes/<noteId>/reactions" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "value": 1 }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const noteId = '<noteId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/notes/${noteId}/reactions`, {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ value: 1 }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Restore look scenes

```http Endpoint
POST /api/v1/overlays/{overlayId}/look-scenes/restore
```

Resets which layers are visible in each scene of a look preset overlay (Starting Soon, Live, BRB, Ending) to the look default. Changes the live scene on air if its visibility differs.

**Scope:** `scenes:write` (Edit scenes) · **MCP tool:** `restore_look_scenes`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/look-scenes/restore" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/look-scenes/restore`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### List templates

```http Endpoint
GET /api/v1/templates
```

Lists the quick-start overlay templates (use the id as template in create_overlay).

**Scope:** `overlays:read` (Read overlays) · **MCP tool:** `list_templates` · **Notes:** read only

::: tabs
@@ cURL
```bash
curl -X GET "https://pxstudio.cloud/api/v1/templates" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const res = await fetch('https://pxstudio.cloud/api/v1/templates', {
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Add a linked layer

```http Endpoint
POST /api/v1/overlays/{overlayId}/members/linked
```

Adds an existing widget setup from another overlay of the same owner as a linked layer: both layers share the same settings and state (e.g. one chat box on two overlays). Owner only. In the live scene the new layer shows up on air.

**Scope:** `members:write` (Add and remove layers) · **MCP tool:** `add_linked_member`

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `sourceOverlayId` | body | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `sourceMemberId` | body | integer | required | Layer (member) id (from get_overlay or list_members). At least 1 |
| `layout` | body | object | optional | Placement in design-space pixels (canvas 1920 wide): x/y move the layer from the canvas center, scale 0.05-4, rot in degrees, opacity 0-1, optional crop (cropL/cropT/cropR/cropB in native px) |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/members/linked" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "sourceOverlayId": "...", "sourceMemberId": 1 }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/members/linked`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ sourceOverlayId: "...", sourceMemberId: 1 }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### List OBS scene mappings

```http Endpoint
GET /api/v1/overlays/{overlayId}/obs-mappings
```

Lists which OBS scene switches the overlay to which scene (OBS sync), and the OBS scene name OBS reported last. Owner only.

**Scope:** `overlays:read` (Read overlays) · **MCP tool:** `list_obs_scene_mappings` · **Notes:** read only

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |

::: tabs
@@ cURL
```bash
curl -X GET "https://pxstudio.cloud/api/v1/overlays/<overlayId>/obs-mappings" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/obs-mappings`, {
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Map an OBS scene

```http Endpoint
POST /api/v1/overlays/{overlayId}/obs-mappings
```

ON AIR: from now on, when OBS switches to the OBS scene with this exact name, the overlay switches its live scene to sceneId by itself (OBS sync, up to 20 mappings). An existing mapping with the same name is replaced. Owner only.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `set_obs_scene_mapping` · **Notes:** destructive, needs confirmation in MCP

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `obsSceneName` | body | string | required | Up to 100 characters |
| `sceneId` | body | integer | required | Scene id (from list_scenes). At least 1 |

::: tabs
@@ cURL
```bash
curl -X POST "https://pxstudio.cloud/api/v1/overlays/<overlayId>/obs-mappings" \
  -H "Authorization: Bearer $PX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "obsSceneName": "...", "sceneId": 1 }'
```
@@ JavaScript
```js
const overlayId = '<overlayId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/obs-mappings`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ obsSceneName: "...", sceneId: 1 }),
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::

### Delete OBS scene mapping

```http Endpoint
DELETE /api/v1/overlays/{overlayId}/obs-mappings/{mappingId}
```

DESTRUCTIVE: removes an OBS scene mapping; OBS switching to that scene no longer switches the overlay. Owner only. Cannot be undone.

**Scope:** `overlays:write` (Design overlays) · **MCP tool:** `delete_obs_scene_mapping` · **Notes:** destructive, needs confirmation in MCP

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `overlayId` | path | string | required | Overlay id (from list_overlays). Up to 64 characters |
| `mappingId` | path | integer | required | Mapping id (from list_obs_scene_mappings). At least 1 |

::: tabs
@@ cURL
```bash
curl -X DELETE "https://pxstudio.cloud/api/v1/overlays/<overlayId>/obs-mappings/<mappingId>" \
  -H "Authorization: Bearer $PX_TOKEN"
```
@@ JavaScript
```js
const overlayId = '<overlayId>';
const mappingId = '<mappingId>';

const res = await fetch(`https://pxstudio.cloud/api/v1/overlays/${overlayId}/obs-mappings/${mappingId}`, {
  method: 'DELETE',
  headers: {
    Authorization: `Bearer ${process.env.PX_TOKEN}`,
  },
});
if (!res.ok) throw new Error(`PX Studio API: ${res.status}`);
const data = await res.json();
```
:::
