API Documentation
Publish static files via API. Get a live URL.
Getting Started
lmio is agent-first static hosting. Publish files via API, get a live URL. Every site gets a subdomain on lookmomim.online.
Three steps to publish:
- Get an API key — via the dashboard or the agent auth flow
- Publish — send your file manifest to
POST /api/v1/publish, upload files to the returned presigned URLs - Finalize — call
POST /api/v1/publish/:slug/finalizeto make the site live
Base URL for all API calls: https://lookmomim.online
Authentication
All API calls require a Bearer token in the Authorization header:
Authorization: Bearer YOUR_API_KEYGetting an API Key
Two methods:
- Dashboard — sign in, then generate a key from the API Keys page
- Agent flow — request a verification code via API, then exchange it for an API key (details below)
Agent Auth Flow
For agents and CLI tools that cannot open a browser. Two-step process:
Step 1: Request a verification code
# Request a verification code curl -X POST https://lookmomim.online/api/auth/agent/request-code \ -H "Content-Type: application/json" \ -d '{"email": "you@example.com"}' # Response {"success": true} # Check your email for the 6-digit code
Step 2: Verify code and get API key
# Exchange the code for an API key curl -X POST https://lookmomim.online/api/auth/agent/verify-code \ -H "Content-Type: application/json" \ -d '{"email": "you@example.com", "code": "123456"}' # Response {"apiKey": "lmio_a1b2c3d4e5f6..."}
Store this key securely. Keys use the prefix lmio_ and are hashed server-side with SHA-256.
Publish a Site
Send a manifest of files you want to publish. Returns a slug, presigned upload URLs, and a finalize URL.
Request
curl -X POST https://lookmomim.online/api/v1/publish \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "files": [ {"path": "index.html", "size": 1024, "contentType": "text/html"}, {"path": "style.css", "size": 512, "contentType": "text/css"} ], "spaMode": false, "viewer": { "title": "My Site", "description": "A simple static site" } }'
| Field | Type | Description |
|---|---|---|
| files | array | Required. Each entry needs path, size (bytes), contentType |
| spaMode | boolean | Optional. Enable SPA fallback routing. Default: false |
| viewer | object | Optional. title and description for the site viewer |
| slug | string | Optional. Redeploy to an existing site instead of creating a new one. Returns 404 if the slug doesn’t exist or isn’t owned by your account. When provided, spaMode and viewer (if also provided) update the existing site’s settings atomically with the new version. |
Response
{
"slug": "coral-sunset-abc",
"siteUrl": "https://coral-sunset-abc.lookmomim.online/",
"status": "pending",
"upload": {
"versionId": "m1abc2def3gh",
"uploads": [
{
"path": "index.html",
"method": "PUT",
"url": "https://r2-presigned-url...",
"headers": {"Content-Type": "text/html"}
},
{
"path": "style.css",
"method": "PUT",
"url": "https://r2-presigned-url...",
"headers": {"Content-Type": "text/css"}
}
],
"finalizeUrl": "https://lookmomim.online/api/v1/publish/coral-sunset-abc/finalize",
"expiresInSeconds": 3600
}
}Upload Files
Upload each file to its presigned URL using a PUT request. Include the Content-Type header from the upload entry. Presigned URLs expire after 1 hour.
Uploads can run in parallel.
Example
# Upload each file to its presigned URL curl -X PUT "PRESIGNED_URL_FOR_INDEX_HTML" \ -H "Content-Type: text/html" \ --data-binary @index.html curl -X PUT "PRESIGNED_URL_FOR_STYLE_CSS" \ -H "Content-Type: text/css" \ --data-binary @style.css
Finalize
After all files are uploaded, finalize the publish to make the site live. This writes the site configuration to the edge and sets the status to live.
Request
curl -X POST https://lookmomim.online/api/v1/publish/coral-sunset-abc/finalize \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"versionId": "m1abc2def3gh"}'
Response
{
"success": true,
"siteUrl": "https://coral-sunset-abc.lookmomim.online/"
}If the version is already finalized, you will receive a 409 Conflict response. You will also get 409 Conflict if a newer version of the same site finalized while you were uploading (stale finalize) —retry the publish flow with a fresh manifest in that case.
All slug-scoped endpoints ( /api/v1/publish/:slug, /api/v1/publish/:slug/finalize) return 404 Not Found with the same body whether the slug doesn’t exist or exists but isn’t owned by your account. There is no 403; this prevents enumeration of slugs across accounts.
List Sites
List all sites belonging to your account, ordered by creation date (newest first).
Request
curl https://lookmomim.online/api/v1/publishes \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{
"publishes": [
{
"slug": "coral-sunset-abc",
"siteUrl": "https://coral-sunset-abc.lookmomim.online/",
"status": "live",
"createdAt": "2026-04-16T12:00:00.000Z",
"updatedAt": "2026-04-16T12:01:00.000Z"
}
]
}Get Site Details
Get full details for a single site, including the file manifest from the current version.
Request
curl https://lookmomim.online/api/v1/publish/coral-sunset-abc \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{
"slug": "coral-sunset-abc",
"siteUrl": "https://coral-sunset-abc.lookmomim.online/",
"status": "live",
"spaMode": false,
"viewer": {"title": "My Site", "description": "A simple static site"},
"currentVersionId": "m1abc2def3gh",
"files": [
{"path": "index.html", "size": 1024, "contentType": "text/html"},
{"path": "style.css", "size": 512, "contentType": "text/css"}
],
"createdAt": "2026-04-16T12:00:00.000Z",
"updatedAt": "2026-04-16T12:01:00.000Z"
}Delete a Site
Permanently delete a site and all its files. Cannot be undone.
Request
curl -X DELETE https://lookmomim.online/api/v1/publish/coral-sunset-abc \ -H "Authorization: Bearer YOUR_API_KEY"
Response
{"success": true}Limits
File Limits
| Limit | Value |
|---|---|
| Max file size | 50 MB per file |
| Max total upload size | 500 MB per publish |
| Max files per publish | 1,000 files |
| Presigned URL expiry | 1 hour |
Rate Limits
| Endpoint | Limit |
|---|---|
| General API | 60 requests / minute |
| Publish (POST /api/v1/publish) | 10 requests / minute |
Error Responses
All errors return a JSON object with an error field:
{"error": "Invalid or missing API key"} // 401
{"error": "Site not found"} // 404
{"error": "Forbidden"} // 403
{"error": "Version is already finalized"} // 409