How to Ingest PPTX into Claude Code with EnConvert

Use EnConvert to ingest a PPTX into a Claude Code workflow as slide-structured JSONL chunks with section metadata the agent can read and reason over by slide

Get API key

A developer using Claude Code to build an agent pipeline that reads PPTX files needs slide-structured chunks with section metadata, not flat paragraph text that loses the slide boundaries. Extracting a PPTX with python-pptx returns paragraphs from each slide’s text frames with no slide structure, no heading hierarchy, and nothing to populate metadata a retrieval layer can filter on. For a workflow that must reason over a product deck, a sales presentation, or a research brief, flat paragraph text without slide context produces content the agent cannot attribute to a specific slide or filter by section. EnConvert’s Ingest endpoint takes the uploaded PPTX and returns JSONL chunks where each slide becomes a ## Slide N: Title Markdown section, each carrying its headings_path breadcrumb, section name, and chunk index in metadata, so the deck is ready for a Claude Code workflow to read and reason over by slide in one call.

Example

python
import json
import os
import time
from pathlib import Path

import requests

HEADERS = {"X-API-Key": os.environ["ENCONVERT_API_KEY"]}
PPTX_PATH = Path("/path/to/your/product-deck.pptx")
OUTPUT_PATH = PPTX_PATH.with_suffix(".chunks.jsonl")

# Step 1: Upload the PPTX (multipart field name is "files")
# Each slide with text becomes a "## Slide N: Title" section
# Slides with no text, such as image-only slides, produce no chunks
with PPTX_PATH.open("rb") as f:
    upload = requests.post(
        "https://api.enconvert.com/v2/ingest/files",
        headers=HEADERS,
        files={
            "files": (
                PPTX_PATH.name,
                f,
                "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            )
        },
        timeout=120,
    )
upload.raise_for_status()
job_id = upload.json()["job_id"]

# Step 2: Poll until the job completes
deadline = time.monotonic() + 900
while True:
    status_response = requests.get(
        f"https://api.enconvert.com/v2/ingest/{job_id}",
        headers=HEADERS,
        timeout=30,
    )
    status_response.raise_for_status()
    job = status_response.json()
    if job["status"] == "completed":
        output_url = job["output_url"]
        break
    if job["status"] in ("failed", "canceled"):
        raise RuntimeError(
            job.get("error_message") or f"Ingest job {job_id} {job['status']}"
        )
    if time.monotonic() >= deadline:
        raise TimeoutError(f"Job {job_id} is still running; resume polling later")
    time.sleep(5)

# Step 3: Download the JSONL output
# The signed URL is valid for 15 minutes. Plain GET, no API key.
jsonl = requests.get(output_url, timeout=120)
jsonl.raise_for_status()

# Save to disk so a Claude Code session can read it directly from the project folder
OUTPUT_PATH.write_bytes(jsonl.content)

# One chunk per line. Split on "\n" only: str.splitlines() also breaks on
# characters such as U+2028 that can appear inside a JSON string
chunks = [
    json.loads(line)
    for line in jsonl.content.decode("utf-8").split("\n")
    if line.strip()
]
print(f"Loaded {len(chunks)} slide chunks saved to {OUTPUT_PATH}")

# Step 4: Print each slide's section and content
# Pass selected chunks into a Claude Code context or load into a vector store
for chunk in chunks:
    metadata = chunk["metadata"]
    print(f"[{metadata['section']} | chunk {metadata['chunk_index']}]")
    print(" / ".join(metadata["headings_path"]))
    print(chunk["content"])
    print()

What you get back

Ingest returns the PPTX as JSONL chunks where each slide becomes a ## Slide N: Title Markdown section, each carrying its headings_path breadcrumb, section name, and chunk index, so a Claude Code workflow can retrieve and reason over content by slide. Extracting text with python-pptx returns paragraphs from each slide’s text frames with no slide structure, no heading hierarchy, and no metadata the workflow can filter on. Image-only slides are skipped.

Get free API key — 500 ops per month, no card required.