API Reference

Use the BankOps.ai REST API to create and update presentations programmatically. External agents and scripts can authenticate with a Bearer token and manage presentation content via JSON.

01

Authentication

All API requests require authentication. Obtain a JWT token by calling the login endpoint, then include it as a Bearer token in subsequent requests.

POST/api/auth/loginAuthenticate and receive a JWT token.
Request
{
  "username": "your_username",
  "password": "your_password"
}
Response (200)
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": {
    "id": "uuid",
    "username": "your_username"
  },
  "org": {
    "id": "uuid",
    "name": "A-1 Investment Bank"
  }
}

Using the token

Include the token in all subsequent requests:

Authorization: Bearer <token>

Tokens expire after 7 days. Browser clients can also use the httpOnly cookie set during login.

02

Get Presentation

Retrieve a presentation by ID, including its content JSON. The presentation must belong to your organization.

GET/api/presentations/:idFetch presentation metadata and content.
Response (200)
{
  "presentation": {
    "id": "bde47f40-c324-4624-af2a-5a779c6c7d10",
    "orgId": "...",
    "title": "Quarterly Review",
    "content": {
      "style": "corporate",
      "slides": [...]
    },
    "createdAt": "2026-02-19T00:00:00.000Z",
    "updatedAt": "2026-02-19T00:00:00.000Z"
  }
}

The content field is null until a deck JSON is submitted via PATCH.

03

Update Presentation

Update a presentation's content and/or title. Uses PATCH semantics — only provided fields are updated.

PATCH/api/presentations/:idUpdate presentation content or title.
Request
{
  "title": "AI Strategy Deck",
  "content": {
    "style": "corporate",
    "slides": [
      {
        "type": "title",
        "title": "AI Strategy",
        "subtitle": "Q1 2026"
      },
      {
        "type": "grid",
        "title": "Key Metrics",
        "body": {
          "direction": "row",
          "children": [...]
        }
      }
    ]
  }
}
Response (200)
{
  "presentation": {
    "id": "bde47f40-...",
    "title": "AI Strategy Deck",
    "content": {
      "style": "corporate",
      "slides": [...]
    },
    "createdAt": "...",
    "updatedAt": "..."
  }
}

Request Fields

FieldTypeRequiredDescription
contentobjectNoFull deck JSON (see schema below)
titlestringNoPresentation title

At least one field must be provided.

04

Error Responses

StatusBodyCause
401{ "error": "Not authenticated." }Missing or invalid token
404{ "error": "Presentation not found." }Wrong ID or different org
400{ "error": "..." }Validation error
05

Presentation JSON Schema

The content field stores a deck JSON object. Below is the complete schema reference. You can also download the raw file: schema.md

schema.md — Full Deck JSON ReferenceDownload
# PPTX SDK — LLM Reference

You are generating JSON that will be converted into PowerPoint (.pptx) presentations. Follow this reference exactly. Every property name, nesting level, and type matters.

---

## Deck Structure

