Reference
Markdown API errors
Every failure from the Markdown Viewer API returns the same predictable JSON envelope with a stable error.code, an appropriate HTTP status, and an optional details field for structured information. Build resilient integrations by switching on the code, not the message.
Error response shape
All errors — whether validation, authentication, rate limiting, or server-side — serialise identically:
{
"error": {
"code": "bad_request",
"message": "Invalid request body.",
"details": {
"fieldErrors": {
"markdown": [
"Required"
]
}
}
}
}code— stable identifier; switch on this.message— human-readable; don't pattern-match against it.details— optional structured payload (eg. field-level validation errors).
Defensive error handling
A robust client checks the HTTP status, parses the JSON envelope, and decides whether to retry, surface a UI error, or escalate:
async function call(path: string, body: unknown, apiKey: string) {
const res = await fetch(`https://trymarkdownviewer.com${path}`, {
method: "POST",
headers: {
"Authorization": `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
const payload = await res.json();
if (!res.ok) {
const code = payload?.error?.code ?? "unknown_error";
// Switch on the stable code, not res.status alone.
switch (code) {
case "rate_limited":
case "quota_exceeded":
// Honour Retry-After or upgrade plan.
throw new Error(`Rate limited: ${code}`);
case "unauthorized":
// Force a key refresh / logout.
throw new Error("Auth failed");
default:
throw new Error(`${code}: ${payload?.error?.message}`);
}
}
return payload.data;
}Error code reference
Every error you can see, in one table. The codes are sorted client → rate → server.
bad_requestInvalid request body
The request body is invalid, missing a required field, or not valid JSON.
How to fix
- Set `Content-Type: application/json` on every request.
- Make sure your payload is valid JSON (no trailing commas, properly quoted strings).
- Check the `details.fieldErrors` object for the exact field that failed validation.
unauthorizedMissing or invalid API key
Your API key is missing, malformed, revoked, or doesn't exist.
How to fix
- Add `Authorization: Bearer <YOUR_API_KEY>` to the request headers.
- Confirm the key isn't revoked — check the API Keys page in your dashboard.
- Make sure you copied the entire key (they're 36+ characters after the prefix).
forbiddenNot allowed on this plan
The action isn't permitted for your current plan or account.
How to fix
- Check whether the endpoint requires a paid plan.
- Upgrade your plan from the billing page if you've hit a plan-only limit.
not_foundResource not found
The endpoint or resource you requested doesn't exist.
How to fix
- Double-check the path — every API route is under `/api/v1/*`.
- Make sure you're not hitting a typo'd path like `/api/v1/renderer`.
method_not_allowedWrong HTTP method
The endpoint exists but doesn't accept the HTTP method you used.
How to fix
- All processing endpoints use `POST`. Send a `POST` request, not `GET`.
- Check the docs page for the endpoint to confirm the expected verb.
payload_too_largeMarkdown body is too big
Your request body exceeds the 256 KiB per-request limit.
How to fix
- Split very long documents into smaller chunks and render them separately.
- Trim oversized inline base64 images out of the markdown before sending.
unsupported_media_typeWrong content type
`Content-Type` must be `application/json`.
How to fix
- Set `Content-Type: application/json` on every API request.
- Don't send `multipart/form-data` — wrap the markdown in JSON instead.
rate_limitedBurst rate limit hit
You sent more than 20 requests in 10 seconds with this key.
How to fix
- Slow down and add a small delay between rapid loops.
- Honour the `Retry-After` response header before retrying.
- Batch requests where possible, or use exponential backoff with jitter.
quota_exceededPlan quota exhausted
Your plan's daily (or monthly) request quota has been used up.
How to fix
- Wait for the quota window to reset — see `X-RateLimit-Reset`.
- Upgrade your plan from the billing page for a higher quota.
timeoutProcessing timed out
The request took longer than the per-request CPU budget (1 second).
How to fix
- Try a smaller markdown document.
- Avoid pathological inputs (eg. thousands of nested lists).
- If you hit this consistently, please open a GitHub issue with a repro.
internal_errorSomething broke on our side
An unexpected error occurred while processing the request.
How to fix
- Retry the request after a short delay.
- If it keeps happening, please report the issue with the timestamp.
network_errorNetwork error
The browser couldn't reach the API at all — DNS, CORS, or offline.
How to fix
- Check that you're online and not blocked by an ad/script blocker.
- If you're calling from a different origin, ensure CORS isn't being blocked.
- Inspect the browser DevTools network tab for the underlying cause.
parse_errorResponse wasn't valid JSON
The server returned a response that couldn't be parsed as JSON.
How to fix
- This usually indicates a network-level failure (eg. proxy, captive portal).
- Retry the request — if it keeps happening, please report it.
FAQ
- It's a stable, machine-readable identifier for the failure (eg. unauthorized, rate_limited, payload_too_large). Build your conditionals against the code — the human-readable error.message can change between versions without warning.
- Both return HTTP 429, but error.code differs. rate_limited means you tripped the per-key 20 req / 10s burst limit. quota_exceeded means your plan's daily or monthly quota has been used up — wait for X-RateLimit-Reset or upgrade.
- Retry idempotent 5xx errors (internal_error, timeout) with exponential backoff. Always honour the Retry-After header on 429 responses. Don't retry 4xx errors — they're client-side and won't fix themselves.
- Failed requests count toward burst limits but do not consume your plan quota — bad_request, unauthorized, and validation errors won't drain your daily allowance.
- When the error code is bad_request, look at the details.fieldErrors object. It's a map of field name → array of validation messages so you can show the user a precise inline error.
What does the error.code field mean?
How do I tell a burst rate limit from a quota exhaustion?
When should I retry a failed request?
Are error responses still rate-limited?
How do I get more context on a validation failure?
Next steps
- Test failures live in the API playground — error responses there link straight back here.
- Tune your retry logic with the rate-limit guide.
- Authentication failing? Re-check the authentication docs.