> ## 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.

# Presentation Generation

> Generate branded .pptx slides and decks from structured JSON, with template inheritance, layout controls, and custom formatting.

# Presentation Generation

Generation turns an analyzed template slide into a real `.pptx`. The template provides the visual system. Your request provides the content, the layout payload, and any overrides you want to apply.

<Note>
  Run [template analysis](/guides/template-management) first. Generation uses each slide's analyzed `slideId` as `template_slide_id`.
</Note>

## 1. Supported Layouts

Layouts describe how content is arranged on the slide. Your template should contain a slide that structurally matches one of these patterns.

| Layout                       | Payload shape                                            |
| ---------------------------- | -------------------------------------------------------- |
| **Title / text slide**       | `title`, `subtitle`, optional text blocks                |
| **Single table**             | One `table` block                                        |
| **Table + text**             | One `table` block plus one or more `text` blocks         |
| **Single chart**             | One `chart` block                                        |
| **Agenda**                   | One `agenda` block                                       |
| **Two-column table + chart** | `content` as two columns; one side table, one side chart |
| **Two-column table + table** | `content` as two columns; both sides table               |

Do not use a two-column `content` array for arbitrary layouts. The current renderer routes two-column content for table + chart and table + table layouts; chart + chart and text + text are not treated as distinct left/right content regions.

The sections below describe the content blocks used inside those layouts.

## 2. Content Blocks

Content blocks are the JSON objects placed inside `slide_data.content.blocks`. Use them to fill the matching regions in a template slide.

