pitchflow-sdk
v0.2.0
Published
Typed Node.js client for the Pitchflow (pflo.ai) API: templates, instantiate, page patches and PDF/PNG export.
Maintainers
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-sdkQuick 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 2Options
| 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()takespagePatches, 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.
blocksreplaces the page's whole block list. - Every patch carries the page's
revisionasbaseRevision, so Pitchflow refuses the patch rather than overwrite an edit someone made in between.
- A patch is forwarded as given: any field the page PATCH endpoint accepts (
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
