# Catalog and prices

> The catalog of styles and montage settings, export presets, operation prices before starting and the OpenAPI spec — endpoints open to any token.

Source: https://docs.slicer.media/en/api/reference/catalog/

The catalog is the same one the Slicer apps use: templates, fonts, accent colors, caption designs, montage settings, direction, durations, material limits and prices. Titles and descriptions come in Russian and English. The catalog rarely changes and is worth caching.

## Styles, settings and prices

`GET /v1/styles`

- **Scopes:** any token
- **Rate limit:** default

### Request

**curl**

```bash
curl "https://api.slicer.media/v1/styles" \
  -H "Authorization: Bearer $SLICER_TOKEN"
```

**JavaScript**

```js
const response = await fetch('https://api.slicer.media/v1/styles', {
  headers: {
    Authorization: `Bearer ${process.env.SLICER_TOKEN}`,
  },
});
const { ok, data, error } = await response.json();
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://api.slicer.media/v1/styles",
    headers={"Authorization": f"Bearer {os.environ['SLICER_TOKEN']}"},
)
body = response.json()
```

### Response

**Response fields: `Styles` (15)**

| Field | Type | Description |
| --- | --- | --- |
| `templates` _(required)_ | `object[]` |     |
| `templates[].id` _(required)_ | `string` |     |
| `fonts` _(required)_ | `object[]` |     |
| `fonts[].id` _(required)_ | `string` |     |
| `colors` _(required)_ | `object[]` |     |
| `colors[].id` _(required)_ | `string` |     |
| `subtitleDesigns` _(required)_ | `object[]` |     |
| `subtitleDesigns[].id` _(required)_ | `string` |     |
| `subtitleOptions` | `object[]` | Caption options (word highlight, entrance, words on screen, letter case) with their values |
| `subtitleOptions[].id` _(required)_ | `string` |     |
| `params` _(required)_ | `object[]` |     |
| `params[].id` _(required)_ | `string` |     |
| `direction` _(required)_ | `object` |     |
| `defaults` _(required)_ | `object` |     |
| `pricing` _(required)_ | `object` |     |

Response example:

```json
{
  "ok": true,
  "data": {
    "templates": [
      {
        "id": "string"
      }
    ],
    "fonts": [
      {
        "id": "string"
      }
    ],
    "colors": [
      {
        "id": "string"
      }
    ],
    "subtitleDesigns": [
      {
        "id": "string"
      }
    ],
    "subtitleOptions": [
      {
        "id": "string"
      }
    ],
    "params": [
      {
        "id": "string"
      }
    ],
    "direction": {},
    "defaults": {},
    "pricing": {}
  }
}
```

## Export presets and the default profile

`GET /v1/export-presets`

- **Scopes:** any token
- **Rate limit:** default

### Request

**curl**

```bash
curl "https://api.slicer.media/v1/export-presets" \
  -H "Authorization: Bearer $SLICER_TOKEN"
```

**JavaScript**

```js
const response = await fetch('https://api.slicer.media/v1/export-presets', {
  headers: {
    Authorization: `Bearer ${process.env.SLICER_TOKEN}`,
  },
});
const { ok, data, error } = await response.json();
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://api.slicer.media/v1/export-presets",
    headers={"Authorization": f"Bearer {os.environ['SLICER_TOKEN']}"},
)
body = response.json()
```

### Response

**Response fields: `object` (4)**

| Field | Type | Description |
| --- | --- | --- |
| `defaultProfile` _(required)_ | `ExportProfile` |     |
| `presets` _(required)_ | `object[]` |     |
| `presets[].id` _(required)_ | `string` |     |
| `presets[].profile` _(required)_ | `ExportProfile` |     |

Response example:

```json
{
  "ok": true,
  "data": {
    "defaultProfile": {
      "container": "mp4",
      "codec": "h264",
      "resolution": "720p",
      "fps": 24,
      "quality": "balanced",
      "colorDepth": 8,
      "audioBitrate": 128,
      "loudness": -14
    },
    "presets": [
      {
        "id": "string",
        "profile": {
          "container": "mp4",
          "codec": "h264",
          "resolution": "720p",
          "fps": null,
          "quality": "balanced",
          "colorDepth": null,
          "audioBitrate": null,
          "loudness": null
        }
      }
    ]
  }
}
```

