How this site works

Want to post your own content here?

Posting is currently by invitation. If you'd like the ability to publish your own projects to fortiers.com, email rick@fortiers.com and ask to be added as a user.

What this site is

fortiers.com is a project ledger — a running, dated index of projects built and shipped. Each entry has a title, a short description, a date, and a link. The homepage lists them newest-first.

It's also a host: a project can be more than a link — its actual files (a static site, game, tool, or demo) can live here, served from fortiers.com/projects/<name>/.

There are two ways to post: by hand through the admin page, or programmatically through a REST API — so an AI agent (Hermes, Claude Code, or any script) can be told "post this site to fortiers.com" and do it in one HTTP call.

Posting via the admin page

  1. Go to /admin.php and log in. (The very first visit asks you to create the password.)
  2. Fill in the Add a project form:
    FieldRequiredNotes
    TitleyesShown big in the ledger.
    DescriptionnoOne or two sentences under the title.
    Where it livesyesHosted here (files served from /projects/<slug>/) or External site (the entry links to a URL you provide).
    Slug namenoHosted only — the folder name under /projects/. A random UUID is used if blank.
    Page filenoHosted only — a single .html file that becomes the project's index.html (max 5 MB), or a .zip of the whole site with index.html at its root (max 50 MB; replaces any previous files for that slug).
    DatenoDefaults to today; controls ordering (newest first).
    ScreenshotnoJPG/PNG/GIF/WebP, max 5 MB. Shown as a thumbnail.
  3. Click Add to ledger — it's live on the homepage immediately. No publish step.

Publishing via the API

This is the here.now-style flow, meant for agents and scripts.

1. Get an API key

Log in to /admin.phpAPI Key tab → Generate API key. Give the key to your agent (e.g. as an environment variable). Every API request must send it as an X-API-Key header.

2. Publish a hosted site

Zip your site so index.html is at the zip root (a single wrapping folder is also fine — it gets flattened), then:

curl -X POST https://fortiers.com/api.php \
  -H "X-API-Key: ftr_..." \
  -F "title=My Cool Project" \
  -F "description=What it does, in a sentence." \
  -F "site=@site.zip"

The response tells you where it lives:

{
  "ok": true,
  "url": "https://fortiers.com/projects/my-cool-project/",
  "project": { "id": "53bb89cac954", "title": "My Cool Project", ... }
}

The site is now served at that URL and a ledger entry pointing to it appears on the homepage.

3. Or just add a ledger entry (no hosting)

Skip the site file and pass a link to wherever the project already lives:

curl -X POST https://fortiers.com/api.php \
  -H "X-API-Key: ftr_..." \
  -F "title=My Repo" \
  -F "link=https://github.com/me/my-repo"
Tip for agents: ask the human for Title and Description before posting, zip the build output, POST once, then reply with the url from the JSON response.

How hosted project sites work

Updating & deleting

From the admin page

The Entries list on /admin.php has Edit and Delete next to every project. Edit pre-fills the form; uploading a new screenshot replaces the old one, leaving it empty keeps it.

From the API

# find the id
curl https://fortiers.com/api.php

# delete the ledger entry
curl -X DELETE "https://fortiers.com/api.php?id=53bb89cac954" \
  -H "X-API-Key: ftr_..."
API delete removes the ledger entry. The hosted files at /projects/<slug>/ stay until overwritten by a new deploy or removed from the admin side — so a deleted entry's demo link keeps working if anyone still has it.

Lost password or leaked key?

API reference

MethodEndpointAuthDoes
GET/api.phpnoneList all projects as JSON.
POST/api.phpkeyPublish: fields title (required), description, date (YYYY-MM-DD), link, slug, site (zip file). A zip overrides link.
DELETE/api.php?id=…keyRemove a ledger entry by id.

Auth header: X-API-Key: <your key>. Errors come back as JSON with ok: false and an error message; success is HTTP 200/201 with ok: true.