easl docs
One API call turns raw agent output into a beautiful, shareable URL.
easl is a smart rendering layer for AI agents. Upload a CSV, Markdown file, JSON blob, or any supported content — easl detects the type and renders it with the best interactive viewer. No accounts required.
| API Base | https://api.easl.dev |
| Sites served at | https://{slug}.easl.dev |
| Anonymous limit | 50 files, 200 MB, expires in 7 days |
| Inline limit | 256 KB content, single file |
Quick Start
The fastest way to publish: inline publish. One API call, content in the body, live URL in the response.
curl -X POST https://api.easl.dev/publish/inline \ -H "Content-Type: application/json" \ -d '{ "content": "# Hello World\nSome **markdown** here.", "contentType": "text/markdown", "title": "My First Page" }' # Response: { "url": "https://warm-dawn.easl.dev", "slug": "warm-dawn", "expiresAt": "2026-03-30T..." }
That's it. Your content is live and beautifully rendered.
Inline Publish (One-Call Magic)
The simplest publish method. Send content as a string, get a URL back instantly. No file uploads, no finalize step.
Supported content types
| contentType | Rendered as |
|---|---|
text/markdown | Styled prose with headings, code, tables, blockquotes |
text/csv | Sortable, filterable interactive table |
application/json | Collapsible tree viewer with syntax highlighting |
text/html | Served as-is |
image/svg+xml | Zoomable, sanitized SVG viewer |
text/x-mermaid | Rendered Mermaid diagram (flowchart, sequence, etc.) |
text/plain | Monospaced text viewer |
Examples
CSV → Interactive Table
curl -X POST https://api.easl.dev/publish/inline \ -H "Content-Type: application/json" \ -d '{ "content": "Name,Role,City\nAlice,Engineer,SF\nBob,Designer,NYC", "contentType": "text/csv", "title": "Team Directory" }'
JSON → Tree Viewer
curl -X POST https://api.easl.dev/publish/inline \ -H "Content-Type: application/json" \ -d '{ "content": "{\"users\": [{\"name\": \"Alice\", \"active\": true}]}", "contentType": "application/json", "title": "API Response" }'
Mermaid → Rendered Diagram
curl -X POST https://api.easl.dev/publish/inline \ -H "Content-Type: application/json" \ -d '{ "content": "graph TD\n A[Start] --> B{Decision}\n B -->|Yes| C[Do it]\n B -->|No| D[Skip]", "contentType": "text/x-mermaid", "title": "My Flowchart" }'
MCP Server
The MCP server lets AI agents publish content natively through the Model Context Protocol. Zero shell commands.
Installation
Add to your MCP configuration (Claude Desktop, Cursor, etc.):
{
"mcpServers": {
"easl": {
"command": "npx",
"args": ["-y", "@easl/mcp-server"]
}
}
}
Available tools
| Tool | Description |
|---|---|
publish_content | Publish raw content (string) → beautiful URL. The killer tool. |
publish_file | Publish a file from disk with presigned upload |
publish_site | Publish a multi-file site (directory) |
list_sites | List published sites in this session |
delete_site | Delete a published site |
Usage
Once configured, just ask your AI agent naturally:
// Your agent can now:
"Publish this CSV as a shareable table"
"Turn this markdown into a beautiful page"
"Show me this JSON in a tree view"
"Create a Mermaid diagram of the architecture"
REST API
Base URL: https://api.easl.dev
Publishing
One-call publish. Send content as a string, get a live URL back instantly. No upload step needed.
Auth: None required (anonymous, 7-day TTL)
Request body
| Field | Type | Description |
|---|---|---|
content | string required | Raw content string (max 256 KB) |
contentType | string required | MIME type (e.g. text/markdown) |
title | string optional | Page title shown in header & browser tab |
template | string optional | Template: minimal, report, or dashboard |
Response (201)
{
"url": "https://warm-dawn.easl.dev",
"slug": "warm-dawn",
"claimToken": "claim_...",
"embed": "<iframe src=\"...?embed=1\" ...></iframe>",
"shareText": "My Page: https://warm-dawn.easl.dev",
"expiresAt": "2026-03-30T12:00:00Z",
"anonymous": true
}
Multi-file publish. Returns presigned R2 upload URLs for each file. Call /finalize after uploads complete.
Auth: None required
Request body
| Field | Type | Description |
|---|---|---|
files | array required | Array of {path, size, contentType} |
slug | string optional | Custom slug (3-48 chars, lowercase alphanumeric + hyphens) |
title | string optional | Site title |
template | string optional | Template name |
ttl | number optional | TTL in seconds (default: 7 days) |
Response (201)
{
"slug": "bold-arch",
"url": "https://bold-arch.easl.dev",
"claimToken": "claim_...",
"upload": {
"versionId": "v_abc123",
"uploads": [
{
"path": "index.html",
"method": "PUT",
"url": "https://presigned-url...",
"headers": { "Content-Type": "text/html" }
}
],
"finalizeUrl": "https://api.easl.dev/finalize/bold-arch",
"expiresInSeconds": 600
},
"expiresAt": "2026-03-30T...",
"anonymous": true
}
Finalize
Activate a site after uploading all files via presigned URLs. Verifies all files exist in R2.
Auth: None required
Request body
| Field | Type | Description |
|---|---|---|
versionId | string required | The version ID from the publish response |
Site Management
Get site metadata including title, files, version, and expiry.
Auth: None required
Delete a site. Requires the claim token from the original publish response.
Auth: X-Claim-Token header
cURL Examples
Publish markdown
curl -X POST https://api.easl.dev/publish/inline \ -H "Content-Type: application/json" \ -d '{"content":"# Report\n\nQ1 was great.","contentType":"text/markdown"}'
Publish CSV
curl -X POST https://api.easl.dev/publish/inline \ -H "Content-Type: application/json" \ -d '{"content":"Name,Score\nAlice,95\nBob,87","contentType":"text/csv"}'
Multi-file publish
# Step 1: Create site curl -X POST https://api.easl.dev/publish \ -H "Content-Type: application/json" \ -d '{"files":[{"path":"index.html","size":1024,"contentType":"text/html"}]}' # Step 2: Upload to presigned URL curl -X PUT "PRESIGNED_URL" \ -H "Content-Type: text/html" \ --data-binary @index.html # Step 3: Finalize curl -X POST https://api.easl.dev/finalize/YOUR_SLUG \ -H "Content-Type: application/json" \ -d '{"versionId":"VERSION_ID"}'
Smart Rendering
easl's core feature. When a site is served, the Worker detects the file type and generates an HTML shell with the right interactive viewer. The raw data is embedded as JSON in a <script> tag, and client-side JavaScript hydrates it into a rich viewer.
Supported Types
| File Type | Detection | Viewer |
|---|---|---|
| CSV | .csv or text/csv | Sortable table with column click-to-sort, alternating rows, sticky header |
| Markdown | .md or text/markdown | Styled prose — headings, lists, code blocks, blockquotes, tables, images |
| JSON | .json or application/json | Collapsible/expandable tree with syntax coloring and expand-all/collapse-all |
| HTML | .html or text/html | Served as-is (no wrapping, no viewer) |
| Images | .png/.jpg/.gif/.webp | Responsive centered image with max-width |
| SVG | .svg or image/svg+xml | Sanitized (scripts stripped), zoomable viewer |
.pdf | Embedded iframe viewer | |
| Mermaid | .mmd or text/x-mermaid | Rendered diagram via Mermaid.js CDN |
Embed Mode
Add ?embed=1 to any site URL to get a clean, headerless version suitable for iframes:
<iframe src="https://warm-dawn.easl.dev?embed=1" width="100%" height="500" frameborder="0" ></iframe>
The embed URL is also returned in the embed field of the publish response.
Anonymous Sites
No account needed. Publish instantly and get a live URL.
| Limit | Value |
|---|---|
| Lifetime | 7 days |
| Max files per site | 50 |
| Max total size | 200 MB |
| Inline content limit | 256 KB |
Each publish returns a claimToken — save it if you need to delete the site later. Send it as the X-Claim-Token header on DELETE /sites/:slug.
Rate Limits
Publish endpoints are rate-limited per IP.
| Endpoint | Limit | Window |
|---|---|---|
/publish | 5 requests | 1 hour |
/publish/inline | 10 requests | 1 hour |
Error Codes
| Code | Meaning |
|---|---|
400 | Bad request — missing or invalid parameters |
404 | Not found — site or version doesn't exist |
409 | Conflict — slug taken or version mismatch |
422 | Unprocessable — files missing from R2 during finalize |
429 | Rate limited — try again later |
500 | Server error |