## Price of an operation

`POST /v1/estimate`

- **Scopes:** any token
- **Rate limit:** default

### Request body `EstimateRequest`

| Field | Type | Description |
| --- | --- | --- |
| `kind` _(required)_ | `string` | — `montage` · `remount` · `retry` · `assistant` · `translate` · `transcribe` |
| `projectId` | `integer` | For retry and transcribe |

### Request

**curl**

```bash
curl -X POST "https://api.slicer.media/v1/estimate" \
  -H "Authorization: Bearer $SLICER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"kind":"montage"}'
```

**JavaScript**

```js
const response = await fetch('https://api.slicer.media/v1/estimate', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.SLICER_TOKEN}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "kind": "montage"
  }),
});
const { ok, data, error } = await response.json();
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://api.slicer.media/v1/estimate",
    headers={"Authorization": f"Bearer {os.environ['SLICER_TOKEN']}"},
    json={
        "kind": "montage",
    },
)
body = response.json()
```

### Response

**Response fields: `Quote` (8)**

| Field | Type | Description |
| --- | --- | --- |
| `status` _(required)_ | `"quote"` |     |
| `cost` _(required)_ | `integer` | Price in tokens; repeat the request with `confirmCost` equal to it. For an operation at cost (`atCost`) — the maximum: the actual cost is charged, never more |
| `free` _(required)_ | `boolean` | The operation is free (first video, free retry) |
| `estimate` | `number` | Operation at cost: expected price in tokens (fractional) |
| `atCost` | `boolean` | Priced at the AI providers’ cost, no markup: the wallet is charged the actual cost, at most `cost` |
| `available` _(required)_ | `integer` | Tokens available now |
| `enough` _(required)_ | `boolean` | Enough tokens to run |
| `spendLimitLeft` _(required)_ | `integer \| null` | What is left of the token's monthly spend limit; `null` — no limit |

Response example:

```json
{
  "ok": true,
  "data": {
    "status": "quote",
    "cost": 24,
    "free": true,
    "estimate": 1.5,
    "atCost": true,
    "available": 240,
    "enough": true,
    "spendLimitLeft": 200
  }
}
```

## This specification (OpenAPI 3.1)

`GET /v1/openapi.json`

- **Scopes:** no token
- **Rate limit:** default

### Request

**curl**

```bash
curl "https://api.slicer.media/v1/openapi.json"
```

**JavaScript**

```js
const response = await fetch('https://api.slicer.media/v1/openapi.json');
const { ok, data, error } = await response.json();
```

**Python**

```python
import requests

response = requests.get(
    "https://api.slicer.media/v1/openapi.json",
)
body = response.json()
```

### Response

The response body is described on this page.

## Schemas

`Styles` — Same catalog as the apps use: ids, titles (ru/en), descriptions, defaults and prices

| Field | Type | Description |
| --- | --- | --- |
| `templates` _(required)_ | `object[]` |     |
| `templates[].id` _(required)_ | `string` |     |
| `fonts` _(required)_ | `object[]` |     |
| `fonts[].id` _(required)_ | `string` |     |
| `colors` _(required)_ | `object[]` |     |
| `colors[].id` _(required)_ | `string` |     |
| `subtitleDesigns` _(required)_ | `object[]` |     |
| `subtitleDesigns[].id` _(required)_ | `string` |     |
| `subtitleOptions` | `object[]` | Caption options (word highlight, entrance, words on screen, letter case) with their values |
| `subtitleOptions[].id` _(required)_ | `string` |     |
| `params` _(required)_ | `object[]` |     |
| `params[].id` _(required)_ | `string` |     |
| `direction` _(required)_ | `object` |     |
| `defaults` _(required)_ | `object` |     |
| `pricing` _(required)_ | `object` |     |

`MontageSettingsInput` — Any subset of montage settings; missing values — defaults, unknown ids — defaults

