All posts

Publish Websites from Make, n8n and Zapier: the Hostilo REST API

Any tool that can send an HTTP request can now create, update and roll back Hostilo websites. The REST API has the same 10 actions as the MCP connector for Claude and ChatGPT, every action has its own URL, and the public openapi.json file describes the whole interface. Below: four concrete use cases and two scenarios you can import as they are, one for n8n and one for Make.

What the API does

ActionMethodWhat it does
list_sitesGETLists your sites with their ids
get_siteGETFull HTML of a site (up to 5 MB)
create_sitePOSTNew site: empty, with HTML, with files or from a template
update_sitePOSTNew HTML for a site, by id or by name
publish_filesPOSTMulti-file site: index.html, CSS, JS, images
import_zipPOSTWhole project from a ZIP file
list_templatesGETReady-made Hostilo templates
list_versionsGETSaved versions of a site
restore_versionPOSTRolls back to a chosen version
get_site_statsGETPage views and visitors

Every action lives at https://hostilo.app/api/v1/<action>. Requests and responses are JSON.

Key, limits and plan

Your first request

curl -X POST https://hostilo.app/api/v1/create_site \
  -H "Authorization: Bearer hk_..." \
  -H "Content-Type: application/json" \
  -d '{"site_name": "prices-2026", "html": "<!DOCTYPE html><html>...</html>"}'

Response:

{"success": true, "message": "Strona utworzona.", "site_id": 124, "url": "https://prices-2026.hostilo.page"}

A site name is 3 to 30 characters: lowercase letters, digits and hyphens. It becomes the address name.hostilo.page.

Use case 1: a sheet or a form becomes a website

Someone fills in a form, or you add a row to a Google Sheet, and a moment later name.hostilo.page shows a finished page. The first run creates the site, every later run replaces its content. Both ready-made scenarios work like this:

1

The scenario sends update_site with the site name in site_id.

2

If the site does not exist yet, the API answers with status 400 and the message "Strona nie istnieje…" (site does not exist). The scenario then calls create_site with the same HTML.

3

On the next row the site is already there, so the run ends at update_site. The previous version goes to the history.

POST https://hostilo.app/api/v1/update_site
{"site_id": "prices-2026", "html": "<!DOCTYPE html><html>...</html>"}

n8n

Download n8n-hostilo-publish.json and choose Import from File in n8n (or paste the file into an empty workflow). You get five nodes: Webhook → Build HTML → update_site → condition → create_site. In both Hostilo nodes create one Header Auth credential: name Authorization, value Bearer hk_.... Click Test workflow and send:

curl -X POST "<Webhook test URL>" \
  -H "Content-Type: application/json" \
  -d '{"site":"prices-2026","title":"Prices 2026","text":"Haircut: $25"}'

Instead of the webhook you can use a Google Sheets Trigger node with the columns site, title and text. When the data has an html field, the scenario publishes it unchanged, so you can put an AI model node in front that writes the whole page.

Make

Download make-hostilo-publish.json, create a new scenario and pick Import Blueprint from the three-dot menu. Modules: Google Sheets Watch Rows (column A: site name, B: title, C: text) → JSON Transform to JSON → HTTP Make an API Key Auth request with update_site → the same module with create_site and a "site does not exist yet" filter. After the import, pick your sheet and add the key: Credentials → Add, Key Bearer hk_..., API Key placement In the header, parameter name Authorization. Select the same key in both HTTP modules.

Why Transform to JSON

HTML full of quotes and line breaks, pasted straight into a request body, breaks the JSON. Transform to JSON turns it into a valid string, so the API gets exactly what is in the sheet.

Zapier

Zapier does not import scenarios from a file, so one step is enough: Webhooks by Zapier → Custom Request, method POST, URL https://hostilo.app/api/v1/update_site, headers Authorization: Bearer hk_... and Content-Type: application/json, and the JSON above in Data. The simplest setup is to create the site once in the dashboard and let the Zap only update it.

Use case 2: every new product gets its own page

A new product lands in your catalog and the scenario creates a page for it, such as spf50-cream.hostilo.page, with a description, a price and an order button. One create_site call with a name taken from the product code is enough. When the page needs its own stylesheet, script and photos, use publish_files:

POST https://hostilo.app/api/v1/publish_files
{
  "site_id": "spf50-cream",
  "files": [
    {"path": "index.html", "content": "<!DOCTYPE html><html>...</html>"},
    {"path": "style.css", "content": "body { font-family: sans-serif }"},
    {"path": "photo.jpg", "content": "/9j/4AAQ...", "encoding": "base64"}
  ]
}

index.html becomes the page, the other files go to the assets/ folder, and Hostilo fixes the links in the HTML for you. You can also start from a design: list_templates returns the templates and create_site with a template field builds the site from one. Keep the site limit in mind: 5 on Free, 20 on PRO. For a large catalog, one page with a product list refreshed by update_site works better.

Use case 3: a page that refreshes itself

A price list from a sheet, a class timetable, open booking slots, league results. A scenario that runs every hour or every morning (a Schedule Trigger node in n8n, the scenario schedule in Make) fetches the data, builds the HTML and sends update_site. Hostilo keeps the last 10 versions, so when the data source breaks something, one call takes you back:

GET  https://hostilo.app/api/v1/list_versions?site_id=prices-2026

POST https://hostilo.app/api/v1/restore_version
{"site_id": "prices-2026", "version_id": "1760601600"}

A restore also saves the current version to the history, so you can undo that step too. Once a week the same scenario can pull the stats and write the page views to a sheet or post them to Slack:

GET https://hostilo.app/api/v1/get_site_stats?site_id=prices-2026&days=7

The Free plan shows 7 days; PRO shows up to 365 days with countries, sources and devices.

Use case 4: your own GPT that publishes websites

Create a GPT in ChatGPT, then go to Configure → Actions → Create new action → Import from URL and enter https://hostilo.app/openapi.json. Authentication: API Key, Auth Type Bearer, paste your key. Use https://hostilo.app/privacy as the privacy policy. The GPT gets all 10 actions with descriptions and picks the right one when you write "publish this page as corner-cafe".

Two notes. GPT Actions accepts responses up to about 100 KB, so get_site on a very large page may not fit. And if you use ChatGPT, Claude or Perplexity just for yourself, the MCP connector is simpler: you sign in with your Hostilo account instead of copying a key.

For agencies and automation builders

One scenario can serve many client sites, because the site name is just a field from a sheet or a CRM. A client adds a promotion to the sheet, the page changes on its own, and you get version history and stats for the monthly report from one API. The /api.php?action= addresses from older integrations keep working, nothing needs rewriting. Full reference: REST documentation.

Frequently asked questions

Does the REST API cost extra?

No. It works on Free and PRO with the same limit of 60 requests per minute. The plan decides how many sites you get, how far back the stats go and whether the account needs regular visits.

How is the REST API different from the MCP connector?

The actions are the same. The MCP connector is for AI apps (Claude, ChatGPT, Perplexity, Cursor), where you sign in with your Hostilo account. REST with an hk_ key is for automation tools, scripts and custom GPTs.

Is the key safe inside a scenario?

Keep it in the tool credentials (n8n: Header Auth, Make: Credentials), not in node fields. The ready-made files do not contain it. If the key leaks, generate a new one in the dashboard and the old one stops working at once.

What happens above 60 requests per minute?

The API returns status 429 with a Retry-After header. In n8n turn on Retry On Fail or Batching in the HTTP Request node; in Make add a Sleep module between calls.

Connect your first scenario

Create a free account, generate a key under API & tools and import a ready file into n8n or Make. No credit card required.

Create a free account

More from the blog