Web Hosting

Hosting API Guide

Everything your other VPS needs to deploy and control HTML pages on this host.

Overview

What this is

A web-page hosting service. From any machine you can create "sites", push HTML/CSS/JS/asset files into them over HTTP, and control who can see them. Files are served directly by this host:

  • Path URL (always on): https://beast-builder.marklo.de/h/<slug>/
  • Optional subdomain: https://<slug>.beast-builder.marklo.de/ (enable per-site)

A site can be public (anyone with the link) or private (needs an access key — good for sharing with friends), and can be open or temporarily closed.

Human vs. machine

Your other VPS never "reads docs" — it just calls the API with a token. You (a person) read this guide in the browser, then drop the token + a script onto that machine.

ForWhereAuth
Human (this guide, management)https://beast-builder.marklo.de/hostingDashboard login (basic auth)
Machine (your other VPS)https://beast-builder.marklo.de/hostapi/v1/…Bearer token only — no dashboard password

Connect your other VPS in 3 steps

1. In this browser, go to API KeysCreate API Key → copy the token from the popup (looks like bbh_…).

2. On your other VPS, set the base URL + token and verify:

export BASE="https://beast-builder.marklo.de/hostapi/v1"
export TOKEN="bbh_paste-your-token-here"

curl -s "$BASE/ping" -H "Authorization: Bearer $TOKEN"
# expect: {"ok":true,"service":"beast-builder-hosting",...}

3. Publish a local site directory (multi-page, with subfolders):

#!/usr/bin/env bash
set -euo pipefail
BASE="https://beast-builder.marklo.de/hostapi/v1"
TOKEN="bbh_your-token"
SLUG="mysite"          # decides the URL: /h/mysite/
DIR="./public"         # your built static-site folder

auth=(-H "Authorization: Bearer $TOKEN")

# create the site (ignore error if it already exists)
curl -s -X POST "$BASE/sites" "${auth[@]}" -H "Content-Type: application/json" \
  -d "{\"slug\":\"$SLUG\",\"name\":\"My Site\"}" >/dev/null || true

# upload every file, preserving relative paths (about.html, blog/post1.html, assets/x.png …)
( cd "$DIR" && find . -type f | sed 's|^\./||' | while read -r f; do
    curl -s -X PUT "$BASE/sites/$SLUG/files/$f" "${auth[@]}" --data-binary "@$f" >/dev/null
    echo "uploaded $f"
  done )

# make sure it is open
curl -s -X PATCH "$BASE/sites/$SLUG" "${auth[@]}" -H "Content-Type: application/json" \
  -d '{"status":"active"}' >/dev/null

echo "Live: https://beast-builder.marklo.de/h/$SLUG/"

Then open https://beast-builder.marklo.de/h/mysite/.

Common operations (run from your other VPS)

# deploy a whole multi-page site in one shot
zip -r site.zip . && curl -s -X POST "$BASE/sites/$SLUG/deploy-zip?clean=true" "${auth[@]}" -F "file=@site.zip"

# temporarily close / re-open (visitors get 503 while closed)
curl -s -X PATCH "$BASE/sites/$SLUG" "${auth[@]}" -H 'Content-Type: application/json' -d '{"status":"closed"}'
curl -s -X PATCH "$BASE/sites/$SLUG" "${auth[@]}" -H 'Content-Type: application/json' -d '{"status":"active"}'

# make private (share with friends) — response contains share_url with ?k=…
curl -s -X PATCH "$BASE/sites/$SLUG" "${auth[@]}" -H 'Content-Type: application/json' -d '{"visibility":"private"}'

# enable the per-site subdomain URL
curl -s -X PATCH "$BASE/sites/$SLUG" "${auth[@]}" -H 'Content-Type: application/json' -d '{"subdomain_enabled":true}'

# delete one page / delete the whole site
curl -s -X DELETE "$BASE/sites/$SLUG/files/old.html" "${auth[@]}"
curl -s -X DELETE "$BASE/sites/$SLUG" "${auth[@]}"

Bearer token

Create a token on the API Keys page (shown once). Send it on every API request:

Authorization: Bearer <your-token>

Base API URL: https://beast-builder.marklo.de/hostapi/v1 — public (not behind the dashboard login); the token is the only credential. The management UI under /hosting stays behind the dashboard login.

Quick check:

curl -s https://beast-builder.marklo.de/hostapi/v1/ping \
  -H "Authorization: Bearer $TOKEN"