| Field | Type | Description |
| --- | --- | --- |
| `templateId` | `string` | Template: `bold`, `clean`, `pop` |
| `fontId` | `string` | Caption font: punch, poster, block, wide, editorial, rounded, script, mono |
| `colorId` | `string` | Accent: amber, azure, lime, crimson, fuchsia, mint, violet, white |
| `subtitles` | `object` | Caption look; a partial change keeps the other fields. A new `design` without `highlight`/`animation`/`words` resets them to `auto` |
| `subtitles.enabled` | `boolean` |     |
| `subtitles.design` | `string` | — `dynamic` · `karaoke` · `classic` · `minimal` · `pop` · `box` · `word` |
| `subtitles.size` | `string` | — `small` · `medium` · `large` |
| `subtitles.position` | `string` | `auto` — each phrase where the frame has the most free space (off the face, hook, plaques, titles) — `auto` · `top` · `center` · `bottom` |
| `subtitles.speakerColors` | `boolean` | Each speaker in its own colour |
| `subtitles.highlight` | `string` | The spoken word: colour, pop (grows), box, underline; `auto` — as the design intends — `auto` · `none` · `color` · `pop` · `box` · `underline` |
| `subtitles.animation` | `string` | Phrase entrance; `words` — word by word as spoken — `auto` · `none` · `fade` · `pop` · `slide` · `words` |
| `subtitles.words` | `string` | Words on screen at once — `auto` · `one` · `few` · `line` · `phrase` |
| `subtitles.letterCase` | `string` | Letter case; `auto` — as the font intends — `auto` · `upper` · `normal` |
| `params` | `object` | Montage parameters, see `GET /v1/styles` → `params` |
| `params.emoji` | `boolean` |     |
| `params.soundEffects` | `boolean` |     |
| `params.mediaCards` | `boolean` |     |
| `params.plaques` | `boolean` |     |
| `params.cameraMotion` | `boolean` |     |
| `params.introZoom` | `boolean` |     |
| `params.hook` | `boolean` |     |
| `smartCut` | `boolean` | Smart cut: remove pauses and retakes |
| `targetDurationSec` | `15 \| 30 \| 60 \| 90 \| null` | Target length; `null` — AI decides (up to 90 s) |
| `language` | `string` | — `auto` · `ru` · `en` |
| `direction` | `object` |     |
| `direction.mode` | `string` | — `auto` · `talking` · `story` · `product` · `aesthetic` |
| `direction.pace` | `string` | — `calm` · `balanced` · `dynamic` |
| `direction.effects` | `string` | — `off` · `light` · `bold` |
| `direction.narration` | `boolean` | AI voiceover |
| `direction.voice` | `string` | — `warm` · `soft` · `confident` · `deep` |

`ExportProfile`

| Field | Type | Description |
| --- | --- | --- |
| `container` | `string` | — `mp4` · `mov` |
| `codec` | `string` | — `h264` · `hevc` |
| `resolution` | `string` | — `720p` · `1080p` · `1440p` · `2160p` |
| `fps` | `24 \| 25 \| 30` |     |
| `quality` | `string` | — `balanced` · `high` · `max` |
| `colorDepth` | `8 \| 10` | 10-bit only with HEVC |
| `audioBitrate` | `128 \| 192 \| 256 \| 320` |     |
| `loudness` | `-14 \| -16 \| -23` | Target loudness, LUFS |

`Quote`

| Field | Type | Description |
| --- | --- | --- |
| `status` _(required)_ | `"quote"` |     |
| `cost` _(required)_ | `integer` | Price in tokens; repeat the request with `confirmCost` equal to it. For an operation at cost (`atCost`) — the maximum: the actual cost is charged, never more |
| `free` _(required)_ | `boolean` | The operation is free (first video, free retry) |
| `estimate` | `number` | Operation at cost: expected price in tokens (fractional) |
| `atCost` | `boolean` | Priced at the AI providers’ cost, no markup: the wallet is charged the actual cost, at most `cost` |
| `available` _(required)_ | `integer` | Tokens available now |
| `enough` _(required)_ | `boolean` | Enough tokens to run |
| `spendLimitLeft` _(required)_ | `integer \| null` | What is left of the token's monthly spend limit; `null` — no limit |