```json
{
  "style": "corporate",
  "slideSize": { "width": 13.333, "height": 7.5 },
  "slides": [ ... ]
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `style` | `string` or `object` | `"corporate"` | Style preset name or inline style object |
| `slideSize` | `{ width, height }` | `{ 10, 7.5 }` | Slide dimensions in inches |
| `slides` | `array` | required | Array of slide definitions |

### Style Presets

| Name | Look | Best For |
|---|---|---|
| `"corporate"` | White bg, dark text, blue accent (#4472C4), Arial/Calibri | Investment banking, finance, formal presentations |
| `"minimal"` | White bg, blue accent (#2980b9), Helvetica Neue | Clean tech pitches, product decks |
| `"dark"` | Dark bg (#1a1a2e), red accent (#E94560), light text | Executive keynotes, dramatic impact |
| `"warm"` | White bg, terracotta accent (#D57F5B), Georgia/Garamond | Creative briefs, editorial presentations |

---

## Slide Types

### Title Slide

```json
{ "type": "title", "title": "Presentation Title", "subtitle": "February 2026" }
```

### Grid Slide (Inline Body)

```json
{
  "type": "grid",
  "title": "Slide Title",
  "sectionLabel": "SECTION NAME",
  "footer": "Source: Company data",
  "body": { ... }
}
```

| Property | Type | Required | Description |
|---|---|---|---|
| `title` | `string` | no | Main heading at top |
| `sectionLabel` | `string` | no | Eyebrow text above title (e.g. section name) |
| `footer` | `string` | no | Footnote at bottom |
| `body` | `object` | yes | Layout tree (see Grid Layout below) |

### Grid Slide (Template Reference)

```json
{
  "type": "grid",
  "title": "Override Title",
  "$template": "templateName",
  "$templateData": { ... }
}
```

Top-level `title`, `sectionLabel`, and `footer` override whatever the template returns.

---

## Grid Layout System

The layout engine uses a 12-column nested grid (like Bootstrap/MUI). Every node is either a **leaf** (has `content`) or a **container** (has `children`).

### Layout Node

```json
{
  "span": 6,
  "direction": "row",
  "gap": 0.15,
  "padding": 0.1,
  "background": "#F5F0EB",
  "border": "#999999",
  "header": "Panel Header",
  "subheader": "Sub-section",
  "subfooter": "Source note",
  "children": [ ... ],
  "content": { ... }
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `span` | `number` (1-12) | equal split | Column weight in parent's 12-column grid |
| `direction` | `"row"` or `"col"` | `"row"` | Stack children horizontally or vertically |
| `gap` | `number` | 0.15 | Gap between children (inches) |
| `padding` | `number` | 0 | Inner padding (inches) |
| `background` | `string` | none | Fill color for this zone |
| `border` | `string` | none | Border color |
| `header` | `string` | none | Dark bar with white text above content |
| `subheader` | `string` | none | Smaller text label with underline above content |
| `subfooter` | `string` | none | Small italic text below content |
| `children` | `array` | — | Child layout nodes (container mode) |
| `content` | `object` | — | Content object (leaf mode) |

**Rules:**
- A node has EITHER `children` OR `content`, never both.
- `span` values in sibling nodes should sum to 12 for balanced layouts, but the engine handles any sum.
- Nesting depth is unlimited. Use `direction: "col"` for vertical stacking and `direction: "row"` for horizontal.

### Common Grid Patterns

**Two equal columns:**
```json
{ "direction": "row", "children": [{ "span": 6, "content": ... }, { "span": 6, "content": ... }] }
```

**Sidebar layout (wide left, narrow right):**
```json
{ "direction": "row", "children": [{ "span": 8, "content": ... }, { "span": 4, "content": ... }] }
```

**Top bar + main content:**
```json
{ "direction": "col", "children": [{ "span": 3, "content": ... }, { "span": 9, "content": ... }] }
```

**KPI row + two-panel bottom:**
```json
{
  "direction": "col", "children": [
    { "span": 3, "direction": "row", "children": [
      { "content": ... }, { "content": ... }, { "content": ... }
    ]},
    { "span": 9, "direction": "row", "children": [
      { "span": 8, "content": ... }, { "span": 4, "content": ... }
    ]}
  ]
}
```

---

## Content Types

Every leaf node's `content` must have a `type` field. Here are all 11 content types:

### `text`

Plain text block. Use for paragraphs, subtitles, large numbers, labels.

```json
{
  "type": "text",
  "text": "Your text here",
  "font": "Arial",
  "fontSize": 1400,
  "color": "#333333",
  "bold": true,
  "align": "l",
  "anchor": "t"
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `text` | `string` | required | The text content (supports `\n` for line breaks) |
| `font` | `string` | style default | Font family |
| `fontSize` | `number` | style default | Font size in hundredths of a point (1400 = 14pt) |
| `color` | `string` | style default | Hex color |
| `bold` | `boolean` | `false` | Bold text |
| `align` | `"l"`, `"ctr"`, `"r"` | `"l"` | Horizontal alignment |
| `anchor` | `"t"`, `"ctr"`, `"b"` | `"t"` | Vertical alignment within bounds |

**When to use:** Section subtitles, large section numbers, descriptive paragraphs, labels, any free-form text.

### `bulletList`

Bulleted list of items. Use for key points, features, takeaways.

```json
{
  "type": "bulletList",
  "items": ["First point", "Second point", "Third point"],
  "fontSize": 1200,
  "color": "#333333",
  "font": "Calibri",
  "lineSpacing": "single"
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `items` | `string[]` | required | Array of bullet point strings |
| `fontSize` | `number` | style default | Font size (hundredths of a point) |
| `color` | `string` | style default | Text color |
| `font` | `string` | style default | Font family |
| `lineSpacing` | `"single"` or `null` | `null` | `"single"` = tight spacing, `null` = normal spacing |

**When to use:** Key takeaways, feature lists, supporting arguments, analysis points. The most common content type for text-heavy slides.

### `statGrid`

KPI/metric display. Large value with smaller label underneath. Auto-arranges in grid.

```json
{
  "type": "statGrid",
  "items": [
    { "value": "$680M", "label": "Annual Revenue", "sublabel": "+12% YoY" },
    { "value": "64%", "label": "Gross Margin" },
    { "value": "4,820", "label": "Customers" }
  ]
}
```

| Property | Type | Description |
|---|---|---|
| `items[].value` | `string` | Large display value (e.g. "$680M", "64%", "4.2x") |
| `items[].label` | `string` | Descriptor below the value |
| `items[].sublabel` | `string?` | Optional tertiary line (e.g. growth rate) |

Layout: 1 item = 1 col, 2 = 2 cols, 3-4 = 2 cols, 5+ = 3 cols. Rows auto-wrap.

**When to use:** KPI dashboards, headline metrics, financial summaries. Best in narrow zones (span 3-4) at the top of a slide.

### `cardGrid`

Bordered cards with title + detail lines. Good for entity profiles, product features.

```json
{
  "type": "cardGrid",
  "items": [
    { "title": "Cloud Platform", "lines": ["AWS-based infrastructure", "99.9% uptime SLA"] },
    { "title": "Mobile SDK", "lines": ["iOS & Android", "React Native support"] }
  ]
}
```

| Property | Type | Description |
|---|---|---|
| `items[].title` | `string` | Card heading (bold, accent color) |
| `items[].lines` | `string[]` | Detail lines below title |

**When to use:** Feature comparisons, product capabilities, service offerings. Each card gets a rounded border.

### `keyValue`

Key-value pair list. Bold key with colon, then value on same line.

```json
{
  "type": "keyValue",
  "items": [
    { "key": "Founded", "value": "2015" },
    { "key": "Headquarters", "value": "San Francisco, CA" },
    { "key": "Employees", "value": "2,500+" }
  ]
}
```

**When to use:** Company overviews, deal parameters, specification lists.

### `table`

Data table with header row and body rows. Auto-styles with alternating row colors.

```json
{
  "type": "table",
  "data": {
    "headers": ["Company", "Revenue", "Growth", "Margin"],
    "rows": [
      ["Acme Corp", "$520M", "15%", "42%"],
      ["Globex", "$380M", "22%", "38%"],
      ["Initech", "$290M", "8%", "45%"]
    ]
  }
}
```

| Property | Type | Description |
|---|---|---|
| `data.headers` | `string[]` | Column headers (styled with accent fill) |
| `data.rows` | `string[][]` | 2D array of cell values |

**When to use:** Financial comparisons, peer analysis, data summaries. Best for structured data with 3-8 columns.

### `teamGrid`

Vertical list of name + title pairs. Simple team roster format.

```json
{
  "type": "teamGrid",
  "items": [
    { "name": "Jane Smith", "title": "Managing Director" },
    { "name": "John Doe", "title": "Vice President" }
  ]
}
```

**When to use:** Team pages, leadership lists, contact information.

### `profile`

Single person/entity profile with name + bullet items. Used inside card layouts.

```json
{
  "type": "profile",
  "name": "Jane Smith",
  "items": ["20+ years experience", "Former Partner at McKinsey", "Harvard MBA"]
}
```

**When to use:** Inside profile card templates. Rarely used directly — prefer `teamGrid` for simple lists or the `profileCards` template for elaborate layouts.

### `image`

Embedded image. Two sizing modes: percentage (stretch to container) or pixel (fit with aspect ratio).

```json
{ "type": "image", "path": "images/chart.png", "width": "100%", "height": "100%" }
```
```json
{ "type": "image", "buffer": "<Buffer>", "width": 800, "height": 500 }
```

| Property | Type | Description |
|---|---|---|
| `path` | `string` | File path (resolved relative to JSON file). Use for JSON-to-PPTX converter. |
| `buffer` | `Buffer` | Raw image data. Use for programmatic API. |
| `width` | `number` or `"N%"` | Pixel width or percentage of container |
| `height` | `number` or `"N%"` | Pixel height or percentage of container |
| `ext` | `string` | Image extension (default: `"png"`) |

**When to use:** Pre-made images, logos, maps, screenshots. For data charts, prefer `type: "chart"` instead (see below).

### `chart`

Inline chart generated at the exact container dimensions. The chart engine renders at the cell's pixel size, so no stretching or squashing occurs.

```json
{ "type": "chart", "chartType": "bar", "title": "Revenue by Year",
  "categories": ["2022", "2023", "2024"], "series": [{ "name": "Rev", "data": [520, 640, 780] }] }
```

Properties vary by `chartType` — see the **Chart Types** section below.

**When to use:** Any data visualization. Always prefer `type: "chart"` over `type: "image"` for charts, because charts are generated at the exact container size and look crisp at any layout position.

### `line`

Horizontal divider line. Used for visual separation.

```json
{ "type": "line", "color": "#999999", "width": 9525 }
```

| Property | Type | Default | Description |
|---|---|---|---|
| `color` | `string` | style primary text color | Line color |
| `width` | `number` | 9525 | Line width in EMU (9525 = 0.75pt) |

**When to use:** Separating sections within a zone. Rarely needed — use `subheader` on layout nodes instead for most cases.

---

## Chart Types

All chart content uses `"type": "chart"` with a `chartType` field. An optional `title` string adds a centered title above the chart.

### `bar`

Vertical (or horizontal) bar chart. Supports grouped and stacked modes.

```json
{
  "type": "chart", "chartType": "bar",
  "title": "Revenue by Segment",
  "categories": ["Software", "Services", "Hardware"],
  "series": [
    { "name": "2023", "data": [320, 180, 95] },
    { "name": "2024", "data": [380, 210, 88] }
  ],
  "horizontal": false,
  "stacked": false
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `categories` | `string[]` | required | X-axis labels |
| `series` | `array` | required | `[{ name, data: number[] }]` |
| `horizontal` | `boolean` | `false` | Horizontal bars |
| `stacked` | `boolean` | `false` | Stack series |

**When to use:** Comparing values across categories. The most versatile chart type. Use for revenue breakdowns, market share, year-over-year comparisons.

### `line`

Line chart with optional smoothing and area fill.

```json
{
  "type": "chart", "chartType": "line",
  "categories": ["Q1", "Q2", "Q3", "Q4"],
  "series": [{ "name": "Revenue", "data": [145, 162, 178, 195] }],
  "smooth": true,
  "area": false
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `categories` | `string[]` | required | X-axis labels |
| `series` | `array` | required | `[{ name, data: number[] }]` |
| `smooth` | `boolean` | `false` | Smooth curves |
| `area` | `boolean` | `false` | Fill area under line |

**When to use:** Trends over time, growth trajectories, margin progression.

### `pie`

Pie or doughnut chart.

```json
{
  "type": "chart", "chartType": "pie",
  "items": [
    { "name": "Software", "value": 65 },
    { "name": "Services", "value": 25 },
    { "name": "Other", "value": 10 }
  ],
  "doughnut": false
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `items` | `array` | required | `[{ name, value }]` |
| `doughnut` | `boolean` | `false` | Doughnut style (hollow center) |

**When to use:** Composition breakdowns, revenue mix, market share distribution. Best with 2-6 segments. Note: uses `items` not `series`.

### `combo`

Combined bar + line chart on the same axes. Supports dual Y-axis.

```json
{
  "type": "chart", "chartType": "combo",
  "categories": ["Q1", "Q2", "Q3", "Q4"],
  "bars": [{ "name": "Revenue", "data": [145, 162, 178, 195] }],
  "lines": [{ "name": "Margin %", "data": [62, 64, 63, 65] }],
  "dualAxis": true
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `categories` | `string[]` | required | X-axis labels |
| `bars` | `array` | `[]` | `[{ name, data }]` for bar series |
| `lines` | `array` | `[]` | `[{ name, data }]` for line series |
| `dualAxis` | `boolean` | `false` | Separate Y-axis for lines |

**When to use:** Revenue + margin, volume + price, any metric pair where one is absolute and one is relative. `dualAxis: true` when scales differ.

### `waterfall`

Waterfall (bridge) chart. First and last values are totals; middle values are deltas.

```json
{
  "type": "chart", "chartType": "waterfall",
  "categories": ["FY24 Revenue", "Organic Growth", "Acquisitions", "FX Impact", "FY25E Revenue"],
  "data": [680, 85, 45, -30, 780]
}
```

| Property | Type | Description |
|---|---|---|
| `categories` | `string[]` | Labels for each bar |
| `data` | `number[]` | First = start total, last = end total, middle = increments/decrements |

**When to use:** Revenue bridges, cost walks, year-over-year reconciliations. Classic investment banking chart.

### `scatter`

Scatter plot with multiple series. Each data point is `[x, y]`.

```json
{
  "type": "chart", "chartType": "scatter",
  "series": [
    { "name": "Tech", "data": [[15, 42], [22, 38], [8, 55]] },
    { "name": "Finance", "data": [[12, 35], [18, 28], [25, 45]] }
  ]
}
```

| Property | Type | Description |
|---|---|---|
| `series` | `array` | `[{ name, data: [x, y][] }]` |

**When to use:** Correlation analysis, peer positioning (growth vs. margin), risk-return plots.

### `gauge`

Single-value gauge/speedometer.

```json
{
  "type": "chart", "chartType": "gauge",
  "value": 73,
  "min": 0,
  "max": 100,
  "label": "NPS Score",
  "format": "{value}"
}
```

| Property | Type | Default | Description |
|---|---|---|---|
| `value` | `number` | `0` | Current value |
| `min` | `number` | `0` | Minimum |
| `max` | `number` | `100` | Maximum |
| `label` | `string` | `""` | Label below gauge |
| `format` | `string` | `"{value}%"` | Display format |

**When to use:** Single KPI with context (NPS, utilization rate, goal progress). Best in small zones.

---

## Templates

Templates generate complete slide specs from structured data. Use `$template` and `$templateData` on the slide definition. Templates handle layout complexity so you only provide the data.

### `investorActivity`

Table-like layout showing investors and their portfolio targets.

```
┌──────────────────────────────────────────────────────────────┐
│  [sectionLabel]                                              │
│  [title]                                                     │
├────┬──────┬──────────────────────────────────────────────────┤
│Inv │  #   │ Target 1     │ Target 2     │ Target 3          │  ← header row
├────┼──────┼──────────────┼──────────────┼────────────────────┤
│Name│ 15   │ Co | Desc    │ Co | Desc    │ Co | Desc         │  ← data rows
└────┴──────┴──────────────┴──────────────┴────────────────────┘
```

```json
{
  "$template": "investorActivity",
  "$templateData": {
    "title": "Investor Activity in Construction Tech",
    "sectionLabel": "Market Overview",
    "investors": [
      {
        "name": "Vista Equity",
        "count": 15,
        "targets": [
          { "company": "Procore", "description": "Project management platform" },
          { "company": "PlanGrid", "description": "Construction blueprints" },
          { "company": "Fieldwire", "description": "Field management" }
        ]
      }
    ]
  }
}
```

**When to use:** Competitive landscape, investor mapping, M&A activity tracking.

### `dashboard`

KPI row on top + two-panel content area below.

```
┌──────────────────────────────────────────────────────────────┐
│  KPI 1    │  KPI 2    │  KPI 3    │  KPI 4                  │  span:3
├───────────────────────────────────┬──────────────────────────┤
│                                   │                          │
│         Left Panel (8)            │    Right Panel (4)       │  span:9
│                                   │                          │
└───────────────────────────────────┴──────────────────────────┘
```

```json
{
  "$template": "dashboard",
  "$templateData": {
    "title": "Revenue Dashboard",
    "kpis": [
      { "value": "$680M", "label": "Revenue" },
      { "value": "64%", "label": "Margin" },
      { "value": "4,820", "label": "Customers" }
    ],
    "leftPanel": {
      "header": "Quarterly Trend",
      "content": { "type": "chart", "chartType": "combo",
        "categories": ["Q1", "Q2", "Q3", "Q4"],
        "bars": [{ "name": "Revenue", "data": [145, 162, 178, 195] }],
        "lines": [{ "name": "Margin", "data": [62, 64, 63, 65] }],
        "dualAxis": true }
    },
    "rightPanel": {
      "header": "Top Segments",
      "content": { "type": "table", "data": {
        "headers": ["Segment", "Rev"],
        "rows": [["Cloud", "$280M"], ["On-Prem", "$210M"]]
      }}
    }
  }
}
```

**When to use:** Executive summary slides, financial dashboards, any slide that needs headline KPIs + detail.

### `peerComparison`

Chart on left + stacked stats/table on right.

```
┌──────────────────────────────────┬───────────────────────────┐
│                                  │  [Peers section]          │  span:7
│         Chart (7)                ├───────────────────────────┤
│                                  │  [Valuation section]      │  span:5
└──────────────────────────────────┴───────────────────────────┘
```

```json
{
  "$template": "peerComparison",
  "$templateData": {
    "title": "Peer Comparison",
    "chart": {
      "header": "EV/Revenue Multiple",
      "content": { "type": "chart", "chartType": "bar",
        "categories": ["Acme", "Globex", "Initech"],
        "series": [{ "name": "EV/Rev", "data": [8.2, 6.5, 4.8] }] }
    },
    "rightHeader": "Financial Comparison",
    "peers": {
      "subheader": "Peer Metrics",
      "content": { "type": "table", "data": {
        "headers": ["Company", "Rev", "Growth"],
        "rows": [["Acme", "$520M", "15%"], ["Globex", "$380M", "22%"]]
      }}
    },
    "valuation": {
      "subheader": "Valuation Summary",
      "content": { "type": "statGrid", "items": [
        { "value": "6.5x", "label": "Median EV/Rev" },
        { "value": "18%", "label": "Median Growth" }
      ]}
    }
  }
}
```

**When to use:** Competitive benchmarking, peer analysis, valuation comparisons.

### `profileCards`

Two columns of entity profile cards (logo + name + bullets) in a 2x2 grid per column.

```json
{
  "$template": "profileCards",
  "$templateData": {
    "title": "Key Players",
    "leftHeader": "Strategic Buyers",
    "rightHeader": "Financial Sponsors",
    "left": [
      { "name": "Acme Corp", "logo": "images/acme.png",
        "items": ["$2.5B revenue", "15 acquisitions since 2020"] }
    ],
    "right": [
      { "name": "Vista Equity", "logo": "images/vista.png",
        "items": ["$100B AUM", "Focus: enterprise software"] }
    ]
  }
}
```

**When to use:** Buyer profiles, competitor overviews, entity comparisons with logos.

### `tableOfContents`

Numbered section list with optional decorative right panel.

```json
{
  "$template": "tableOfContents",
  "$templateData": {
    "title": "Table of Contents",
    "sections": ["Executive Summary", "Market Overview", "Financials", "Outlook"],
    "panelColor": "#D9D9D9"
  }
}
```

**When to use:** Agenda/TOC slide near the beginning of a presentation.

### `sectionTitle`

Full-bleed section divider with large number and uppercase title.

```json
{
  "$template": "sectionTitle",
  "$templateData": {
    "number": "01.",
    "name": "EXECUTIVE SUMMARY",
    "panelColor": "#8FA4B3"
  }
}
```

**When to use:** Section dividers between major presentation sections. Place before each new section.

### `transactionGrid`

Grid of tombstone cards (deal announcements). N columns of tombstones.

```json
{
  "$template": "transactionGrid",
  "$templateData": {
    "title": "Select Transactions",
    "columns": 4,
    "transactions": [
      {
        "clientName": "Acme Corp",
        "clientLogo": "images/acme.png",
        "transactionText": "— Acquired by —",
        "counterpartyLogo": "images/buyer.png",
        "date": "Sep 2025"
      }
    ]
  }
}
```

**When to use:** Deal track record, credentials slides, M&A transaction lists.

### `globalBuyers`

Large image (e.g. world map) on top + row of tombstones below.

```json
{
  "$template": "globalBuyers",
  "$templateData": {
    "title": "Global Buyer Universe",
    "mapImage": { "type": "image", "path": "images/world-map.png", "width": "100%", "height": "100%" },
    "transactions": [
      { "clientName": "Asia Buyer", "transactionText": "— Acquired —", "date": "2025" }
    ]
  }
}
```

**When to use:** Geographic buyer mapping, global transaction coverage.

### `customerQuotes`

Quote cards on top + press/testimonial banner below.

```json
{
  "$template": "customerQuotes",
  "$templateData": {
    "title": "What Our Clients Say",
    "quotes": [
      { "text": "Transformed our workflow completely.", "author": "Jane Smith",
        "role": "VP Engineering", "company": "Acme Corp" }
    ],
    "banner": [
      { "text": "\"Best platform we've used\" — TechCrunch" },
      { "text": "\"Game-changing\" — Forbes" }
    ],
    "bannerColor": "#F5F0EB"
  }
}
```

**When to use:** Testimonials, client endorsements, press quotes.

### `credentialsProfile`

2x2 quadrant: stats, practice areas (icon grid), tombstones, team profiles.

```json
{
  "$template": "credentialsProfile",
  "$templateData": {
    "title": "Firm Overview",
    "stats": {
      "header": "Key Metrics",
      "items": [{ "value": "$50B+", "label": "Transactions" }, { "value": "200+", "label": "Deals" }]
    },
    "practiceAreas": {
      "header": "Practice Areas",
      "items": [{ "label": "M&A Advisory" }, { "label": "Capital Markets" }]
    },
    "transactions": {
      "header": "Recent Deals",
      "tombstones": [{ "clientName": "Acme", "transactionText": "Acquired by", "date": "2025" }]
    },
    "team": {
      "header": "Senior Team",
      "members": [{ "name": "John Doe", "items": ["Managing Director", "20+ years"] }]
    }
  }
}
```

**When to use:** Firm credentials, company overview, "about us" slides.

### `marketUpdate`

Chart on top half + 2x2 trend grid on bottom (icon + title + bullets per cell).

```json
{
  "$template": "marketUpdate",
  "$templateData": {
    "title": "Market Update",
    "chart": {
      "header": "S&P 500 Performance",
      "content": { "type": "chart", "chartType": "line",
        "categories": ["Jan", "Feb", "Mar", "Apr"],
        "series": [{ "name": "S&P", "data": [4800, 4950, 5100, 5200] }] }
    },
    "trendsHeader": "Key Market Themes",
    "trends": [
      { "title": "AI Infrastructure", "bullets": ["$200B capex cycle", "Cloud demand accelerating"] },
      { "title": "Rate Environment", "bullets": ["Fed holding steady", "Yield curve normalizing"] }
    ]
  }
}
```

**When to use:** Market overview slides, industry update briefings.

### `chartQuadrant`

2x2 grid of chart panels. Each quadrant has a header and 1+ charts.

```json
{
  "$template": "chartQuadrant",
  "$templateData": {
    "title": "Industry Dynamics",
    "quadrants": [
      { "header": "Revenue Growth",
        "charts": [{ "type": "chart", "chartType": "bar",
          "categories": ["2022", "2023", "2024"],
          "series": [{ "name": "Rev", "data": [520, 640, 780] }] }] },
      { "header": "Margin Trend",
        "charts": [{ "type": "chart", "chartType": "line",
          "categories": ["2022", "2023", "2024"],
          "series": [{ "name": "Margin", "data": [58, 62, 65] }] }] },
      { "header": "Revenue Mix",
        "charts": [{ "type": "chart", "chartType": "pie",
          "items": [{ "name": "Software", "value": 65 }, { "name": "Services", "value": 35 }] }] },
      { "header": "Revenue Bridge",
        "charts": [{ "type": "chart", "chartType": "waterfall",
          "categories": ["FY24", "Growth", "M&A", "FY25E"],
          "data": [640, 95, 45, 780] }] }
    ]
  }
}
```

**When to use:** Multi-chart analysis slides, industry dynamics, comprehensive data overview. Best when you need 4 related charts on one slide.

### `keyTrends`

Subtitle row on top + 3 equal columns, each with header, 2/3 text, 1/3 visual.

```
┌──────────────────────────────────────────────────────────────┐
│  [title]                                                     │
├──────────────────────────────────────────────────────────────┤
│  [subtitle text]                                             │  span:2
├──────────────────┬──────────────────┬────────────────────────┤
│  ██ Header 1 ██  │  ██ Header 2 ██  │  ██ Header 3 ██       │
│                  │                  │                        │  span:10
│  [bullets]       │  [bullets]       │  [bullets]             │  2/3
│                  │                  │                        │
│  [chart/visual]  │  [chart/visual]  │  [chart/visual]        │  1/3
└──────────────────┴──────────────────┴────────────────────────┘
```

```json
{
  "$template": "keyTrends",
  "$templateData": {
    "title": "Industry Key Trends",
    "subtitle": "As demand for digital transformation accelerates...",
    "sectionLabel": "Market Overview",
    "columns": [
      {
        "header": "Cloud Adoption",
        "text": { "type": "bulletList", "items": [
          "85% of enterprises adopting multi-cloud",
          "Annual cloud spend exceeding $600B"
        ]},
        "visual": { "type": "chart", "chartType": "bar",
          "categories": ["2022", "2023", "2024"],
          "series": [{ "name": "Spend ($B)", "data": [410, 500, 620] }] }
      },
      {
        "header": "AI Integration",
        "text": { "type": "bulletList", "items": [
          "GenAI adoption up 3x YoY",
          "Enterprise AI market at $150B"
        ]},
        "visual": { "type": "chart", "chartType": "pie",
          "items": [{ "name": "GenAI", "value": 45 }, { "name": "ML Ops", "value": 35 }, { "name": "Other", "value": 20 }] }
      },
      {
        "header": "Security Spend",
        "text": { "type": "bulletList", "items": [
          "Zero-trust adoption at 61%",
          "Cybersecurity M&A accelerating"
        ]},
        "visual": { "type": "chart", "chartType": "line",
          "categories": ["2022", "2023", "2024"],
          "series": [{ "name": "Spend ($B)", "data": [170, 195, 225] }], "smooth": true }
      }
    ]
  }
}
```

**When to use:** Industry trend analysis, thematic overviews. Best when you have 3 parallel themes each needing explanation + visual evidence.

---

## Components

Components are reusable sub-slide building blocks that can be placed in any grid cell. Use `$component` in body node children.

### `tombstone`

Investment banking deal tombstone card.

```json
{
  "$component": "tombstone",
  "clientName": "Acme Corp",
  "clientLogo": "images/acme.png",
  "transactionText": "— Acquired by —",
  "counterpartyLogo": "images/buyer.png",
  "date": "September 2025",
  "logoWidth": 100,
  "logoHeight": 40
}
```

**When to use:** Inside `transactionGrid` or `globalBuyers` templates, or in custom grid layouts for deal credentials.

---

## Decision Guide

### Choosing a Slide Type

| User Intent | Slide Type |
|---|---|
| Opening/title slide | `type: "title"` |
| Agenda / table of contents | `$template: "tableOfContents"` |
| Section break | `$template: "sectionTitle"` |
| KPI dashboard with charts | `$template: "dashboard"` |
| Financial comparison | `$template: "peerComparison"` |
| 4 charts on one slide | `$template: "chartQuadrant"` |
| 3 parallel themes/trends | `$template: "keyTrends"` |
| Deal track record | `$template: "transactionGrid"` |
| Client testimonials | `$template: "customerQuotes"` |
| Firm credentials / about us | `$template: "credentialsProfile"` |
| Market briefing with trends | `$template: "marketUpdate"` |
| Buyer/investor profiles | `$template: "profileCards"` or `$template: "investorActivity"` |
| Custom layout | `type: "grid"` with inline `body` |

### Choosing a Chart Type

| Data Shape | Chart Type |
|---|---|
| Values across categories | `bar` |
| Trend over time | `line` |
| Composition / market share | `pie` |
| Revenue + margin (two scales) | `combo` with `dualAxis: true` |
| Year-over-year bridge | `waterfall` |
| Correlation (x,y pairs) | `scatter` |
| Single KPI with range context | `gauge` |

### Choosing a Content Type

| Content Need | Content Type |
|---|---|
| Key points / analysis | `bulletList` |
| Headline metrics | `statGrid` |
| Structured data comparison | `table` |
| Feature/product cards | `cardGrid` |
| Specifications / parameters | `keyValue` |
| Team roster | `teamGrid` |
| Free-form text | `text` |
| Data visualization | `chart` |
| Pre-made image | `image` |

---

## Common Presentation Structures

### Corporate / Investment Banking Pitch

```json
{
  "style": "corporate",
  "slides": [
    { "type": "title", "title": "...", "subtitle": "..." },
    { "type": "grid", "$template": "tableOfContents", "$templateData": { "sections": [...] } },
    { "type": "grid", "$template": "sectionTitle", "$templateData": { "number": "01.", "name": "EXECUTIVE SUMMARY" } },
    { "type": "grid", "$template": "dashboard", "$templateData": { ... } },
    { "type": "grid", "$template": "sectionTitle", "$templateData": { "number": "02.", "name": "MARKET OVERVIEW" } },
    { "type": "grid", "$template": "keyTrends", "$templateData": { ... } },
    { "type": "grid", "$template": "chartQuadrant", "$templateData": { ... } },
    { "type": "grid", "$template": "sectionTitle", "$templateData": { "number": "03.", "name": "COMPETITIVE LANDSCAPE" } },
    { "type": "grid", "$template": "peerComparison", "$templateData": { ... } },
    { "type": "grid", "$template": "investorActivity", "$templateData": { ... } },
    { "type": "grid", "$template": "sectionTitle", "$templateData": { "number": "04.", "name": "CREDENTIALS" } },
    { "type": "grid", "$template": "transactionGrid", "$templateData": { ... } },
    { "type": "grid", "$template": "credentialsProfile", "$templateData": { ... } }
  ]
}
```

### Product / Tech Pitch

```json
{
  "style": "minimal",
  "slides": [
    { "type": "title", "title": "...", "subtitle": "..." },
    { "type": "grid", "title": "The Problem", "body": { "direction": "row", "children": [
      { "span": 7, "content": { "type": "bulletList", "items": [...] } },
      { "span": 5, "content": { "type": "statGrid", "items": [...] } }
    ]}},
    { "type": "grid", "title": "Our Solution", "body": { "direction": "row", "children": [
      { "span": 6, "content": { "type": "cardGrid", "items": [...] } },
      { "span": 6, "content": { "type": "chart", "chartType": "bar", ... } }
    ]}},
    { "type": "grid", "$template": "dashboard", "$templateData": { ... } },
    { "type": "grid", "$template": "customerQuotes", "$templateData": { ... } }
  ]
}
```

---

## Important Rules

1. **Always use `type: "chart"` for data visualizations**, not `type: "image"`. Charts are rendered at the exact container size.
2. **`fontSize` is in hundredths of a point**: 1400 = 14pt, 1200 = 12pt, 2800 = 28pt.
3. **Colors are hex strings** with `#` prefix: `"#4472C4"`, `"#333333"`.
4. **`pie` charts use `items`**, all other charts use `series` (except `waterfall` which uses `data`).
5. **`combo` charts use `bars` and `lines`**, not `series`.
6. **Template properties go in `$templateData`**, not on the slide root (except `title`, `sectionLabel`, `footer` which override).
7. **`span` values are relative weights** in a 12-column grid. Two children with span 6 each = two equal halves.
8. **Images in JSON files use `path`** (file path), while programmatic API uses `buffer` (Buffer object).
9. **Keep bullet items concise** — 1-2 lines each, 3-6 items per list.
10. **Use `sectionLabel`** on content slides to show which section the slide belongs to.
06

Example Deck

A working 3-slide example demonstrating a title slide, an inline grid layout, and a dashboard template. Download: example-deck.json

example-deck.jsonDownload
{
  "style": "corporate",
  "slides": [
    {
      "type": "title",
      "title": "Quarterly Business Review",
      "subtitle": "Q1 2026 — A-1 Investment Bank"
    },
    {
      "type": "grid",
      "title": "Executive Summary",
      "sectionLabel": "OVERVIEW",
      "body": {
        "direction": "row",
        "children": [
          {
            "span": 6,
            "header": "Key Metrics",
            "content": {
              "type": "statGrid",
              "items": [
                { "value": "$42M", "label": "Revenue", "sublabel": "+18% YoY" },
                { "value": "68%", "label": "Gross Margin" },
                { "value": "1,250", "label": "Customers", "sublabel": "+320 net new" },
                { "value": "4.2x", "label": "LTV/CAC" }
              ]
            }
          },
          {
            "span": 6,
            "header": "Revenue Trend",
            "content": {
              "type": "chart",
              "chartType": "bar",
              "title": "Quarterly Revenue ($M)",
              "categories": ["Q2 '25", "Q3 '25", "Q4 '25", "Q1 '26"],
              "series": [{ "name": "Revenue", "data": [32, 35, 38, 42] }]
            }
          }
        ]
      }
    },
    {
      "type": "grid",
      "$template": "dashboard",
      "$templateData": {
        "title": "Financial Dashboard",
        "kpis": [
          { "value": "$42M", "label": "Revenue" },
          { "value": "68%", "label": "Gross Margin" },
          { "value": "$8.2M", "label": "EBITDA" },
          { "value": "118%", "label": "Net Retention" }
        ],
        "leftPanel": {
          "header": "Revenue & Margin Trend",
          "content": {
            "type": "chart",
            "chartType": "combo",
            "categories": ["Q2 '25", "Q3 '25", "Q4 '25", "Q1 '26"],
            "bars": [{ "name": "Revenue ($M)", "data": [32, 35, 38, 42] }],
            "lines": [{ "name": "Margin %", "data": [64, 65, 67, 68] }],
            "dualAxis": true
          }
        },
        "rightPanel": {
          "header": "Top Segments",
          "content": {
            "type": "table",
            "data": {
              "headers": ["Segment", "Rev", "Growth"],
              "rows": [
                ["Enterprise", "$24M", "+22%"],
                ["Mid-Market", "$12M", "+15%"],
                ["SMB", "$6M", "+8%"]
              ]
            }
          }
        }
      }
    }
  ]
}
07

Full Workflow Example

Complete workflow using curl to authenticate, update a presentation, and verify.

Shell
# 1. Login and capture token
TOKEN=$(curl -s -X POST "$BANKOPS_API_URL/api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"'$BANKOPS_USERNAME'","password":"'$BANKOPS_PASSWORD'"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")

# 2. Download the schema reference
curl -s "$BANKOPS_API_URL/developers/schema.md" -o schema.md

# 3. Download the example deck
curl -s "$BANKOPS_API_URL/developers/example-deck.json" -o example-deck.json

# 4. PATCH presentation with your deck JSON
curl -X PATCH "$BANKOPS_API_URL/api/presentations/YOUR_PRESENTATION_ID" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Q1 Review",
    "content": {
      "style": "corporate",
      "slides": [
        {
          "type": "title",
          "title": "Q1 Business Review",
          "subtitle": "A-1 Investment Bank"
        },
        {
          "type": "grid",
          "$template": "dashboard",
          "$templateData": {
            "title": "Financial Summary",
            "kpis": [
              { "value": "$42M", "label": "Revenue" },
              { "value": "68%", "label": "Margin" }
            ],
            "leftPanel": {
              "header": "Trend",
              "content": {
                "type": "chart",
                "chartType": "bar",
                "categories": ["Q1","Q2","Q3","Q4"],
                "series": [{"name":"Rev","data":[35,38,40,42]}]
              }
            },
            "rightPanel": {
              "header": "Segments",
              "content": {
                "type": "table",
                "data": {
                  "headers": ["Segment","Rev"],
                  "rows": [["Enterprise","$24M"],["SMB","$6M"]]
                }
              }
            }
          }
        }
      ]
    }
  }'

# 5. Verify
curl -s "$BANKOPS_API_URL/api/presentations/YOUR_PRESENTATION_ID" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool