Public API is available. Convert Markdown to images with 50 watermarked requests/month.
Back to Blog
Sunday, August 2, 2026

Markdown to Image API: Generate PNGs with cURL, Node.js, Python, and n8n

Markdown to Image API: Generate PNGs with cURL, Node.js, Python, and n8n

Markdown to Image API: Generate PNGs with cURL, Node.js, Python, and n8n

Manual export is fine for one image. It becomes a bottleneck when your product needs to turn every AI report, changelog, support answer, or social post into a consistent visual. A Markdown-to-image API moves that render step into code: send Markdown, choose a format and theme, receive a URL or binary file, and store the result where your application needs it.

This guide builds a real integration with the MarkdownToImage API. You will start with cURL, then implement the same workflow in Node.js and Python, configure n8n, and add the production safeguards that quick-start snippets often omit.

The endpoint and limits in this article were checked against the official API documentation on August 2, 2026. Quotas and plans can change, so verify the current pricing page before estimating production cost.

1. When should you use a Markdown-to-image API?

Use an API when image generation is part of a repeatable workflow rather than an occasional design task. Common examples include:

  • turning an LLM response into a downloadable report image;
  • generating release-note cards after a deployment;
  • creating Open Graph or social cards from CMS fields;
  • rendering code, tables, Mermaid diagrams, or KaTeX formulas consistently;
  • producing visual artifacts inside n8n, Dify, Make, CI, or an internal tool.

A browser converter is still faster for a one-off export. The API becomes valuable when the input already exists in another system, the same styling must be applied many times, or the output must continue automatically to storage, publishing, or messaging.

2. Before you start: token and environment

Sign in to MarkdownToImage and create an API token from the API Tokens area. Treat it like a password: do not put it in source code, Markdown files, screenshots, client-side JavaScript, or workflow exports.

For local testing, expose it as an environment variable:

export MARKDOWN_TO_IMAGE_API_TOKEN="mti_your_token_here"

In production, use your hosting platform’s encrypted secret store. If a token appears in a public repository or log, revoke it and create a new one rather than trying to hide the old commit.

The API currently offers a monthly free quota with watermarked output. Watermark-free and higher-volume usage depends on credits or the current plan. Check the official API and pricing pages at implementation time instead of hard-coding a quota assumption into your product.

3. Make the first request with cURL

The generation endpoint accepts JSON and uses Bearer authentication. This request creates an 1200-pixel-wide PNG with a dark GitHub-style theme:

curl -X POST https://markdowntoimage.com/api/v1/images/generate \
  -H "Authorization: Bearer $MARKDOWN_TO_IMAGE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "markdown": "# Weekly release\n\n- Faster exports\n- Clearer reports\n- One automated workflow",
    "format": "png",
    "width": 1200,
    "quality": 2,
    "theme": "github-dark",
    "mode": "url"
  }'

A successful URL-mode response contains data.imageUrl. The URL is temporary, so opening it in a browser proves the render worked but does not create permanent storage. Download the file promptly and upload it to your own object storage, CMS, or media library.

4. Choose the right parameters and format

The request can be simple—only markdown is required—but explicit settings make automated output predictable.

ParameterWhat it controlsPractical choice
markdownSource contentValidate length and required sections before sending
formatpng, jpeg, webp, or pdfPNG for crisp UI and code; WebP for smaller web assets; PDF for documents
widthRender width from 200 to 2560 pixels1200 for social and report cards; test your real layout
qualityDevice scale factor from 1 to 3Start at 2; higher values increase output size and render work
themeOverall visual themePin a named theme so releases do not change appearance unexpectedly
codeStyleSyntax-highlighting paletteChoose for contrast with the page theme
fontFamilyFont family presetTest all languages your product will render
modeurl or binary responseURL for easy orchestration; binary for direct file pipelines

Use JPEG for photographic content where lossy compression is acceptable. Use PNG for code, diagrams, and sharp interface elements. Use WebP when bandwidth matters and every consumer supports it. Although PDF uses the same generation endpoint, it is a document output rather than a normal social image.

5. Node.js: generate and save the image

The following Node.js script calls the API, checks the HTTP response, downloads the temporary result, and writes a real file. It uses the global fetch API available in current Node.js releases.

import { writeFile } from "node:fs/promises";

const token = process.env.MARKDOWN_TO_IMAGE_API_TOKEN;
if (!token) throw new Error("MARKDOWN_TO_IMAGE_API_TOKEN is required");

const response = await fetch("https://markdowntoimage.com/api/v1/images/generate", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    markdown: "# Build report\n\n- Tests: **passed**\n- Deploy: **ready**",
    format: "png",
    width: 1200,
    quality: 2,
    theme: "github-dark",
    mode: "url",
  }),
  signal: AbortSignal.timeout(30_000),
});

if (!response.ok) {
  throw new Error(`Generation failed: ${response.status} ${await response.text()}`);
}

const result = await response.json();
const imageResponse = await fetch(result.data.imageUrl, {
  signal: AbortSignal.timeout(30_000),
});
if (!imageResponse.ok) {
  throw new Error(`Download failed: ${imageResponse.status}`);
}

await writeFile("build-report.png", Buffer.from(await imageResponse.arrayBuffer()));
console.log("Saved build-report.png");

For a web service, return only after your permanent upload finishes. Recording the API response URL without copying the file creates a delayed failure when that temporary URL expires.

6. Python: generate and save the image

