Error Handling
Error response format and common error codes.
All Unmarkdown™ API errors return a consistent JSON envelope. This makes it straightforward to handle errors programmatically regardless of the endpoint.
Error Response Format
Every error response follows this structure:
{
"error": {
"code": "error_code",
"message": "Human-readable description of the problem",
"status": 400
}
}
| Field | Type | Description |
|---|---|---|
code | string | Machine-readable error code for programmatic handling |
message | string | Human-readable description. Safe to display to users. |
status | number | HTTP status code (matches the response status) |
Error Codes
| Status | Code | Description | Suggested Action |
|---|---|---|---|
| 400 | invalid_body | Malformed JSON in request body | Check your JSON syntax |
| 400 | validation_error | Invalid parameter value or missing required field | Check the field requirements for this endpoint |
| 400 | content_rejected | Content flagged by abuse scanner (demo publish only) | Review content for phishing or spam patterns |
| 401 | unauthorized | Missing, invalid, or revoked API key | Check your API key is correct and active |
| 403 | forbidden | Feature requires Pro tier | Upgrade to Pro or remove the Pro-only parameter |
| 403 | quota_exceeded | Free tier document limit (3) reached | Upgrade to Pro for unlimited documents |
| 404 | not_found | Resource does not exist or does not belong to you | Verify the resource ID |
| 409 | conflict | Slug already taken by another document | Choose a different slug |
| 410 | expired | Demo page has expired (past 72 hours) | Demo pages cannot be claimed after expiration |
| 429 | rate_limited | Too many requests per second | Wait and retry with backoff |
| 429 | quota_exceeded | Monthly API quota exhausted | Wait for monthly reset or upgrade to Pro |
| 500 | internal_error | Unexpected server error | Retry the request. If persistent, contact support. |
| 500 | render_error | Failed to render markdown to HTML | Check your markdown for syntax issues |
Handling Errors in Code
const res = await fetch('https://api.unmarkdown.com/v1/documents/publish', {
method: 'POST',
headers: {
'Authorization': 'Bearer um_your_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: '# Hello' })
});
if (!res.ok) {
const { error } = await res.json();
switch (error.code) {
case 'unauthorized':
console.error('Check your API key');
break;
case 'rate_limited':
console.error('Slow down, retrying...');
// implement backoff
break;
case 'quota_exceeded':
console.error(`Quota exceeded: ${error.message}`);
break;
case 'validation_error':
console.error(`Invalid request: ${error.message}`);
break;
default:
console.error(`API error: ${error.message}`);
}
}
import requests
res = requests.post(
'https://api.unmarkdown.com/v1/documents/publish',
headers={'Authorization': 'Bearer um_your_key'},
json={'content': '# Hello'}
)
if not res.ok:
error = res.json()['error']
if error['code'] == 'rate_limited':
print('Rate limited, retrying...')
elif error['code'] == 'quota_exceeded':
print(f"Quota exceeded: {error['message']}")
else:
print(f"Error {error['status']}: {error['message']}")
Best Practices
Always check the code field. Do not rely on HTTP status codes alone, since multiple error types can share the same status code (for example, both rate_limited and quota_exceeded return 429).
Display the message to users. Error messages are written to be human-readable and safe to show in a UI.
Retry on 429 and 500. Rate limit errors and server errors are transient. Implement retry logic with exponential backoff. Do not retry 400, 401, 403, or 404 errors, as those require a change to the request.
TIP
The status field inside the error envelope always matches the HTTP response status code. This is useful when your HTTP library does not expose the status code directly.