> ## Documentation Index
> Fetch the complete documentation index at: https://docs-slidekit.theduomi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Template management

> Upload your .pptx template, run analysis, and inspect what each slide accepts.

A template is the brand and structural contract for everything you generate — fonts, colours, table styles, chart presets, master layouts. The API never invents a look; it conforms to whatever your `.pptx` encodes. Upload it once, analyze it once, and reference it by ID on every generation request.

## Step 1: Prepare your template

Build the template in PowerPoint (or any tool that exports `.pptx`). A few things that help analysis identify slide structure cleanly:

* Tables with the right column count and a populated header row
* Charts with realistic sample categories and series
* Distinct master layouts for distinct page types (table-heavy pages, chart pages, agenda, dividers)
* Title placeholders on slides that should accept titles

The example used throughout this page is slide 1 of a small demo template — a single six-column table with a coloured header band:

<Frame caption="Demo template, slide 1 — six-column table with a header band">
  <img src="https://mintcdn.com/duomi/0eYM0n6_9GystnoS/images/template-management/example-template-slide1.png?fit=max&auto=format&n=0eYM0n6_9GystnoS&q=85&s=a81bd13cbf2c7b7d414d0b8cae7bd0b1" alt="Empty template slide with a teal/blue six-column header band." width="3600" height="2025" data-path="images/template-management/example-template-slide1.png" />
</Frame>

## Step 2: Upload

Two-step flow: the API returns a signed upload URL; you `PUT` the `.pptx` directly to storage; you confirm the upload.

### Initiate

```http theme={"dark"}
POST /api/v1/templates
X-API-Key: your-api-key
Content-Type: application/json

{
  "filename": "ic-memo-template.pptx",
  "file_size": 1048576,
  "metadata": {
    "category": "ic-memo",
    "tags": ["pe", "fund-1"],
    "description": "IC memo template for fund 1"
  }
}
```

```json theme={"dark"}
{
  "template_id": "tmpl_abc123",
  "upload_url": "https://storage.example.com/signed-url...",
  "expires_in": 3600,
  "status": "pending"
}
```

### Upload the file

`PUT` the `.pptx` bytes to `upload_url`. The bytes go directly to object storage; the API never sees them.

### Confirm

```http theme={"dark"}
POST /api/v1/templates/{template_id}/upload/confirm
X-API-Key: your-api-key
```

The service verifies the object exists and marks the template as uploaded.

## Step 3: Run analysis

```http theme={"dark"}
POST /api/v1/templates/{template_id}/analysis
X-API-Key: your-api-key
Content-Type: application/json

{
  "options": {
    "parse_master_template_layout": true,
    "parse_slides": true,
    "include_placeholder_positions": true,
    "include_table_details": true
  }
}
```

Analysis runs asynchronously; the response returns immediately with an `analysis_id` and `status: "processing"`.

## Step 4: Inspect the analysis output

Once analysis completes, fetch the results:

```http theme={"dark"}
GET /api/v1/templates/{template_id}/analysis
X-API-Key: your-api-key
```

The response wraps the parser output. The top-level structure:

```json theme={"dark"}
{
  "slides": [
    {
      "slideId": "slide_a3f81c92",
      "slideIndex": 0,
      "slideNumber": 1,
      "title": null,
      "dimension": { "width": 1440.0, "height": 810.0 },
      "shapes": [ /* one entry per shape on the slide */ ]
    },
    {
      "slideId": "slide_7e2bd445",
      "slideIndex": 1,
      "slideNumber": 2,
      "title": null,
      "dimension": { "width": 1440.0, "height": 810.0 },
      "shapes": [ /* ... */ ]
    }
  ]
}
```

**Each slide gets its own `slideId`** (assigned during analysis, stable across reads). Generation requests target slides by `slideId`, not by template — which means a single deck can mix slides from multiple templates by referencing each one's `slideId`. `slideIndex` (0-based) and `slideNumber` (1-based, matches PowerPoint's slide number) are also available if you need ordering.

