JavaScript and TypeScript
Publish from Node.js, Deno, Bun or a serverless function with fetch.
No SDK needed: the API is plain fetch. This works in Node.js 18+, Deno, Bun and serverless runtimes. Keep the key on the server; never ship it to a browser.
const API = "https://flatpage.app/v1";
const headers = { Authorization: `Bearer ${process.env.FLATPAGE_API_KEY}` };
type Site = {
id: string;
slug: string;
url: string;
status: string;
version: number | null;
};
type PublishResult = {
uploadId: string;
status: string;
site?: Site;
warnings?: string[];
};
async function call<T>(path: string, init: RequestInit = {}): Promise<T> {
const res = await fetch(`${API}${path}`, {
...init,
headers: { ...headers, ...init.headers },
});
if (!res.ok) {
const { error } = await res.json().catch(() => ({ error: res.statusText }));
throw new Error(`Flatpage ${res.status}: ${error}`);
}
return res.status === 204 ? (undefined as T) : res.json();
}
/** Waits for a publish that answered 202 (still processing). */
async function untilLive(result: PublishResult): Promise<Site> {
for (let i = 0; !result.site && i < 30; i++) {
await new Promise((r) => setTimeout(r, 2000));
result = await call<PublishResult>(`/uploads/${result.uploadId}`);
}
if (!result.site) throw new Error("Still processing after a minute");
return result.site;
}
/** Publishes HTML as a new site, or as a new version of `site` when given. */
export async function publishHtml(
html: string,
opts: { site?: string; linkName?: string } = {},
) {
const result = await call<PublishResult>(
opts.site ? `/sites/${opts.site}` : "/sites",
{
method: opts.site ? "PUT" : "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
html,
linkName: opts.site ? undefined : opts.linkName,
}),
},
);
return untilLive(result);
}
/** Publishes a .zip or .pdf from disk (up to 25 MB). */
export async function publishFile(
path: string,
contentType: "application/zip" | "application/pdf",
site?: string,
) {
const { readFile } = await import("node:fs/promises");
const result = await call<PublishResult>(site ? `/sites/${site}` : "/sites", {
method: site ? "PUT" : "POST",
headers: { "Content-Type": contentType },
body: await readFile(path),
});
return untilLive(result);
}Use it:
const site = await publishHtml(
"<!doctype html><title>Report</title><h1>Q3 report</h1>",
{
linkName: "q3-report",
},
);
console.log(site.url); // https://q3-report.flatpage.page
// Later: same link, new content
await publishHtml(nextVersionHtml, { site: "q3-report" });Want types for every response? Generate them from the OpenAPI spec, for example with npx openapi-typescript https://flatpage.app/openapi.json -o flatpage.d.ts.