The idea
Pick one slug per report andPUT to it on every run:
- The first run creates the Page (
201). - Every later run adds a version (
200), and the same URL now shows it. - Unchanged HTML is skipped (
"deduplicated": true), so a run with nothing new costs no storage and no version. - Renaming the slug in the app does not break the job. The old slug still reaches the same Page.
Step by step
1
Create a key with Pages write
In your bot’s settings, open API keys, create a key, and turn on Pages write. The key is shown once. Keep it on your server.
2
Render the HTML
Build a complete HTML document. Give it a
<title>: it becomes the Page title when you do not send one.3
PUT it to the slug
4
Share the URL once
The response carries
url. Pin it in a channel, put it on a dashboard, or post a page_preview card. It stays valid for the life of the Page.One Page per dataset
Slugs are the unit.sales-report, support-queue and uptime-eu are three Pages, each refreshed by its own job, or by one job in a loop. Your plan caps how many Pages a workspace can hold, so reuse slugs rather than minting dated ones like sales-2026-09-21. The version history already keeps every run.
Send only what the job owns
Whatever you send is applied on every run, and whatever you leave out is left alone. Sendtitle and visibility if the job owns them. Leave them out if someone manages them in the app, otherwise the next run overwrites their change.
How often?
Posting it to a chat
The job can also tell people.POST a page_preview block to any of the bot’s conversations with the same API key, using page.id, page.title and url from the upsert response:
mid, the card updates in place instead of stacking up. See Post a message (API key).
No-code recipes
n8n
Schedule Trigger + HTTP Request.
Make
A scheduled scenario + HTTP module.
Zapier
Schedule by Zapier + a custom request.