| Block    | Use it for                                                                          | Details                                          |
| -------- | ----------------------------------------------------------------------------------- | ------------------------------------------------ |
| `text`   | Section headers, paragraphs, bullets, and supporting copy                           | [Text Blocks](/guides/text-blocks)               |
| `table`  | Row-and-column data, logos, table styling, conditional formatting, and pagination   | [Table Blocks](/guides/table-blocks)             |
| `chart`  | Bar and column charts with categories, series, axes, legends, labels, and data rows | [Chart Blocks](/guides/chart-blocks)             |
| `agenda` | Agenda slides with section labels and an active section                             | [Slide Input](/guides/slide-input#agenda-blocks) |

For a single-column layout, `content` is one column object:

```json theme={"dark"}
{
  "content": {
    "blocks": [
      { "type": "text", "text": { "bullets": ["Point 1", "Point 2"] } }
    ]
  }
}
```

In a `text` block, `bullets` is an array of strings. Each string renders as one bullet paragraph in the matching text region.

For a two-column layout, `content` is an array of column objects. The optional column `header` is only used by two-column templates that include header textboxes marked `LHS_header` and `RHS_header`, where `LHS` means left-hand side and `RHS` means right-hand side.

```json theme={"dark"}
{
  "content": [
    {
      "header": "Renewal pipeline",
      "blocks": [
        { "type": "table", "table": { "table": { "rows": [] } } }
      ]
    },
    {
      "header": "ARR at risk",
      "blocks": [
        { "type": "chart", "chart": { "categories": [], "series": [] } }
      ]
    }
  ]
}
```

<CardGroup cols={3}>
  <Card title="Table Blocks" icon="table" href="/guides/table-blocks">
    Author table rows, dynamic columns, logos, reusable styles, conditional formatting, and pagination.
  </Card>

  <Card title="Chart Blocks" icon="chart-column" href="/guides/chart-blocks">
    Author bar and column charts with series, axes, legends, labels, and data rows.
  </Card>

  <Card title="Text Blocks" icon="text" href="/guides/text-blocks">
    Author slide text, text sections, bullets, and formatting overrides.
  </Card>
</CardGroup>

## 3. Template Inheritance

By default, generation inherits from the template. If you omit formatting fields, the renderer uses the fonts, sizes, colors, table styling, chart presets, placeholder positions, and master layouts already encoded in the `.pptx`.

Use overrides only where the generated content needs to differ from the template.

| If you send        | Result                                                                            |
| ------------------ | --------------------------------------------------------------------------------- |
| No formatting      | Template styling is used wherever available                                       |
| Partial formatting | Specified fields override; unspecified fields continue to inherit where supported |
| Full formatting    | Payload controls that element's font, size, color, emphasis, or cell styling      |

The common pattern is: let the template carry the brand, then override only data-driven styling such as status colors, risk flags, chart series colors, or one-off title sizing.

## 4. Generate Slides

There are two generation modes:

| Mode         | Endpoint                                   | Use when                                             |
| ------------ | ------------------------------------------ | ---------------------------------------------------- |
| Single slide | `POST /api/v1/presentations/generate`      | You need one logical slide generated as an async job |
| Deck         | `POST /api/v1/presentations/generate-deck` | You need multiple slides in one `.pptx`              |

Both modes use the same slide object shape:

```json theme={"dark"}
{
  "template_slide_id": "slide_a3f81c92",
  "slide_data": {},
  "options": {}
}
```

| Field               | What it controls                                        |
| ------------------- | ------------------------------------------------------- |
| `template_slide_id` | Which analyzed template slide to clone and populate     |
| `slide_data`        | The content and optional formatting for that slide      |
| `options`           | Pagination, font-fit, footer, and slide-number behavior |

For layout guidance, option fields, defaults, and deck inheritance rules, see [Layout & Rendering Controls](/guides/generation-options).

### What you can specify in `slide_data`

| Area             | Fields                                                                                                                                                                                                                                                                                  |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Slide text       | `title`, `subtitle`, `footer`, `footnote`                                                                                                                                                                                                                                               |
| Text blocks      | Single-column: `content.blocks[].text.{header,text,bullets}`. Two-column: `content[].blocks[].text.{header,text,bullets}`                                                                                                                                                               |
| Text formatting  | `slide_format.title`, `slide_format.subtitle`, `slide_format.body`, `slide_format.textbox.{header,text,bullets}`, plus text-block `header_format`, `text_format`, `bullets_format`                                                                                                      |
| Tables           | `rows`, `rows[].cells`, row `is_header`, cell `value`, cell `is_logo`, multi-paragraph or bullet cell values, `column_configs`                                                                                                                                                          |
| Table formatting | `table_format`, `format_templates`, `format_template` references from cells, paragraphs, or `column_configs[]`, conditional `rules`, text formatting, and cell formatting                                                                                                               |
| Charts           | Bar/column chart fields: `chart_type`, `categories`, `series[].{name,values,color}`, `title`, `title_format`, `legend`, `value_axis`, `category_axis`, `value_axis_unit`, `caption`, `show_bar_labels`, `show_data_table`, `data_rows`, `data_table_header_column`, `data_table_format` |
| Agenda           | `sections`, `active_index`, `active_font_color`, `active_bold`, `active_underline`                                                                                                                                                                                                      |

Formatting objects commonly accept:

```json theme={"dark"}
{
  "font_name": "Arial",
  "font_size": 12,
  "bold": true,
  "italic": false,
  "color": "#333333",
  "alignment": "left",
  "line_spacing": 1.2
}
```

## Generate One Slide

Use `generate` for one logical slide. The endpoint returns immediately with a `generation_id`; poll status until the generated file is ready.

<Accordion title="Single-slide request example">
  ```http theme={"dark"}
  POST /api/v1/presentations/generate
  X-API-Key: your-api-key
  Content-Type: application/json

  {
    "template_slide_id": "slide_customer_health_table",
    "slide_data": {
      "title": "Customer Health Overview",
      "footnote": "Source: CRM export, April 2026",
      "slide_format": {
        "title": {
          "font_name": "Arial",
          "font_size": 30,
          "bold": true,
          "color": "#111827"
        }
      },
      "content": {
        "blocks": [
          {
            "type": "table",
            "table": {
              "table": {
                "format_templates": {
                  "health_score": {
                    "rules": [
                      {
                        "condition": { "field": "value", "operator": "greater_than_or_equal", "value": 8 },
                        "cell": { "background_color": "#E7F4EE" },
                        "text": { "bold": true, "color": "#0F5132" }
                      },
                      {
                        "condition": { "field": "value", "operator": "less_than", "value": 6 },
                        "cell": { "background_color": "#FDECEC" },
                        "text": { "bold": true, "color": "#842029" }
                      }
                    ]
                  }
                },
                "column_configs": [
                  { "column_index": 2, "format_template": "health_score" }
                ],
                "rows": [
                  {
                    "is_header": true,
                    "cells": [
                      { "value": "Company" },
                      { "value": "Owner" },
                      { "value": "Health" },
                      { "value": "Signal" },
                      { "value": "Next step" }
                    ]
                  },
                  {
                    "cells": [
                      { "value": "stripe.com", "is_logo": true },
                      { "value": "Sarah Chen" },
                      { "value": "9" },
                      { "value": "Expansion-ready" },
                      { "value": "Send pricing proposal" }
                    ]
                  }
                ]
              }
            }
          }
        ]
      }
    },
    "options": {
      "auto_paginate_tables": true,
      "table_min_font_size": 8,
      "show_slide_numbers": true,
      "footer_text": "Confidential"
    }
  }
  ```
</Accordion>

Example response:

```json theme={"dark"}
{
  "generation_id": "gen_def456",
  "status": "pending",
  "message": "Generation started. Poll status URL for progress.",
  "status_url": "https://api.example.com/api/v1/presentations/gen_def456/status",
  "created_at": "2026-04-30T17:35:00Z"
}
```

The final status response includes `total_pages_generated`, `slide_results`, file size, and a signed `download_url`. `total_pages_generated` can be greater than `1` when a table-only slide paginates.

## Generate a Deck

Use `generate-deck` for multi-slide output. The endpoint returns immediately with a `generation_id`; poll status until the deck is ready.

Slides render in the same order as the `slides` array. Each slide can use a different `template_slide_id`, including slides from different analyzed templates in the same organization.

<Accordion title="Deck request example">
  ```http theme={"dark"}
  POST /api/v1/presentations/generate-deck
  X-API-Key: your-api-key
  Content-Type: application/json

  {
    "slides": [
      {
        "template_slide_id": "slide_cover",
        "slide_data": {
          "title": "Q2 2026 Portfolio Review",
          "subtitle": "Investment Committee Draft"
        }
      },
      {
        "template_slide_id": "slide_agenda",
        "slide_data": {
          "title": "Agenda",
          "content": {
            "blocks": [
              {
                "type": "agenda",
                "agenda": {
                  "sections": [
                    "Portfolio snapshot",
                    "Customer health",
                    "Renewal outlook",
                    "Action plan"
                  ],
                  "active_index": 1,
                  "active_bold": true,
                  "active_underline": true
                }
              }
            ]
          }
        }
      },
      {
        "template_slide_id": "slide_chart_and_table",
        "slide_data": {
          "title": "Renewal Outlook by Cohort",
          "content": [
            {
              "header": "ARR at risk",
              "blocks": [
                {
                  "type": "chart",
                  "chart": {
                    "chart_type": "stacked_column",
                    "categories": ["Q2", "Q3", "Q4"],
                    "series": [
                      { "name": "Committed", "values": [18.2, 21.4, 24.1], "color": "#0F766E" },
                      { "name": "Upside", "values": [4.5, 3.9, 5.2], "color": "#2563EB" },
                      { "name": "At risk", "values": [2.1, 3.4, 2.8], "color": "#DC2626" }
                    ],
                    "show_bar_labels": true,
                    "value_axis_unit": "$M",
                    "legend": {
                      "position": "bottom",
                      "text_format": { "font_size": 8 }
                    },
                    "data_rows": [
                      ["Total ARR", "$24.8M", "$28.7M", "$32.1M"],
                      ["At-risk %", "8%", "12%", "9%"]
                    ],
                    "data_table_format": {
                      "font_name": "Arial",
                      "font_size": 8,
                      "color": "#333333"
                    }
                  }
                }
              ]
            },
            {
              "header": "Management actions",
              "blocks": [
                {
                  "type": "table",
                  "table": {
                    "table": {
                      "table_format": {
                        "header_row": {
                          "text": { "bold": true, "font_size": 9 },
                          "cell": { "background_color": "#E5E7EB" }
                        },
                        "default": {
                          "text": { "font_size": 8 }
                        }
                      },
                      "rows": [
                        {
                          "is_header": true,
                          "cells": [
                            { "value": "Account group" },
                            { "value": "Action" },
                            { "value": "Owner" }
                          ]
                        },
                        {
                          "cells": [
                            { "value": "Executive sponsor gaps" },
                            { "value": "Schedule renewal risk review" },
                            { "value": "CS leadership" }
                          ]
                        },
                        {
                          "cells": [
                            { "value": "Q3 renewals" },
                            { "value": "Pull forward adoption readout" },
                            { "value": "Product strategy" }
                          ]
                        }
                      ]
                    }
                  }
                }
              ]
            }
          ]
        },
        "options": {
          "auto_paginate_tables": false,
          "table_min_font_size": 7,
          "textbox_min_font_size": 8
        }
      }
    ],
    "options": {
      "auto_paginate_tables": true,
      "show_slide_numbers": true,
      "footer_text": "Confidential",
      "footer_font_size": 8,
      "footer_font_name": "Arial",
      "table_min_font_size": 8,
      "textbox_min_font_size": 8
    }
  }
  ```
</Accordion>

Example response:

```json theme={"dark"}
{
  "generation_id": "gen_ghi789",
  "status": "pending",
  "message": "Generation started. Poll status URL for progress.",
  "status_url": "https://api.example.com/api/v1/presentations/gen_ghi789/status",
  "created_at": "2026-04-30T17:40:00Z"
}
```

## Poll Status

```http theme={"dark"}
GET /api/v1/presentations/{generation_id}/status
X-API-Key: your-api-key
```

Poll every 2 to 5 seconds until `status` is terminal.

| Status       | Meaning                               |
| ------------ | ------------------------------------- |
| `pending`    | Request is queued                     |
| `processing` | Slides are being rendered             |
| `completed`  | Every requested slide succeeded       |
| `partial`    | Some slides succeeded and some failed |
| `failed`     | No usable deck was generated          |

Completed example:

```json theme={"dark"}
{
  "generation_id": "gen_ghi789",
  "status": "completed",
  "progress": 100,
  "message": "Generated 4 pages from 3/3 slides",
  "total_slides_requested": 3,
  "total_pages_generated": 4,
  "slide_results": [
    { "slide_index": 0, "template_slide_id": "slide_cover", "pages_generated": 1, "status": "completed", "error": null },
    { "slide_index": 1, "template_slide_id": "slide_agenda", "pages_generated": 1, "status": "completed", "error": null },
    { "slide_index": 2, "template_slide_id": "slide_chart_and_table", "pages_generated": 2, "status": "completed", "error": null }
  ],
  "file_size": 7450000,
  "download_url": "https://storage.example.com/download/gen_ghi789.pptx?token=...",
  "download_url_expires_in": 3600
}
```

Always inspect `slide_results` for async deck jobs. A `partial` result can still include a downloadable `.pptx`.

## Download

Use the signed `download_url` when available. To download through the API instead:

```http theme={"dark"}
GET /api/v1/presentations/{presentation_id}/download
X-API-Key: your-api-key
```

`presentation_id` can be either:

* `gen_xxx` from slide generation
* `gen_xxx` from deck generation
* `pres_xxx` from older direct-return generation output, if present

For generation jobs, download is available after status is `completed` or `partial`.

## Page Counts and Indexes

Pagination can make output slide counts differ from request slide counts:

* `total_slides_requested` is the number of logical slides in the request.
* `total_pages_generated` is the number of actual PowerPoint slides in the output file.
* `slide_results[].pages_generated` tells you which logical slides expanded.
* Chart update `slide_index` values refer to the output presentation, so paginated table-only slides can shift later indexes.

## Related Guides

<CardGroup cols={3}>
  <Card title="Table Blocks" icon="table" href="/guides/table-blocks">
    Rows, cells, logos, reusable styles, conditional formatting, and pagination.
  </Card>

  <Card title="Chart Blocks" icon="chart-column" href="/guides/chart-blocks">
    Chart types, categories, series, legends, axes, labels, and data rows.
  </Card>

  <Card title="Text Blocks" icon="text" href="/guides/text-blocks">
    Slide text, text sections, bullets, and formatting overrides.
  </Card>

  <Card title="Slide Input" icon="brackets-curly" href="/guides/slide-input">
    Full JSON shapes for text, tables, charts, agendas, and formatting.
  </Card>

  <Card title="Layout & Rendering Controls" icon="sliders" href="/guides/generation-options">
    Layout compatibility, aspect ratio, pagination, fitting, footers, and slide numbers.
  </Card>

  <Card title="Examples" icon="copy" href="/guides/examples">
    Complete payloads for common slide and deck patterns.
  </Card>
</CardGroup>
