Markdown-to-PDF API on Sandbox and Main Endpoints
2026-04-21
A lot of agent and automation workflows generate Markdown first — reports, summaries, changelogs, tickets — but final delivery still needs a PDF. The Node4All md2pdf endpoint covers that step in a single request, on both sandbox.node4all.com (testnet) and api.node4all.com (mainnet), gated by x402 v2 payments.
What it does
POST a Markdown document, receive a PDF. The endpoint accepts either a JSON body with a markdown field or a multipart upload (file, .md, up to 10MB) and returns application/pdf directly — no async polling, no second request to fetch the result.
Endpoints
| Environment | URL |
|---|---|
| Sandbox (Base Sepolia) | POST https://sandbox.node4all.com/v1/md2pdf |
| Production (Base Mainnet) | POST https://api.node4all.com/v1/md2pdf |
Both URLs follow the same x402 v2 contract: an unauthorized request returns 402 Payment Required with a base64-encoded PAYMENT-REQUIRED header. Decode it, sign an EIP-3009 transferWithAuthorization, and resubmit with the PAYMENT-SIGNATURE header. The response includes the generated PDF and a PAYMENT-RESPONSE header carrying the settlement receipt.
Quick start with x402-fetch
The path of least resistance is the x402-fetch client — it negotiates the 402 challenge, signs the authorization, and retries the request for you.
import { wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const fetchWithPayment = wrapFetchWithPayment(fetch, account);
const res = await fetchWithPayment(
"https://sandbox.node4all.com/v1/md2pdf",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ markdown: "# Hello\n\nThis PDF was generated from Markdown." }),
},
);
const pdfBuffer = Buffer.from(await res.arrayBuffer());
// write pdfBuffer to disk, stream to S3, attach to an email, etc.
If you want to see the raw protocol — the 402 challenge, the headers, the encoded settlement — the same thing in curl looks like this:
# Step 1: probe the endpoint to see the price/asset/network the server expects.
curl -i -X POST https://sandbox.node4all.com/v1/md2pdf \
-H "Content-Type: application/json" \
-d '{"markdown":"# Hello"}'
# → HTTP/1.1 402 Payment Required
# → payment-required: <base64 JSON>
# Step 2: sign and resubmit (use x402-fetch or the agent toolkit; signing
# EIP-3009 by hand isn't fun).
For agents in Claude Desktop or any MCP-capable runtime, the @node4all/x402-agent-toolkit MCP server wraps the same flow as a tool call.
Multipart uploads
For files larger than what fits cleanly in a JSON body, use multipart:
curl -X POST https://sandbox.node4all.com/v1/md2pdf \
-H "PAYMENT-SIGNATURE: <base64 EIP-3009 authorization>" \
-F "file=@document.md" \
--output output.pdf
The 10MB cap is generous — typical agent-generated Markdown lands under 200KB.
Errors you might hit
400 Bad Request— neithermarkdownJSON field nor afileupload was provided.413 Payload Too Large— the document exceeds the 10MB limit.415 Unsupported Media Type— the multipart upload is not a.mdfile.500 Internal Server Error— surface this to us; it's almost always a Markdown edge case worth fixing.
Pricing
/v1/md2pdf is priced at $0.02 per request in USDC on Base. The sandbox version uses Base Sepolia testnet USDC, the production version uses real USDC.
What's next
The companion endpoint, /v1/pdf2md, is now live too — layout-aware PDF → Markdown extraction for ingesting long documents into a model context window. More endpoints (image extraction, structured data, archival) are queued behind it.