htmlslop API
Upload an HTML page and get a stable, content-addressed URL. Create aliases โ stable redirect URLs you can repoint over time. All writes are signed with RFC 9421 HTTP Message Signatures.
๐ค Coding agents: the authoritative, copy-paste signing spec โ with every ambiguity resolved and a self-check test vector โ lives at /llms.txt. Verify your signature against the vector before calling the API to avoid opaque 401s.
Authentication
Every write is signed with HMAC-SHA256 using a key you've been issued (keyId + secret). The signature travels in standard headers:
Signature-Inputโ covered components + params (keyid,created,nonce,alg)Signatureโ the HMAC, base64Content-Digestโ RFC 9530sha-256of the body (on requests with a body)
Requests are rejected if created is more than 300s from server time, or if the nonce has been used before (single-use โ no replay).
How to sign (bash + openssl)
Covered components are @method, @path, and content-digest. Build the signature base exactly as shown, HMAC it, and send the three headers.
KEY_ID="k1"; SECRET="your-secret"
BODY='{"html":"<h1>hi</h1>","title":"My Page"}'
PATH_="/api/v1/upload"; METHOD="POST"
CREATED=$(date +%s)
NONCE=$(openssl rand -hex 16)
DIGEST="sha-256=:$(printf %s "$BODY" | openssl dgst -sha256 -binary | base64):"
PARAMS="(\"@method\" \"@path\" \"content-digest\");created=$CREATED;keyid=\"$KEY_ID\";nonce=\"$NONCE\";alg=\"hmac-sha256\""
# Signature base โ one line per component, then the params line (no trailing newline)
BASE=$(printf '"@method": %s\n"@path": %s\n"content-digest": %s\n"@signature-params": %s' \
"$METHOD" "$PATH_" "$DIGEST" "$PARAMS")
SIG=$(printf %s "$BASE" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)
curl -X POST https://$HOST$PATH_ \
-H "Content-Digest: $DIGEST" \
-H "Signature-Input: sig1=$PARAMS" \
-H "Signature: sig1=:$SIG:" \
-H "Content-Type: application/json" \
--data "$BODY"
Endpoints
Upload a page
POST /api/v1/upload โ body {"html", "title", "ttl"?} (html โค 5 MiB; ttl seconds, default 7d).
Returns 201 {url, expiresAt, ttl}. The URL is /<contentHash>-<title>.html and is immutable + cached aggressively. Re-uploading identical content yields the same URL. Pages are served Brotli/gzip-compressed via content negotiation.
Create an alias
POST /api/v1/aliases โ body {"title", "target"} where target is an existing page path like /<hash>-title.html.
Returns 201 {aliasId, url}. The alias URL (/alias-<id>-<title>.html) is stable and 302-redirects to the target. Not cached, so updates take effect immediately.
Update an alias
PUT /api/v1/aliases/{aliasId} โ body {"target"}. Repoints the alias to a new (existing) page. The alias URL stays the same.
Delete an alias
DELETE /api/v1/aliases/{aliasId} โ no body. Removes the alias.
Machine-readable
GET /api/v1 returns this API's shape as JSON. GET /llms.txt is the full agent reference (signing spec, schemas, error shapes, test vector) as raw text.