Each entry in `shapes` has a common set of fields, plus type-specific extras keyed off `shape_type`. The rest of this section walks through each shape type with a real excerpt from the parser running against slide 1 of the demo template above.

### Common fields (every shape)

```json theme={"dark"}
{
  "is_placeholder": true,
  "placeholder_type": "SLIDE_NUMBER",
  "placeholder_index": 13,
  "shape_type": "AutoShape",
  "name": "Slide Number Placeholder 1",
  "text": "1",
  "x": 1363.0147705078125,
  "y": 772.1712036132812,
  "width": 76.98519897460938,
  "height": 29.77204704284668
}
```

| Field                       | Meaning                                                         |
| --------------------------- | --------------------------------------------------------------- |
| `shape_type`                | `AutoShape`, `Table`, `Chart`, `OleObjectFrame`, etc.           |
| `name`                      | The shape's name as set in PowerPoint                           |
| `is_placeholder`            | `true` if the shape is a master-layout placeholder              |
| `placeholder_type`          | `TITLE`, `BODY`, `SLIDE_NUMBER`, etc. (or `null`)               |
| `placeholder_index`         | Index that ties the shape to its master-layout slot (or `null`) |
| `text`                      | Current text on the shape (often `""` for an unfilled template) |
| `x`, `y`, `width`, `height` | Position and size in points                                     |

### Placeholder shapes (TITLE, BODY, SLIDE\_NUMBER)

Adds `text_format`, describing the font the template uses for that placeholder.

```json theme={"dark"}
{
  "is_placeholder": true,
  "placeholder_type": "TITLE",
  "placeholder_index": 0,
  "shape_type": "AutoShape",
  "name": "Title 2",
  "text": "",
  "x": 66.0,
  "y": 64.91110229492188,
  "width": 1242.0,
  "height": 48.0,
  "text_format": {
    "font_color": { "r": 44, "g": 44, "b": 44 },
    "font_size": 33.75,
    "font_name": "Arial",
    "bold": true,
    "italic": false
  }
}
```

The `text_format` block tells you what the title (or body, etc.) will look like once populated — the same font and colour the template's master layout encodes.

### Table shapes

Adds `table_rows` / `table_columns`, plus `table_info` (dimensions, style preset, six PowerPoint table-style flags) and `table_styling` (per-cell formatting for the header and body rows).

```json theme={"dark"}
{
  "shape_type": "Table",
  "name": "Table 4",
  "x": 66.0,
  "y": 140.69583129882812,
  "width": 1298.1602783203125,
  "height": 52.39228439331055,
  "table_rows": 1,
  "table_columns": 6,
  "table_info": {
    "rows": 1,
    "columns": 6,
    "width": 1298.1602783203125,
    "height": 52.39228439331055,
    "style_preset": "TableStylePreset.MEDIUM_STYLE_2_ACCENT_1",
    "has_first_row": false,
    "has_last_row": false,
    "has_first_col": false,
    "has_last_col": false,
    "horizontal_banding": false,
    "vertical_banding": false
  },
  "table_styling": {
    "header_row_format": [
      {
        "fill_type": "FillType.SOLID",
        "fill_color": { "r": 204, "g": 0, "b": 0 },
        "transparency": 0.0,
        "borders": {
          "left":   { "width": 2.25, "color": { "r": 255, "g": 255, "b": 255 }, "style": "LineStyle.SINGLE" },
          "top":    { "width": 2.25, "color": { "r": 255, "g": 255, "b": 255 }, "style": "LineStyle.SINGLE" },
          "right":  { "width": 2.25, "color": { "r": 255, "g": 255, "b": 255 }, "style": "LineStyle.SINGLE" },
          "bottom": { "width": 2.25, "color": { "r": 255, "g": 255, "b": 255 }, "style": "LineStyle.SINGLE" },
          "diagonal_down": { "width": null, "color": null, "style": "LineStyle.NOT_DEFINED" },
          "diagonal_up":   { "width": null, "color": null, "style": "LineStyle.NOT_DEFINED" }
        }
      }
    ],
    "body_row_format": [],
    "header_text_format": [
      { "font_color": { "r": 255, "g": 255, "b": 255 }, "font_size": 14.0, "font_name": "Arial", "bold": true, "italic": false, "alignment": "center" }
    ],
    "body_text_format": []
  }
}
```

