Free hosting for HTML, JSON, key-value, files, multi-file sites with short URLs and TTL retention
Full LLM thinking from the 4-phase benchmark pipeline.
```json
{
"service_type": "rest_api",
"base_url": "https://brewpage.app/api",
"auth_method": "api_key_header",
"auth_config": {"header": "X-Owner-Token", "prefix": null},
"endpoints": [
{
"path": "/html",
"method": "POST",
"purpose": "Publish an HTML page (or Markdown with format=markdown), returns a shareable HTTPS link",
"params": {
"ns": {"type": "string", "required": true},
"ttl": {"type": "integer", "required": false},
"tags": {"type": "string", "required": false},
"format": {"type": "string", "required": false},
"content": {"type": "string", "required": true},
"filename": {"type": "string", "required": false}
},
"response_format": "json",
"is_primary": true
},
{
"path": "/files",
"method": "POST",
"purpose": "Upload a file (max 5MB); images, PDFs, video and audio render inline",
"params": {
"ns": {"type": "string", "required": true},
"ttl": {"type": "integer", "required": false},
"file": {"type": "binary", "required": true}
},
"response_format": "json",
"is_primary": true
},
{
"path": "/sites",
"method": "POST",
"purpose": "Upload a multi-file HTML site via ZIP archive or individual files (max 20MB, 100 files)",
"params": {
"ns": {"type": "string", "required": true},
"ttl": {"type": "integer", "required": false},
"archive": {"type": "binary", "required": false},
"files": {"type": "array", "required": false},
"paths": {"type": "array", "required": false}
},
"response_format": "json",
"is_primary": true
},
{
"path": "/sites/{ns}/{id}",
"method": "GET",
"purpose": "Get site metadata and file list (requires owner token)",
"params": {
"ns": {"type": "string", "required": true},
"id": {"type": "string", "required": true},
"X-Owner-Token": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/sites/{ns}/{id}",
"method": "PUT",
"purpose": "Republish site in place, replacing the file bundle (requires owner token)",
"params": {
"ns": {"type": "string", "required": true},
"id": {"type": "string", "required": true},
"X-Owner-Token": {"type": "string", "required": true},
"archive": {"type": "binary", "required": false},
"paths": {"type": "array", "required": false},
"tags": {"type": "string", "required": false},
"ttl": {"type": "string", "required": false},
"entry": {"type": "string", "required": false}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/sites/{ns}/{id}",
"method": "DELETE",
"purpose": "Delete a site and all its files (requires owner token)",
"params": {
"ns": {"type": "string", "required": true},
"id": {"type": "string", "required": true},
"X-Owner-Token": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/kv",
"method": "POST",
"purpose": "Create a key-value store",
"params": {
"ns": {"type": "string", "required": true},
"ttl": {"type": "integer", "required": false},
"key": {"type": "string", "required": true},
"value": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/kv/{ns}/{id}/{key}",
"method": "PUT",
"purpose": "Set a key in a KV store (requires owner token)",
"params": {
"ns": {"type": "string", "required": true},
"id": {"type": "string", "required": true},
"key": {"type": "string", "required": true},
"value": {"type": "string", "required": true},
"X-Owner-Token": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/kv/{ns}/{id}/{key}",
"method": "GET",
"purpose": "Get a value from a KV store",
"params": {
"ns": {"type": "string", "required": true},
"id": {"type": "string", "required": true},
"key": {"type": "string", "required": true}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/json",
"method": "POST",
"purpose": "Store a JSON document",
"params": {
"ns": {"type": "string", "required": true},
"ttl": {"type": "integer", "required": false},
"document": {"type": "object", "required": true}
},
"response_format": "json",
"is_primary": false
},
{
"path": "/json/{ns}/{id}",
"method": "GET",
"purpose": "Retrieve a stored JSON document",
"params": {
"ns": {"type": "string", "required": true},
```json
{
"tests": [
{
"name": "mint_owner_token",
"endpoint": "/owner-token",
"method": "GET",
"headers": {
"User-Agent": "ProwlBench/1.0"
},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Mints a fresh stateless owner token, returns {token, ownerId}",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "token", "type": "string", "min_length": 16}
},
{
"name": "publish_html_page",
"endpoint": "/html",
"method": "POST",
"headers": {
"User-Agent": "ProwlBench/1.0",
"Content-Type": "application/json"
},
"payload": {
"content": "<!doctype html><html><head><title>Prowl Bench</title></head><body><h1>Hello</h1></body></html>"
},
"expected_status": 201,
"intent": "happy_path",
"expected_behavior": "Stores HTML content and returns shareable link plus ownerToken",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "link", "type": "string", "min_length": 8}
},
{
"name": "publish_markdown_page",
"endpoint": "/html",
"method": "POST",
"headers": {
"User-Agent": "ProwlBench/1.0",
"Content-Type": "application/json"
},
"payload": {
"content": "# Prowl Bench\n\nMarkdown **rendering** test."
},
"expected_status": 201,
"intent": "happy_path",
"expected_behavior": "Renders markdown to styled HTML and returns a shareable link",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "link", "type": "string", "min_length": 8}
},
{
"name": "write_json_document",
"endpoint": "/json",
"method": "POST",
"headers": {
"User-Agent": "ProwlBench/1.0",
"Content-Type": "application/json"
},
"payload": {"agent": "prowl", "run": 1, "ok": true},
"expected_status": 201,
"intent": "happy_path",
"expected_behavior": "Stores the JSON document and returns a shareable link",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "link", "type": "string", "min_length": 8}
},
{
"name": "create_kv_store",
"endpoint": "/kv",
"method": "POST",
"headers": {
"User-Agent": "ProwlBench/1.0",
"Content-Type": "application/json"
},
"payload": {"key": "prowl-key", "value": "prowl-value"},
"expected_status": 201,
"intent": "happy_path",
"expected_behavior": "Creates a KV store with an initial key/value and returns a shareable link",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "link", "type": "string", "min_length": 8}
},
{
"name": "read_json_document",
"endpoint": "/json/public/{id}",
"method": "GET",
"headers": {
"User-Agent": "ProwlBench/1.0"
},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns the stored raw JSON content for a published document",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "content", "type": "string"}
},
{
"name": "read_public_gallery",
"endpoint": "/gallery",
"method": "GET",
"headers": {
"User-Agent": "ProwlBench/1.0"
},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns paginated list of public gallery items",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "items", "type": "array"}
},
{
"name": "platform_stats",
"endpoint": "/stats",
"method": "GET",
"headers": {
"User-Agent": "ProwlBench/1.0"
},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns platform-wide creation/view counts with per-type breakdown",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "totalCreated", "type": "number"}
},
{
"name": "random_namespace",
"endpoint": "/namespace/random",
"method": "GET",
"headers": {
"User-Agent": "ProwlBench/1.0"
},
"expected_status": 200,
"intent": "happy_path",
"expected_behavior": "Returns a fresh non-colliding namespace suggestion",
"metrics": ["latency", "status_code", "accuracy"],
"validation": {"field": "namespace", "type": "string", "min_length": 1}
},
{
"name": "html_missing_content_rejected",
"endpoint": "/html",
"method": "POST",
"headers": {
"User-Agent": "ProwlBench/1.0",
"Content-Type": "application/json"
},
"payload": {},
"expected_status": 400,
"intent": "validation",
"expected_behavior": "Rejects request missing the required 'content' field with a 4xx error",
"metrics": ["latency", "sta8/12 tests passed
| Test | Endpoint | Status | Latency |
|---|---|---|---|
| mint_owner_token | GET /owner-token | 200 | 351ms |
| publish_html_page | POST /html | 201 | 218ms |
| publish_markdown_page | POST /html | 201 | 223ms |
| write_json_document | POST /json | 201 | 259ms |
| create_kv_store | POST /kv | 201 | 232ms |
| read_json_document | GET /json/public/{id} | 404 | 121ms |
| read_public_gallery | GET /gallery | 200 | 136ms |
| platform_stats | GET /stats | 200 | 222ms |
| random_namespace | GET /namespace/random | 200 | 150ms |
| html_missing_content_rejected | POST /html | 400 | 120ms |
{"model": "deepseek", "data": {"overall": 74, "dimensions": {"token_efficiency": 7.0, "first_try_success": 8.0, "response_parseability": 9.0, "error_clarity": 6.0, "doc_quality": 6.0, "auth_simplicity": 9.0, "latency": 9.0, "consistency": 8.0}, "pricing_normalized": {"cost_per_1k_requests": 0, "cost_per_1m_input_tokens": null, "cost_per_1m_output_tokens": null, "free_tier_requests": null, "estimated_monthly_cost_light": 0, "estimated_monthly_cost_heavy": 0}, "issues": [{"severity": "high", "detail": "GET /json/public/{id} returned 404 immediately after a successful write of that JSON document \u2014 read-after-write inconsistency. An agent that stores a doc and immediately fetches it cannot reliably retrieve it.", "endpoint": "/json/public/{id}"}, {"severity": "medium", "detail": "PUT /html/public/{id} with a wrong owner token returned 404 'HTML page not found' instead of 403. This masks the real cause (auth failure) and misleads agents into thinking the resource doesn't exist.", "endpoint": "/html/public/{id}"}, {"severity": "medium", "detail": "Validation errors are generic ('Malformed request body') with no field-level detail. Agents cannot tell which field was missing or malformed without guessing.", "endpoint": "/html"}, {"severity": "low", "detail": "Successful write responses embed a large 'visibilityNotice' string on every create, inflating token usage.", "endpoint": "/html"}], "recommendations": ["Fix read-after-write consistency: a document created via POST /json must be immediately retrievable via GET.", "Return 403 (not 404) when a valid-resource request carries an invalid owner token; distinguish 'not found' from 'forbidden'.", "Add field-level validation error details (e.g. {'errors': [{'field': 'content', 'message': 'required'}]}) for 400 responses.", "Move the verbose visibilityNotice out of default response bodies or shorten it to keep responses token-lean.", "Publish a complete OpenAPI spec with request/response schemas and examples to reduce agent guesswork."]}}Show your live agent-readiness score on your own site. Free, no auth — it updates as your score changes.
<a href="https://prowl.world/service/brewpage">
<img src="https://prowl.world/badge/brewpage.svg" height="56" alt="Agent-readiness on Prowl">
</a>
See operational metrics, LLM evaluations, agent readiness, and more.
Open in Dashboard