TypeScript SDK

@pptx/sdk for TypeScript

Typed client for the pptx.dev REST API. Works in Node 20+, Next.js (App Router, server + client), Bun, and modern browsers. Ships OPF document types, typed errors, and a dual ESM / CJS build.

Install

Shell
npm i @pptx/sdk
# or
pnpm add @pptx/sdk
# or
bun add @pptx/sdk

First call

Create a client with your API key and validate an OPF document. Validation is always free.

TypeScript
import { PptxClient } from "@pptx/sdk";

const pptx = new PptxClient({ apiKey: process.env.PPTX_API_KEY });

const result = await pptx.opf.validate({
  $schema: "https://pptx.dev/schema/opf/v1",
  version: "1.0",
  meta: { title: "Hello" },
  design: { theme: "corporate-minimal" },
  slides: [
    {
      id: "s1",
      layout: "title-slide",
      elements: [
        { id: "h1", type: "text", content: { text: "Hello, world" } },
      ],
    },
  ],
});

console.log(result.valid, result.errors, result.warnings);

Authentication

The client resolves a bearer token in this order:

  1. The apiKey option passed to the constructor.
  2. The PPTX_API_KEY environment variable (Node / Bun runtimes only).
TypeScript
import { PptxClient } from "@pptx/sdk";

const pptx = new PptxClient({ apiKey: "ppx_..." });

Get your API key from the API Keys page.

Generate a .pptx from OPF

TypeScript
import { PptxClient, type OPFDocument } from "@pptx/sdk";

const pptx = new PptxClient();

const doc: OPFDocument = {
  $schema: "https://pptx.dev/schema/opf/v1",
  version: "1.0",
  meta: { title: "Q1 Review" },
  design: { theme: "corporate-minimal" },
  slides: [
    {
      id: "title",
      layout: "title-slide",
      elements: [
        { id: "h1", type: "text", content: { text: "Q1 Review" } },
      ],
    },
  ],
};

const job = await pptx.opf.generate(doc, { format: "pptx" });
console.log(job.status, job.slideCount);

Parse an existing .pptx

TypeScript
import { readFile } from "node:fs/promises";
import { PptxClient } from "@pptx/sdk";

const pptx = new PptxClient();
const bytes = await readFile("deck.pptx");

const { parseId, slideCount } = await pptx.parse.upload({
  data: bytes,
  filename: "deck.pptx",
});

const slide0 = await pptx.parse.slide(parseId, 0);
console.log(slide0.textRuns);

Error handling

All errors extend PptxError.

ErrorWhen
PptxNetworkErrorfetch threw (DNS, TLS, timeout, aborted)
PptxApiErrorHTTP 4xx / 5xx response with JSON or text body
PptxValidationErrorHTTP 422 with validationErrors[] from opf.generate
PptxRateLimitErrorHTTP 429 (exposes retryAfterSeconds)
TypeScript
import {
  PptxValidationError,
  PptxRateLimitError,
} from "@pptx/sdk";

try {
  await pptx.opf.generate(badDoc);
} catch (err) {
  if (err instanceof PptxValidationError) {
    console.error("OPF schema errors:", err.validationErrors);
  } else if (err instanceof PptxRateLimitError) {
    console.error("Retry after:", err.retryAfterSeconds, "s");
  } else {
    throw err;
  }
}

Every error exposes requestId when the server returned an X-Request-Id header.

OPF types

The full OPF type tree is available from the root entry or the /opf subpath.

TypeScript
import type { OPFDocument, OPFSlide, OPFElement } from "@pptx/sdk";
// or
import type { OPFDocument } from "@pptx/sdk/opf";

Custom base URL

For local development against a Next.js dev server:

TypeScript
const pptx = new PptxClient({
  baseUrl: "http://localhost:3000/api",
});