The example shows one entry in each per-cell array; the real response has one entry per column (six entries, mostly identical). Each border block also includes `diagonal_down` and `diagonal_up` (typically `LineStyle.NOT_DEFINED` for tables that don't use diagonals).

`table_styling` arrays:

| Array                | What it contains                                                                                               |
| -------------------- | -------------------------------------------------------------------------------------------------------------- |
| `header_row_format`  | One entry per column of the header row: fill type, fill colour, transparency, and four borders + two diagonals |
| `header_text_format` | One entry per column of the header row: font name, size, colour, bold/italic, alignment                        |
| `body_row_format`    | Same shape as `header_row_format`, for body rows; empty when the template has no populated body row            |
| `body_text_format`   | Same shape as `header_text_format`, for body rows                                                              |

#### Table-style flags

The six boolean flags inside `table_info` mirror PowerPoint's "Table Tools → Design → Table Style Options" checkboxes. They control whether the applied **style preset** (e.g. `MEDIUM_STYLE_2_ACCENT_1`) emphasizes certain rows or columns:

| Flag                 | PowerPoint checkbox | Effect when `true`                            |
| -------------------- | ------------------- | --------------------------------------------- |
| `has_first_row`      | Header Row          | First row gets the style's header formatting  |
| `has_last_row`       | Total Row           | Last row gets the style's "totals" formatting |
| `has_first_col`      | First Column        | First column gets emphasized formatting       |
| `has_last_col`       | Last Column         | Last column gets emphasized formatting        |
| `horizontal_banding` | Banded Rows         | Alternating row colours from the style        |
| `vertical_banding`   | Banded Columns      | Alternating column colours from the style     |

These flags are independent of the cell-level formatting in `header_row_format` / `header_text_format`. In the example above all six are `false` because the header band is styled directly on each cell, not via the style preset.

### Chart shapes

Charts return only the common shape fields — position, name, `shape_type: "Chart"`. Example from a chart slide elsewhere in the same template:

```json theme={"dark"}
{
  "is_placeholder": false,
  "placeholder_type": null,
  "placeholder_index": null,
  "shape_type": "Chart",
  "name": "Chart 4",
  "text": "",
  "x": 66.0,
  "y": 171.47369384765625,
  "width": 1242.0,
  "height": 553.6691284179688
}
```

The chart's internal structure (categories, series, preset) lives inside the `.pptx` itself; generation requests reference the chart by its slide's identifier and supply the data to populate it. See the [chart guides](/guides/chart-updates) for how to fill or refresh a chart.

### Text-marker shapes (AutoShape placeholders)

Templates also use a second placeholder pattern: regular `AutoShape` shapes whose `text` field holds a recognized marker string. The API identifies these by their `text` value and swaps in the real content from the request payload. Common markers in the demo template: `LHS_header`, `RHS_header`, `Bullet_placeholder`, `Text_placeholder`.

These have `is_placeholder: false` and `placeholder_type: null` (PowerPoint doesn't classify them as native placeholders) but functionally they are content slots.

```json theme={"dark"}
{
  "is_placeholder": false,
  "placeholder_type": null,
  "placeholder_index": null,
  "shape_type": "AutoShape",
  "name": "Rectangle 14",
  "text": "LHS_header",
  "x": 66.0,
  "y": 164.58921813964844,
  "width": 605.142822265625,
  "height": 48.2400016784668
}
```

The distinction:

| Shape                         | Identifier the API uses                                 |
| ----------------------------- | ------------------------------------------------------- |
| Native PowerPoint placeholder | `placeholder_type` (`TITLE`, `BODY`, etc.)              |
| Text-marker AutoShape         | `text` value (`LHS_header`, etc.)                       |
| Decorative AutoShape          | None — has `text: ""` and is ignored at generation time |

### Authoring-tool artifacts

`OleObjectFrame` shapes are embedded objects from authoring tools, most commonly think-cell. They appear on every slide in templates built with such tools and don't carry generatable content.

```json theme={"dark"}
{
  "is_placeholder": false,
  "placeholder_type": null,
  "placeholder_index": null,
  "shape_type": "OleObjectFrame",
  "name": "think-cell data - do not delete",
  "text": "",
  "x": 0.12503936886787415,
  "y": 0.12503936886787415,
  "width": 0.09661417454481125,
  "height": 0.12503936886787415
}
```

The parser returns these as-is for completeness. Safe to ignore.

## Step 5: Use it for generation

Generation requests reference slides by `slideId`. Because IDs are per-slide, a single deck can pull slides from multiple templates — useful for assembling pitch books, IC memos, or LP updates that combine standard cover/agenda slides from one template with content slides from another.

```json theme={"dark"}
{
  "slides": [
    { "template_slide_id": "slide_a3f81c92", "slide_data": { /* ... */ } },
    { "template_slide_id": "slide_b1f9e2d7", "slide_data": { /* ... */ } },
    { "template_slide_id": "slide_c4d20af8", "slide_data": { /* ... */ } }
  ]
}
```

See [Slide input](/guides/slide-input) for how to map your data onto each slide's analysis structure, and [Examples](/guides/examples) for copy-paste payloads against common slide shapes.

## Maintenance

### Template lifecycle

| Action                                               | Endpoint                              |
| ---------------------------------------------------- | ------------------------------------- |
| List templates                                       | `GET /api/v1/templates`               |
| Get template details and the latest analysis summary | `GET /api/v1/templates/{id}`          |
| Download the original `.pptx`                        | `GET /api/v1/templates/{id}/download` |
| Update template metadata (name, tags, description)   | `PATCH /api/v1/templates/{id}`        |
| Soft-delete a template                               | `DELETE /api/v1/templates/{id}`       |
| Restore a soft-deleted template                      | `POST /api/v1/templates/{id}/restore` |

### Analysis

| Action                                                                      | Endpoint                                               |
| --------------------------------------------------------------------------- | ------------------------------------------------------ |
| Re-run analysis (e.g. after parser updates, or to refresh with new options) | `POST /api/v1/templates/{id}/analysis`                 |
| Check analysis status (lightweight, no full payload)                        | `GET /api/v1/templates/{id}/analysis/status`           |
| Get the full analysis results                                               | `GET /api/v1/templates/{id}/analysis`                  |
| Cancel a running analysis                                                   | `DELETE /api/v1/templates/{id}/analysis/{analysis_id}` |

### Slides

| Action                                              | Endpoint                                                   |
| --------------------------------------------------- | ---------------------------------------------------------- |
| Get a specific slide's analysis (by `slide_number`) | `GET /api/v1/templates/{id}/slides/{slide_number}`         |
| Render a slide as a PNG preview                     | `GET /api/v1/templates/{id}/slides/{slide_number}/preview` |

The slide preview endpoint is useful when an agent or app wants to show the user a thumbnail of the template slide they're about to populate.

### Updating templates

There is no endpoint to overwrite a template's `.pptx` bytes. If you change the underlying file, upload it as a **new** template (new `template_id`) — generations reference templates by ID and the analysis is tied to the file that was uploaded. The `PATCH` endpoint only updates metadata (name, tags, description), not the file itself.

<Tip>
  Looking for the endpoint that picks the best-fit slide for a given input shape? That's `POST /api/v1/templates/match`, documented under [Slide input](/guides/slide-input) since it's part of composing a generation request rather than maintaining a template.
</Tip>
