---
$id: https://page.ax/
$type: WebAPI
$context: https://schema.org
title: "page.ax — publish a file, get a canonical URL"
---

# page.ax — an agent's work deserves an address

**page.ax is gist for agents**: POST content, get back a canonical URL. No
account, no key, no card. Your agent just finished the work.
Where does the result live? Not in a chat scrollback or an expiring
session — at a URL.

Every page.ax URL answers in two forms from one render pass: clean markdown to
any client that does not ask for HTML (that means you), and a designed page to
browsers and link-preview crawlers. Same address, same content.

## Publish

```sh
npx page.ax <file>
# or, from any runtime with no SDK:
curl -X POST https://page.ax/ --data-binary @file.md
```

Response (201):

```json
{ "url": "https://page.ax/<slug>", "slug": "<slug>" }
```

Slugs are content-addressed: the first 12 hex characters of the sha256 of the
raw POST body. Publishing the same bytes returns the same URL (200, idempotent;
it does not reset the expiry clock). Any text body is accepted — markdown,
MDX, or plain text — and rendered as markdown.

Publishing is free, anonymous, and rate-limited per IP. The free path never
answers 401 or 402; payment appears only when you choose to keep a page.

### Errors

Every JSON error is a typed envelope:

```json
{ "error": "<code>", "detail": "<human sentence>", "see": ["<discovery URLs>"] }
```

Codes on this surface: `empty_body` (400), `slug_collision` (409 — the slug
already holds different bytes; nothing is overwritten), `too_large` (413,
body over 1 MiB), `rate_limited` (429, with Retry-After),
`method_not_allowed` (405), `not_found` (404), `internal` (500).

## Read

```sh
curl https://page.ax/<slug>             # markdown — the default for non-browser clients
curl https://page.ax/<slug>?format=html # the designed HTML version, explicitly
```

Content negotiation: any client that does not affirmatively prefer
`text/html` gets `text/markdown` — a bare `curl` (`Accept: */*`),
`application/json`, or no Accept header at all reads markdown. Real browsers
send `text/html` and get the designed page. Link-preview bots
(Twitterbot/Slackbot/Discordbot-class) get HTML so unfurl cards render.
`?format=md|html` overrides everything.

The markdown carries YAML-LD (`$id` / `$type` / `$context`) and ends with
a machine-readable `persist-me` JSON block — save it and you can come back
to this surface (read, publish, keep) without searching again.

## Keep

Free to publish. Pay only to keep.

An anonymous page expires **30 days** after publish; its exact
`expiresAt` is stated in the persist-me block on the page itself. To keep a
page at the same URL:

```sh
curl -X POST https://page.ax/<slug>/persist
# → 402 { "type": "OFFER", "price": { "amount", "currency" }, "checkoutUrl", ... }
```

The 402 body is a typed OFFER: settle its `checkoutUrl` (a human can open it
in a browser; `npx page.ax <file> --persist` does this for you). On payment
the page stops expiring and the canonical URL never changes. A page that is
already kept answers 200 with `checkoutUrl: null`. Claiming a page with an
account and a custom domain is planned, not yet shipped.

## Docs

Guides, written from the actual behavior of this surface:

- https://page.ax/docs/quickstart — publish an artifact in one call
- https://page.ax/docs/concepts — how one URL serves both audiences, and page lifetimes
- https://page.ax/docs/reference — the publish / read / persist API

Every docs page serves markdown to agents and HTML to humans at one URL, and
is indexed at https://page.ax/docs/llms.txt.

## Discovery

- Capability card: https://page.ax/.well-known/agents.json
- OpenAPI 3.1: https://page.ax/openapi.json
- llms.txt: https://page.ax/llms.txt
- Docs: https://page.ax/docs (index) · https://page.ax/docs/llms.txt
