Markdown to HTML API#

The Markdown to HTML API converts a Markdown file to a fully styled HTML document with a single request to POST /v1/convert/markdown-to-html. Upload a .md or .markdown file via multipart form data and receive a complete, self-contained HTML page with embedded CSS, a responsive layout, and a built-in dark mode toggle. The result is ready to open in any browser. The HTML is returned directly by default, or set direct_download=false for JSON metadata with a presigned download URL.


Endpoint#

POST /v1/convert/markdown-to-html

Content-Type: multipart/form-data

Accepted input: .md or .markdown files (UTF-8 encoded)

Output format: .html (text/html)


Authentication#

Requires either a private API key or a JWT token from a public key.

X-API-Key: sk_your_private_key

Or:

Authorization: Bearer <jwt_token>

Request Parameters#

Parameter Type Required Default Description
file file Yes -- The .md or .markdown file to convert. Must be UTF-8 encoded.
output_filename string No Input filename Custom output filename. The .html extension is added automatically.
direct_download boolean No true When true, returns the HTML document directly. When false, returns JSON metadata with a presigned download URL.

Conversion Rules#

The converter uses Python-Markdown with the following extensions enabled:

Extension What It Does
tables Pipe-delimited Markdown tables rendered as HTML <table> elements
fenced_code Triple-backtick code blocks with language identifiers (```python)
codehilite Syntax highlighting CSS classes on code blocks (via Pygments)
toc Table of contents generation via a [TOC] marker in your document
attr_list Attach HTML attributes to elements using {.class #id} syntax

Example#

Input:

# My Document

[TOC]

## Introduction

This is a **bold** and *italic* example.

## Data Table

| Name  | Age | City   |
|-------|-----|--------|
| Alice | 30  | London |
| Bob   | 25  | Paris  |

## Code Sample

```python
def hello():
    print("Hello, world!")
```

Output: A complete <!DOCTYPE html> document with:

  • The rendered Markdown inside a <body> with max-width 800px, centered layout
  • Styled tables, code blocks, links, and headings
  • A clickable table of contents generated from the headings
  • A dark mode toggle button (top-right corner) that persists the user's preference to localStorage

Output Styling#

The generated HTML includes an embedded <style> block with:

  • Light and dark themes via CSS custom properties, toggled by a data-theme attribute
  • System font stack (-apple-system, BlinkMacSystemFont, Segoe UI, Arial, sans-serif)
  • Responsive layout with 800px max-width and centered content
  • Line height of 1.6 for readability
  • Styled elements: code blocks (with background), tables (with borders and striped rows), links, and block quotes
Note on syntax highlighting: The codehilite extension adds Pygments CSS class names to code blocks, but no Pygments stylesheet is bundled in the output. Code blocks will have correct structure and basic styling, but language-specific color highlighting requires adding a Pygments CSS theme to the page. The built-in styling provides background and font styling for all code blocks regardless.

Response#

Direct Download (direct_download=true, default)#

HTTP 200 OK
Content-Type: text/html
Content-Disposition: inline; filename="readme_20260405_123456789.html"

Returns the full HTML document. Since the Content-Disposition is inline, browsers will render the page directly.

Metadata Response (direct_download=false)#

{
    "presigned_url": "https://spaces.example.com/...",
    "object_key": "env/files/{project_id}/markdown-to-html/readme_20260405_123456789.html",
    "filename": "readme_20260405_123456789.html",
    "file_size": 5678,
    "conversion_time_seconds": 0.04
}

Code Examples#

Python#

import requests

with open("README.md", "rb") as f:
    response = requests.post(
        "https://api.enconvert.com/v1/convert/markdown-to-html",
        headers={"X-API-Key": "sk_your_private_key"},
        files={"file": ("README.md", f, "text/markdown")}
    )

with open("README.html", "wb") as out:
    out.write(response.content)

Node.js#

const form = new FormData();
form.append("file", fs.createReadStream("README.md"));

const response = await fetch("https://api.enconvert.com/v1/convert/markdown-to-html", {
    method: "POST",
    headers: { "X-API-Key": "sk_your_private_key" },
    body: form
});

const html = await response.text();
fs.writeFileSync("README.html", html);

PHP#

$ch = curl_init("https://api.enconvert.com/v1/convert/markdown-to-html");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["X-API-Key: sk_your_private_key"],
    CURLOPT_POSTFIELDS => ["file" => new CURLFile("README.md", "text/markdown")]
]);
$html = curl_exec($ch);
curl_close($ch);
file_put_contents("README.html", $html);

Go#

body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, _ := writer.CreateFormFile("file", "README.md")
file, _ := os.Open("README.md")
io.Copy(part, file)
writer.Close()

req, _ := http.NewRequest("POST", "https://api.enconvert.com/v1/convert/markdown-to-html", body)
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("X-API-Key", "sk_your_private_key")
resp, _ := http.DefaultClient.Do(req)

JavaScript -- Browser (Public Key)#

const tokenRes = await fetch("https://api.enconvert.com/v1/auth/token", {
    method: "POST",
    headers: { "X-API-Key": "pk_your_public_key" }
});
const { token } = await tokenRes.json();

const form = new FormData();
form.append("file", fileInput.files[0]);

const response = await fetch("https://api.enconvert.com/v1/convert/markdown-to-html", {
    method: "POST",
    headers: { "Authorization": `Bearer ${token}` },
    body: form
});

const data = await response.json();
window.open(data.presigned_url, "_blank");

Error Responses#

Status Condition
400 Bad Request File is not a .md or .markdown file
400 Bad Request Invalid Markdown encoding (expected UTF-8)
400 Bad Request Markdown to HTML conversion failed
401 Unauthorized Missing or invalid API key / JWT token
402 Payment Required Monthly ops allowance exhausted
402 Payment Required Storage limit reached
413 Payload Too Large File exceeds plan's maximum file size

Limits#

Limit Value
Max file size Plan-dependent (Founding: 5 MB)
Input encoding UTF-8 only
Accepted extensions .md, .markdown
Monthly conversions Plan-dependent

Frequently asked questions#

How do I render Markdown to HTML with a REST API?#

Send a multipart/form-data POST request to POST /v1/convert/markdown-to-html with your .md or .markdown file in the file field, authenticating with an X-API-Key header or a JWT Authorization: Bearer token. The response is a complete HTML document by default.

Does the Markdown to HTML API support tables, code blocks, and a table of contents?#

Yes. The converter uses Python-Markdown with the tables, fenced_code, codehilite, toc, and attr_list extensions enabled. Add a [TOC] marker in your document to generate a clickable table of contents from the headings.

Why don't my code blocks have language-specific syntax highlighting colors?#

The codehilite extension adds Pygments CSS class names to code blocks, but no Pygments stylesheet is bundled in the output. Add a Pygments CSS theme to the page for color highlighting; the built-in styling still provides background and font styling for all code blocks.

Can I convert Markdown to HTML directly from the browser?#

Yes. Exchange a public key (pk_...) for a JWT via POST /v1/auth/token, then call the endpoint with an Authorization: Bearer header and open the returned presigned_url.

Does the generated HTML include dark mode?#

Yes. The output includes light and dark themes via CSS custom properties, toggled by a data-theme attribute, with a dark mode toggle button that persists the user's preference to localStorage.