ephemr docs cli mcp pricing
login signup

API Docs

The job

Publish a static page, send the URL, and let it expire. The default life is 72 hours. A shorter ttl is allowed. Over 72 hours is rejected. Pin keeps an already-live page reachable after that clock. Unpin or delete when it should die.

The URL is public. Anyone with the link can open the page and its files. Do not publish secrets or private client work. There is no server-side execution.

Quick start with the CLI

brew install veturu/ephemr/ephemr   # or: curl -sSf https://ephemr.io/install.sh | sh
ephemr login                        # paste your API key (stored in ~/.config/ephemr/config.json)
ephemr publish ./site/              # auto-zips the directory and returns the URL
ephemr publish page.html --ttl 24h  # single HTML file, custom TTL
ephemr list                         # see all your pages and their expiry
ephemr pin <slug>                   # keep a live page reachable after expiry
ephemr extend <slug> --ttl 72h      # refresh expiry up to the default cap
ephemr delete <slug>                # take a page down early

Full CLI docs: /cli. For use inside AI editors (Claude Desktop, Cursor, Codex): /mcp.

HTTP API

Everything the CLI and MCP server do is available as plain HTTP. The reference below covers every endpoint.

Authentication

Pass your API key as Authorization: Bearer eph_live_.... Create keys in the portal. The raw key is shown once — store it securely.

Publish a page

POST /api/v1/pages
Authorization: Bearer eph_live_...
Content-Type: multipart/form-data

fields:
  archive:          zip (index.html at root) or a single .html/.htm file
  html:             optional raw HTML instead of archive (exactly one of archive or html)
  ttl:              optional Go duration (30m, 24h, 72h). Omit for the default TTL.
                    Must be at least 1 minute and at most the account default.
                    Over the cap returns 400 ttl_exceeds_limit (not clamped).
  title:            optional
  description:      optional
  alias:            optional — publish to a stable alias URL
  replace_previous: optional, "true" — delete the alias's old target page
                    (by default it stays active at its own slug URL and
                    keeps counting against your active-page quota)

Example with curl:

curl -X POST https://ephemr.io/api/v1/pages \
  -H "Authorization: Bearer $EPHEMR_API_KEY" \
  -F "archive=@site.zip" \
  -F "title=my demo" \
  -F "ttl=24h"

A zip that lacks index.html still fails. A single HTML upload is wrapped as a one-file site whose entry is index.html.

Response:

{
  "id": "uuid",
  "slug": "abc123xy",
  "url": "https://abc123xy.pages.ephemr.io/",
  "hostname": "abc123xy.pages.ephemr.io",
  "status": "active",
  "pinned": false,
  "created_at": "...",
  "expires_at": "..."
}

List your pages

GET /api/v1/pages
Authorization: Bearer eph_live_...

Extend, pin, unpin

These act on an active page you own. Pin keeps a page reachable after expires_at. Pinned pages still count against the active-page limit.

POST /api/v1/pages/{id}/extend
Authorization: Bearer eph_live_...
Content-Type: application/json

{"ttl": "24h"}

Sets a new expires_at of now+ttl (default: the account default). The new expiry must be in the future and at most now+default TTL. This can lengthen a short publish up to the free cap, or refresh the window; it cannot set a multi-year expiry.

POST /api/v1/pages/{id}/pin
POST /api/v1/pages/{id}/unpin
Authorization: Bearer eph_live_...

Unpin of a page whose expires_at is already past sets a new expiry within the same cap (default now+default TTL) unless you supply a valid ttl.

Delete a page

DELETE /api/v1/pages/{id}
Authorization: Bearer eph_live_...

Aliases

Aliases are stable, human-readable URLs you own (e.g. myapp.pages.ephemr.io). When you publish to an alias, the alias URL always points at the latest deploy.

POST /api/v1/aliases
Authorization: Bearer eph_live_...
Content-Type: application/json

{"name": "myapp"}

Response (201):

{"id": "uuid", "name": "myapp", "hostname": "myapp.pages.ephemr.io"}
GET /api/v1/aliases
Authorization: Bearer eph_live_...

Returns {"aliases": [...]}.

DELETE /api/v1/aliases/{id}
Authorization: Bearer eph_live_...

Returns 204. The current target page remains reachable at its own slug URL.

Page events

GET /api/v1/pages/{id}/events
Authorization: Bearer eph_live_...

Returns the lifecycle timeline for a page: {"events": [{"id", "type", "data", "created_at"}, ...]}.

Limits (free accounts)

Errors

{ "error": { "code": "...", "message": "..." } }