npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pitchflow-sdk

v0.2.0

Published

Typed Node.js client for the Pitchflow (pflo.ai) API: templates, instantiate, page patches and PDF/PNG export.

Readme

pitchflow-sdk

A typed Node.js client for the Pitchflow API. Use it to list templates, render a deck from a template, patch its pages, and export the deck as PDF or PNG.

  • No runtime dependencies. It uses the built-in fetch, which needs Node 18 or newer.
  • Ships as both ESM and CommonJS, with type definitions.
  • Your API key stays on the server. Call Pitchflow from your backend and never from the browser.

Install

npm install pitchflow-sdk

Quick start

import { Pitchflow } from "pitchflow-sdk";

const pitchflow = new Pitchflow({
  apiKey: process.env.PITCHFLOW_API_KEY!,
  externalClientId: process.env.PITCHFLOW_EXTERNAL_CLIENT_ID, // every deck is created under this client
});

const templates = await pitchflow.listTemplates();

// Render: instantiate the template, then patch what instantiate can't fill.
const deck = await pitchflow.render({
  templateId: templates[0].id,
  title: "Spring menu",
  variables: {},
  pagePatches: [
    { title: "Spring menu", tagline: "4 sections · 32 items", blocks: [{ type: "bullets", items: ["…"] }] },
  ],
});

const pdf = await pitchflow.downloadPdf(deck.pitchId);                  // Uint8Array
const png = await pitchflow.downloadPagePng(deck.pitchId, deck.pages[0].id); // Uint8Array, scale 2

Options

| Option | Default | Description | | ------------------ | ------------------ | --------------------------------------------------------------------------- | | apiKey | (required) | Your Pitchflow API key (pf_…). | | externalClientId | (none) | Sent as client.externalId whenever a payload has no client of its own. | | baseUrl | https://pflo.ai | The Pitchflow API base URL. | | fetch | globalThis.fetch | A custom fetch, for tests or a proxy. | | timeoutMs | 60000 | How long one request may run before it is aborted. |

Methods

| Method | Pitchflow endpoint | | --------------------------------------------------- | ------------------------------------------------------- | | listTemplates() | GET /api/templates/overview?format=json | | getTemplate(id) | GET /api/templates/doc?id=…&format=json | | getBlockSchema(type) | GET /api/docs/blocks/:type | | instantiate(payload) | POST /api/templates/instantiate | | getPitch(pitchId) | GET /api/builder/pitches/:id | | patchPage(pitchId, pageId, changes, baseRevision) | PATCH /api/builder/pitches/:id/pages/:pageId | | render(mapping) | instantiate, then getPitch, then patchPage per page | | downloadPdf(pitchId) | POST /api/pitches/:id/pdf | | downloadPagePng(pitchId, pageId, { scale }) | GET /api/pitches/:id/pages/:pageId.png?scale=1\|2 |

Things to know about Pitchflow

  • Unknown names are rejected. Pitchflow refuses any variable, slot or block that the template does not declare, with errors like "Unknown variable" or "Unknown slot(s)". Call getTemplate(id) before you build a payload.
  • Decks are deduplicated on template, client and variables. If you send no variables, every render updates the same deck.
  • Instantiate only fills slots. A page's title, tagline and footnote, and any block without a slot, are copied from the template's sample content. render() takes pagePatches, which are matched to pages by order:
    • A patch is forwarded as given: any field the page PATCH endpoint accepts (title, tagline, footnote, layout, blocks, …) can go in it, and the SDK never needs to know about it.
    • Plain values (title, tagline, footnote, …) are sent only when they differ from what is already there. An empty string clears one.
    • Structured values are always sent when you give them. blocks replaces the page's whole block list.
    • Every patch carries the page's revision as baseRevision, so Pitchflow refuses the patch rather than overwrite an edit someone made in between.

Errors

Every failed call throws a PitchflowError:

import { PitchflowError } from "pitchflow-sdk";

try {
  await pitchflow.render(mapping);
} catch (e) {
  if (e instanceof PitchflowError) {
    e.status;      // HTTP status, or 0 for a network error or timeout
    e.message;     // e.g. "Variable validation failed (title: Required)"
    e.fields;      // [{ field: "title", message: "Required" }]
    e.isAuthError; // 401/403: Pitchflow rejected your API key
    e.body;        // the raw response body
  }
}

isAuthError is about your API key, not your user's session. In a web app, map it to a 502 rather than passing a 401 through, or your frontend may sign the user out.

License

MIT