Endpoints

Method & pathPurpose
GET /hostapi/v1/pingVerify token & connectivity
GET /hostapi/v1/sitesList all sites
POST /hostapi/v1/sitesCreate a site
GET /hostapi/v1/sites/{slug}Site details + file list
PATCH /hostapi/v1/sites/{slug}Update name/visibility/status/subdomain/index/rotate key
DELETE /hostapi/v1/sites/{slug}Delete site + all files
GET /hostapi/v1/sites/{slug}/filesList files
PUT /hostapi/v1/sites/{slug}/files/{path}Upload/replace one file (raw body or multipart file)
DELETE /hostapi/v1/sites/{slug}/files/{path}Delete one file
POST /hostapi/v1/sites/{slug}/pagesUpload an HTML page from JSON {path, html}
POST /hostapi/v1/sites/{slug}/deploy-zipDeploy a whole multi-page site from a .zip (?clean=true to wipe first)

Create a site

curl -s -X POST https://beast-builder.marklo.de/hostapi/v1/sites \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"slug":"mysite","name":"My Site","visibility":"public"}'

Response includes url_path and (for private sites) access_key + share_url.

Upload a single page or asset

# raw body — content-type comes from the path extension
curl -s -X PUT https://beast-builder.marklo.de/hostapi/v1/sites/mysite/files/index.html \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: text/html" \
  --data-binary @index.html

# nested path / asset
curl -s -X PUT https://beast-builder.marklo.de/hostapi/v1/sites/mysite/files/assets/logo.png \
  -H "Authorization: Bearer $TOKEN" --data-binary @logo.png

Upload an HTML page from JSON

curl -s -X POST https://beast-builder.marklo.de/hostapi/v1/sites/mysite/pages \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"path":"about.html","html":"<h1>About</h1><a href=\"index.html\">home</a>"}'

Deploy a whole multi-page site (.zip)

cd my-site && zip -r ../site.zip . && cd ..
curl -s -X POST "https://beast-builder.marklo.de/hostapi/v1/sites/mysite/deploy-zip?clean=true" \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@site.zip"

Open / close & access control

# temporarily close (visitors get 503)
curl -s -X PATCH https://beast-builder.marklo.de/hostapi/v1/sites/mysite \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"status":"closed"}'

# make private + get a shareable key
curl -s -X PATCH https://beast-builder.marklo.de/hostapi/v1/sites/mysite \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"visibility":"private"}'
# -> response.share_url looks like https://beast-builder.marklo.de/h/mysite/?k=XXXX  (send this to friends)

# enable the subdomain URL
curl -s -X PATCH https://beast-builder.marklo.de/hostapi/v1/sites/mysite \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"subdomain_enabled":true}'

Multi-page sites & interlinks

Within a site, link between pages using relative paths so links work under /h/<slug>/:

<a href="about.html">About</a>            <!-- good -->
<a href="blog/post1.html">Post 1</a>      <!-- good (nested) -->
<img src="assets/logo.png">               <!-- good -->
<a href="/about.html">About</a>           <!-- avoid: root-absolute breaks under /h/<slug>/ -->

The site root serves index.html by default (configurable per site). If you enable the subdomain URL, both relative and root-absolute links work because each site sits at its own root.

Deploy script for your other VPS

#!/usr/bin/env bash
set -euo pipefail
BASE="https://beast-builder.marklo.de/hostapi/v1"
TOKEN="bbh_xxx_your_token"
SLUG="mysite"

auth=(-H "Authorization: Bearer $TOKEN")

# 1) create the site (ignore error if it already exists)
curl -s -X POST "$BASE/sites" "${auth[@]}" -H "Content-Type: application/json" \
  -d "{\"slug\":\"$SLUG\",\"name\":\"My Site\"}" || true

# 2) push every file in ./public, preserving relative paths
cd public
find . -type f | sed 's|^\./||' | while read -r f; do
  curl -s -X PUT "$BASE/sites/$SLUG/files/$f" "${auth[@]}" --data-binary "@$f" >/dev/null
  echo "uploaded $f"
done

# 3) make sure it is open
curl -s -X PATCH "$BASE/sites/$SLUG" "${auth[@]}" -H "Content-Type: application/json" \
  -d '{"status":"active"}' >/dev/null

echo "Live at https://beast-builder.marklo.de/h/$SLUG/"