FlatpageDocs

Python

Publish from Python scripts, notebooks and data pipelines with requests.

Install requests (pip install requests) and set FLATPAGE_API_KEY in your environment.

flatpage.py
import os
import time

import requests

API = "https://flatpage.app/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['FLATPAGE_API_KEY']}"


def _check(res: requests.Response) -> dict:
    if not res.ok:
        try:
            message = res.json()["error"]
        except ValueError:
            message = res.reason
        raise RuntimeError(f"Flatpage {res.status_code}: {message}")
    return res.json() if res.content else {}


def _until_live(result: dict) -> dict:
    """Waits for a publish that answered 202 (still processing)."""
    for _ in range(30):
        if result.get("site"):
            return result["site"]
        time.sleep(2)
        result = _check(session.get(f"{API}/uploads/{result['uploadId']}"))
    raise TimeoutError("Still processing after a minute")


def publish(path: str, site: str | None = None, link_name: str | None = None) -> dict:
    """Publishes an .html, .zip or .pdf file (up to 25 MB). Pass `site` to update that site in place."""
    content_type = {
        ".html": "text/html",
        ".zip": "application/zip",
        ".pdf": "application/pdf",
    }[os.path.splitext(path)[1].lower()]
    with open(path, "rb") as f:
        if site:
            res = session.put(f"{API}/sites/{site}", data=f, headers={"Content-Type": content_type})
        else:
            params = {"linkName": link_name} if link_name else {}
            res = session.post(f"{API}/sites", data=f, params=params, headers={"Content-Type": content_type})
    return _until_live(_check(res))


def publish_html(html: str, site: str | None = None, link_name: str | None = None) -> dict:
    """Publishes an HTML string, for example a report you just rendered."""
    if site:
        res = session.put(f"{API}/sites/{site}", json={"html": html})
    else:
        res = session.post(f"{API}/sites", json={"html": html, "linkName": link_name})
    return _until_live(_check(res))

Use it:

site = publish("report.html", link_name="weekly-report")
print(site["url"])  # https://weekly-report.flatpage.page

# Every Monday: same link, new numbers
publish("report.html", site="weekly-report")

# Views for the last 30 days
stats = _check(session.get(f"{API}/sites/weekly-report/stats"))
print(stats["last30Days"]["total"])

Notebooks and charts

Export a notebook or a Plotly/Altair chart to a single HTML file (jupyter nbconvert --to html, fig.write_html(..., include_plotlyjs="cdn")) and publish it with publish(). Keep it self-contained: relative links to files you didn't upload won't load.