Trace one Markdown loose file to see what an Energon success response guarantees. The path matters because a 201 confirms coordinated work across token authentication, policy resolution, quota reservation, R2 storage, D1 catalog commit, cache invalidation, and URL construction. The response then splits into a public content URL on the content origin and an authenticated API URL on the hub origin.
Data flow: a Markdown handoff
End-to-end sequence
1. The router establishes an agent actor
POST /v1/files dispatches only after the router has applied the content-host boundary and schema bootstrap. Authenticated /v1 routes live in auth-class tables in src/v1-routes.ts. The files POST row calls requireToken, then postLooseFromRequest (src/v1-routes.ts:161-164). Authentication validates the advertised token prefix, hashes the presented secret, looks up its D1 row, rejects revocation or expiry, applies the email-domain policy, and returns the owner’s normalized actor (src/auth.ts:83-118).
The agent can prove this boundary before publishing:
ENERGON_ORIGIN="https://energon.your-company.example"
test -n "$ENERGON_TOKEN" || { echo "Set the token minted by this host" >&2; exit 1; }
curl -fsS "$ENERGON_ORIGIN/v1/whoami" \
-H "Authorization: Bearer $ENERGON_TOKEN"2. The request becomes one loose-file object
The request parser distinguishes raw bytes, multipart uploads, and server-side duplication. A raw body requires X-Filename; JSON with that header is treated as file content, not as a duplication command (src/files.ts). createLooseFile then sanitizes the name, validates the Energon byte limit and content-origin configuration, resolves the publisher’s stable handle, mints an id, detects the content type, and resolves share password, write password, TTL, and write policy.
3. R2 bytes and D1 metadata converge
The create path reserves quota, writes the bytes to R2, and inserts the catalog row in D1. If the catalog insert fails, it deletes the just-written R2 object and releases the reservation instead of returning a partial success (src/files.ts). Only after both layers agree does it build url from CONTENT_ORIGIN, build api_url from PUBLIC_ORIGIN, purge the object’s public cache prefix, and return 201 (src/urls.ts).
4. The two returned URLs serve different recipients
The public handler looks up the id and handle in D1, enforces expiry and an optional share-password gate, canonicalizes the current filename, and fetches R2 (src/files.ts). A valid X-Energon-Write-Password skips that share gate on GET. A browser requesting HTML receives sanitized rendered Markdown; curl, ?raw=1, or the authenticated API returns source bytes (src/markdown.ts). The receiving agent uses its own token on api_url; no publisher credential travels with the link. Serving bytes also stamps last read in the background.
Guest PUT and site-path DELETE never enter those /v1 helpers. The router classifies the content host, then src/guest-write.ts authorizes WriteAuthority from the write-password header, mutates R2 and D1 with the current write hash in the predicate, and returns JSON without hub or api_url (src/index.ts:370-399; src/guest-write.ts). Last writer stays the last account; written_via records shared write. Site public paths include the site id before the slug. From v1.10.0, a guest site-path write publishes a new site version that keeps the other paths, the same way an authenticated path PUT does.
Never reconstruct the two URLs from a guessed hostname, handle, or id. Keep the response fields. A share password protects only public-content reads; a write password authorizes guest PUT on that same URL; any valid agent key on this Energon can read a public object’s authenticated API URL in api_url without either public password. A private object answers its public URL with 403 link_private and its API URL only for the creating account’s keys.
Try this flow in Publish through the HTTP API, then use Manage shared work for replacement and duplication. Let an outside agent update a URL covers tokenless PUT. Security model explains each trust boundary, and Architecture and integrity covers rollback for more complex mutations.