---
title: "Inspect a PDF and propose an extraction strategy (no job, no charge)"
method: POST
path: "/v1/deck/from-pdf/analyze"
tags: ["pdf"]
---

# Inspect a PDF and propose an extraction strategy (no job, no charge)

`POST /v1/deck/from-pdf/analyze`

## Request

- Base URL: `https://api.slideforge.dev`
- URL: `https://api.slideforge.dev/v1/deck/from-pdf/analyze`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`

Upload a PDF and receive metadata, per-page stats, source classification, and an estimated cost. Use this to show users what they're about to spend before calling `/v1/deck/from-pdf`. No job is created and the file is not persisted — re-upload the same file to `/v1/deck/from-pdf` when ready.

## Response `200`

Analysis returned

- PdfAnalysis: Output of analyze_pdf() — what /analyze returns and what /generate uses to route.
  - `producer` string: PDF metadata producer string (telemetry only — never used for routing). Captured so we can correlate buckets with real-world tools after the fact.
  - `page_count` integer, required: Number of pages in the PDF
  - `file_size_bytes` integer, required: Source PDF size in bytes
  - `bucket` 'slide-vector' | 'slide-raster' | 'doc-text' | 'doc-image-heavy' | 'scanned' | 'mixed' | 'unknown', required: Routing decision derived from structural features. The /v1/deck/from-pdf endpoint accepts a file iff its bucket is currently implemented.
  - `features` PdfFeatures, required: Document-level structural features used by the bucket classifier. Everything here comes from `fitz` primitives — no LLM calls. The fields are deliberately concrete (counts, ratios, booleans) so threshold tuning against a real corpus is reproducible.
    - `aspect_ratio_first` number, required: width / height of the first page
    - `is_slide_aspect` boolean, required: True if the first page sits in a slide-shaped aspect band (roughly 1.25–2.45 — covers 4:3, 16:10, 16:9, ultrawide)
    - `is_doc_portrait` boolean, required: True if the first page is portrait-oriented (aspect < 1.0)
    - `consistent_dimensions` boolean, required: True if every page in the document shares the same width/height
    - `total_text_chars` integer, required: Sum of extractable characters across all pages
    - `total_text_spans` integer, required: Sum of text spans (formatted runs) across all pages. Zero with non-zero total_text_chars suggests glyph-outlined text — readable but unformatted.
    - `total_images` integer, required: Sum of embedded images across all pages
    - `total_drawings` integer, required: Sum of vector drawing primitives (rects, paths, lines) across all pages — high counts indicate hand-built slide content rather than scanned/raster
    - `unique_fonts` integer, required: Number of distinct fonts seen across the doc
    - `pages_with_text` integer, required: Pages with at least 50 chars of extractable text
    - `pages_image_only` integer, required: Pages with images present but fewer than 50 chars of extractable text
    - `pages_blank` integer, required: Pages with no text and no images
  - `estimated_cost_usd` number, required: Per-page price for the bucket × page_count
  - `can_extract` boolean, required: True iff /v1/deck/from-pdf will currently accept this file.
  - `unsupported_reason` string, nullable: Human-readable hint shown to the user when can_extract is False, explaining what's not yet supported.
  - `pages` PdfPageInfo[]: Per-page summary, in document order
    - `page_number` integer, required: 1-based page number
    - `has_text` boolean, required: True if the page contains extractable text
    - `has_images` boolean, required: True if the page contains embedded images
    - `text_char_count` integer, required: Total characters of extractable text
    - `text_preview` string: First ~80 characters of text content (for the analysis card)

## Other responses

- `400`: Invalid PDF (size, format, corrupted)
- `413`: File too large
- `422`: Validation Error
- `429`: Rate limit exceeded

---

[API](https://skmtc.dev/slideforge/apis/slideforge-api.md) · [All operations](https://skmtc.dev/slideforge/apis/slideforge-api/llms.txt) · [OpenAPI document](https://skmtc.dev/slideforge/apis/slideforge-api/revisions/ae698e3d3c00?raw)