Python follows the same two-request pattern in URL mode: create the render, then download it. The explicit timeouts prevent a worker from hanging indefinitely.

import os
from pathlib import Path

import requests

token = os.environ["MARKDOWN_TO_IMAGE_API_TOKEN"]
payload = {
    "markdown": "# Build report\n\n- Tests: **passed**\n- Deploy: **ready**",
    "format": "png",
    "width": 1200,
    "quality": 2,
    "theme": "github-dark",
    "mode": "url",
}

response = requests.post(
    "https://markdowntoimage.com/api/v1/images/generate",
    headers={"Authorization": f"Bearer {token}"},
    json=payload,
    timeout=30,
)
response.raise_for_status()

image_url = response.json()["data"]["imageUrl"]
image_response = requests.get(image_url, timeout=30)
image_response.raise_for_status()
Path("build-report.png").write_bytes(image_response.content)
print("Saved build-report.png")

Wrap this function with your job queue rather than running a long render inside a user-facing request when volume grows. A queue gives you controlled concurrency, retries, and a place to record the final storage URL.

7. Build the same workflow in n8n

In n8n, place an HTTP Request node after the node that creates or fetches your Markdown. Store the token in n8n Credentials rather than pasting it directly into the workflow JSON.

Method: POST
URL: https://markdowntoimage.com/api/v1/images/generate
Authentication: Header Auth
Header name: Authorization
Header value: Bearer {{$credentials.markdownToImageToken}}
Send Body: JSON
Body:
{
  "markdown": "{{$json.content}}",
  "format": "png",
  "width": 1200,
  "quality": 2,
  "theme": "github-dark",
  "mode": "url"
}

Connect a second HTTP Request node to download {{$json.data.imageUrl}}, enable file output, and then send that binary file to S3, Google Drive, Directus, WordPress, Slack, or your next destination. Configure the error branch explicitly so authentication or quota failures do not silently publish an empty record.

8. URL mode or binary mode?

Choose URL mode when your automation platform handles JSON easily and can perform a second download. It is convenient for queues, webhooks, and no-code workflows, but the returned URL is retained temporarily—currently 24 hours according to the official documentation.

Choose binary mode when you want one response that can be streamed directly into storage. It removes the second HTTP request, but your client must handle binary content, content type, file extension, memory limits, and partial-upload cleanup correctly.

Whichever mode you use, save the final asset in storage you control. Also store useful metadata beside it: requested format, width, theme, source content ID, generation timestamp, and a hash of the Markdown. That makes duplicate detection and incident diagnosis much easier.

9. Handle API errors without duplicate renders

The API documents these important outcomes:

HTTP statusMeaningRecommended action
400Missing Markdown or invalid parametersDo not retry unchanged input; validate the payload
401Missing, invalid, or revoked tokenStop and alert; rotate or correct the secret
429Free quota or credits are unavailableDelay the job, notify the owner, or upgrade capacity
500Generation or internal failureRetry with backoff a limited number of times

Automatic retries should target transient failures, not every non-200 response. Use exponential backoff with jitter for 500 responses and network timeouts. Before retrying after an uncertain connection failure, check whether your application already stored an output for the same content hash. This prevents one logical job from creating several paid renders.

Log the status code, provider error code, job ID, attempt number, and latency—but never log the full Authorization header.

10. Production checklist

Before sending real traffic, verify these points:

  • keep the API token in an encrypted server-side secret store;
  • set connection and total request timeouts;
  • cap retries and add exponential backoff with jitter;
  • limit worker concurrency to match your quota and downstream storage;
  • validate Markdown size and required fields before calling the API;
  • pin format, width, theme, code style, and font settings;
  • download URL-mode results immediately to permanent storage;
  • derive safe, deterministic filenames rather than trusting user input;
  • add alt text and meaningful surrounding copy when publishing generated images;
  • record usage and alert before quota exhaustion;
  • test multilingual fonts, long code lines, tables, Mermaid, and KaTeX with your real content;
  • keep a manual fallback for business-critical publishing workflows.

Start with a small representative test set. Ten realistic Markdown samples reveal more layout problems than hundreds of “Hello World” calls.

11. Frequently asked questions

Can the API convert Markdown directly to PNG?

Yes. Send format: "png" to the generation endpoint. You can also request JPEG, WebP, or PDF. PNG is usually the safest choice for code, text, diagrams, and interface screenshots.

Can I use the Markdown-to-image API from a browser?

Do not expose a secret API token in client-side code. Call the API from your server, serverless function, or protected automation workflow, then return the stored result to the browser.

How do I generate images from AI or LLM output?

Pass the model’s Markdown output into the markdown field after applying your own length, content, and safety checks. A stable prompt template plus pinned render settings produces more consistent cards than allowing every response to choose its own layout.

Is n8n enough, or do I need Node.js or Python?

n8n is enough for straightforward generation, download, and upload workflows. Use application code when you need high concurrency, custom idempotency, detailed observability, or tight integration with product permissions and billing.

12. Next step: test one real payload

Take one piece of Markdown your product already produces and run the cURL example against it. Inspect code wrapping, tables, fonts, and image dimensions before expanding the workflow.

When the first render looks right, open the MarkdownToImage API guide, create a server-side token, and move the Node.js, Python, or n8n recipe into a small production test. The safest rollout is one real content type, one fixed visual preset, permanent storage, and observable error handling—then scale from evidence.

Markdown to Image API: cURL, Node.js, Python & n8n | MarkdownToImage