Outpost API
Host SPAs and static HTML under short URLs (/p/<id>) with three
flavors of authentication and a built-in MCP server. This reference covers
every HTTP endpoint the service exposes.
https://outpost.click.
Development: http://localhost:8000 (started with
uvicorn app.main:app --reload).
Quick start
1. Get an API token
Log in at /login, create a token at /tokens. The full token is shown once; save it.
2. Create a page from a ZIP
curl -X POST https://outpost.click/api/pages \
-H "Authorization: Bearer op_YOUR_TOKEN" \
-F "name=Hello World" \
-F "visibility=public" \
-F "file=@./site.zip"
The response includes the live URL:
{
"id": "Ab12Cd34",
"name": "Hello World",
"visibility": "public",
"default_file": "index.html",
"url": "https://outpost.click/p/Ab12Cd34",
"created_at": "2026-05-03T17:42:11"
}
3. Or import from a URL
curl -X POST https://outpost.click/api/pages \
-H "Authorization: Bearer op_YOUR_TOKEN" \
-F "name=Mirror" \
-F "visibility=public" \
-F "source_url=https://example.com"
4. Or upload a single HTML file
curl -X POST https://outpost.click/api/pages \
-H "Authorization: Bearer op_YOUR_TOKEN" \
-F "name=Notes" \
-F "visibility=public" \
-F "file=@./notes.html"
Endpoint cheatsheet
Authentication (details)
| Method | Path | Auth | Purpose |
|---|---|---|---|
| POST | /auth/register | none | Register an email/password user (when enabled). |
| POST | /auth/login | none | Exchange credentials for a JWT and token cookie. |
| POST | /auth/logout | none | Clear the token cookie. |
| GET | /auth/me | bearer | Return the current user. |
| GET | /auth/auth0/login | none | Begin Auth0 authorization-code flow. |
| GET | /auth/callback | none | Auth0 redirect target. |
| GET | /auth/google/login | none | Begin Google OAuth flow. |
| GET | /auth/google/callback | none | Google redirect target. |
| GET | /auth/complete | none | Helper page that stores the JWT in localStorage. |
Pages CRUD (details)
| Method | Path | Purpose |
|---|---|---|
| GET | /pages | List the caller's pages. |
| POST | /pages | Create a page from upload or source_url. |
| PUT | /pages/{page_id} | Update metadata or replace files. |
| DELETE | /pages/{page_id} | Delete a page and its files. |
Public page serving (details)
| Method | Path | Purpose |
|---|---|---|
| GET | /p/{page_id} | Redirect to the page's default file. |
| GET | /p/{page_id}/{path} | Serve a stored file (or the access gate). |
| POST | /p/{page_id}/verify | Submit a passcode to unlock the page (sets cookie). |
API tokens (details)
| Method | Path | Purpose |
|---|---|---|
| POST | /api/tokens | Create a new op_… token. |
| GET | /api/tokens | List the caller's tokens (no secrets). |
| PUT | /api/tokens/{id} | Rename a token. |
| DELETE | /api/tokens/{id} | Revoke a token. |
Programmatic upload (details)
| Method | Path | Purpose |
|---|---|---|
| POST | /api/pages | Create a page using an op_… token. |
| POST | /api/pages/{page_id}/files | Replace files on an existing page. |
| POST | /upload/{token} | Upload using a short-lived signed token. |
Model Context Protocol (details)
| Method | Path | Purpose |
|---|---|---|
| GET | /mcp | Open an SSE session, receive the message endpoint. |
| POST | /mcp/message?session_id=… | JSON-RPC channel for an SSE session. |
| POST | /mcp | Stateless Streamable HTTP JSON-RPC endpoint. |
Conventions
Authorization header
All authenticated endpoints accept the standard
Authorization: Bearer <token> header. The token may be:
- A JWT (HS256, issued by
/auth/loginor one of the OAuth callbacks). - An API token starting with
op_(created via/api/tokens). - An Auth0 RS256 ID token if Auth0 is enabled.
The server auto-detects the token type by the op_ prefix versus
JWT structure.
Cookies
token— the session JWT,HttpOnly,SameSite=Lax, 24-hourmax_age.page_access_<page_id>— set by the access-gate verifier after a correct passcode is supplied.
Errors
Errors are FastAPI HTTPException JSON responses:
{ "detail": "Invalid credentials" }
Validation failures use the standard FastAPI 422 envelope:
{
"detail": [
{
"loc": ["body", "password"],
"msg": "ensure this value has at least 8 characters",
"type": "value_error.any_str.min_length"
}
]
}
Cache headers
Page-serving routes set Cache-Control: no-store, no-cache,
must-revalidate, max-age=0 plus Pragma: no-cache and
Expires: 0 when the page is non-public
(private/shared) or when any passcode is configured.
Public pages without passcodes inherit FastAPI defaults.
Date format
All timestamps are ISO-8601 strings serialized from naive UTC
datetime values stored in Postgres
(e.g. "2026-05-03T17:42:11").
Page id format
Page ids are exactly 8 characters from
[A-Za-z0-9], generated by secrets.choice and verified
unique against the pages table before insertion.
Data model summary
See the linked sub-pages for full request/response shapes. The Postgres
schema is created on startup by init_schema() and contains:
users— id, email, password_hash, org_id, created_at.pages— id (8 chars), owner_id, name, visibility, passcode_hashes (encrypted), allowed_emails, default_file, created_at, updated_at.page_files— page_id, file_path, content (BYTEA), content_type. Files live in the database, not on disk.api_tokens— user_id, name, token_hash (SHA-256), token_prefix (first 12 chars), status, created_at, last_used_at.