ginta

Files and routing

A site is a set of files served at https://<name>.ginta.page/ (or its own domain). index.html is the home page.

index.html          → /
about.html          → /about         (/about.html redirects there)
blog/index.html     → /blog/
blog/first.html     → /blog/first
404.html            → any unknown address (status 404)
_redirects          → redirects and rewrites (below)
assets/app-B8f2.js  → /assets/app-B8f2.js
img/hero.avif       → /img/hero.avif
.well-known/security.txt

Links to .html pages are shown without .html. Root-relative links (/assets/app.js) work: every site has its own origin.

File types

Text (editable with find/replace) Binary (uploaded as bytes)
html css js mjs json map webmanifest xml svg txt md csv, _redirects png jpg jpeg webp avif gif ico woff woff2 ttf otf pdf wasm mp4 webm mp3

Names: letters, digits, ., -, _; folders up to 10 deep; a leading _ is fine (_next/, _astro/); hidden files aren't (except .well-known/). _g/, _m/, _ginta/, f/, s/ are Ginta's. A binary file must really be what its extension says. How many files and MB: limits.

_redirects

Netlify / Cloudflare Pages format, one rule per line:

/old-menu        /menu              301
/blog/:slug      /news/:slug        301
/docs/*          /help/:splat       302
/shop            https://shop.example.com/   302
/*               /index.html        200
  • Status 301 (default), 302, 303, 307, 308: redirects. They apply before files.
  • Status 200: a rewrite (another file answers, the address stays). Only when no file matches, so /* /index.html 200 is the single-page-app fallback.
  • Redirects to another website work on paid plans.

Uploading

  • create_site / update_site: files with content (text) or content_base64 (binary).
  • upload_files: many files, or a url per file Ginta downloads; no files → an upload link for a .zip (Claude Code).
  • Every change is a version; restore_version undoes one. The last 20 versions are kept.

JavaScript

Your own scripts, modules and WebAssembly run as they are. Not allowed: scripts from other websites (bundle libraries instead), service workers, password or card-number fields (also when JavaScript creates them), forms posting to other websites, pages imitating a bank/payment/tech login, crypto seed phrases. Pages may only fetch their own address: outside APIs go through a connection.

Forms

<form method="POST" action="/f/__SITE_ID__">
  <input type="text" name="_gotcha" hidden>
  <input name="email" type="email" required> <textarea name="message"></textarea> <button>Send</button>
</form>

__SITE_ID__ is filled in at publish. With fetch(…, { headers: { Accept: "application/json" } }) the answer is JSON. Messages: get_messages and Your sites → Messages.

REST API

The same with a signed-in session (cookie) and an Origin: https://ginta.app header:

POST /api/sites create { name, files }
PUT /api/sites/<id> change { edits, files, delete, notify_email }
GET /api/sites/<id>/files read
POST /api/sites/<id>/upload-link { "mode": "replace" | "merge" } → upload link for a .zip
GET /api/sites/<id>/versions, POST /api/sites/<id>/rollback history, undo
GET /api/sites/<id>/stats, GET /api/sites/<id>/speed visitors, scores
PUT /api/sites/<id>/secrets/<NAME>, PUT /api/sites/<id>/connections/<name> secrets, connections