Python
Convert PDF, DOCX, images, and more to Markdown using Python. Code examples with requests and httpx for LLM and RAG pipelines.
No SDK needed — use requests or httpx to call the Markdown Anything REST API.
Installation
pip install requests
# or for async support:
pip install httpxSync Conversion
import requests
def convert_file(file_path: str, token: str) -> dict:
with open(file_path, 'rb') as f:
response = requests.post(
'https://markdownanything.com/api/v1/convert',
headers={'Authorization': f'Bearer {token}'},
files={'file': f},
data={
'include_metadata': 'true',
},
)
response.raise_for_status()
data = response.json()
print(data['markdown'])
print(f"Credits remaining: {data['credits_remaining']}")
return dataimport httpx
def convert_file(file_path: str, token: str) -> dict:
with open(file_path, 'rb') as f:
response = httpx.post(
'https://markdownanything.com/api/v1/convert',
headers={'Authorization': f'Bearer {token}'},
files={'file': f},
data={
'include_metadata': 'true',
},
)
response.raise_for_status()
data = response.json()
print(data['markdown'])
print(f"Credits remaining: {data['credits_remaining']}")
return dataAsync Conversion with Polling
Submit large files asynchronously and poll for the result:
import time
import requests
def convert_async(file_path: str, token: str, webhook_url: str = None) -> dict:
headers = {'Authorization': f'Bearer {token}'}
with open(file_path, 'rb') as f:
data = {'webhook_url': webhook_url} if webhook_url else {}
response = requests.post(
'https://markdownanything.com/api/v1/convert',
headers=headers,
files={'file': f},
data=data,
)
response.raise_for_status()
result = response.json()
status_url = result['status_url']
print(f"Conversion {result['id']} queued")
# Poll for result
return poll_conversion(status_url, headers)
def poll_conversion(status_url: str, headers: dict, max_attempts: int = 30) -> dict:
for _ in range(max_attempts):
response = requests.get(status_url, headers=headers)
data = response.json()
if data['status'] == 'completed':
return data
if data['status'] == 'failed':
raise Exception(f"Conversion failed: {data.get('error')}")
time.sleep(2)
raise TimeoutError('Polling timed out')import asyncio
import httpx
async def convert_async(file_path: str, token: str) -> dict:
headers = {'Authorization': f'Bearer {token}'}
async with httpx.AsyncClient() as client:
with open(file_path, 'rb') as f:
response = await client.post(
'https://markdownanything.com/api/v1/convert',
headers=headers,
files={'file': f},
data={'webhook_url': 'https://your-server.com/webhook'},
)
response.raise_for_status()
result = response.json()
status_url = result['status_url']
# Poll for result
return await poll_conversion(client, status_url, headers)
async def poll_conversion(
client: httpx.AsyncClient,
status_url: str,
headers: dict,
max_attempts: int = 30,
) -> dict:
for _ in range(max_attempts):
response = await client.get(status_url, headers=headers)
data = response.json()
if data['status'] == 'completed':
return data
if data['status'] == 'failed':
raise Exception(f"Conversion failed: {data.get('error')}")
await asyncio.sleep(2)
raise TimeoutError('Polling timed out')Enhanced AI
import requests
def convert_with_enhanced_ai(file_path: str, token: str) -> dict:
with open(file_path, 'rb') as f:
response = requests.post(
'https://markdownanything.com/api/v1/convert',
headers={'Authorization': f'Bearer {token}'},
files={'file': f},
data={'use_enhanced_ai': 'true'},
)
response.raise_for_status()
return response.json()Enhanced AI costs 2-3 credits depending on your plan. See credit costs.
Error Handling
import requests
def safe_convert(file_path: str, token: str) -> dict | None:
with open(file_path, 'rb') as f:
response = requests.post(
'https://markdownanything.com/api/v1/convert',
headers={'Authorization': f'Bearer {token}'},
files={'file': f},
)
if response.status_code == 402:
data = response.json()
print(f"Insufficient credits: need {data['credits_required']}, "
f"have {data['credits_available']}")
return None
if response.status_code == 429:
retry_after = response.headers.get('Retry-After', '60')
print(f"Rate limited. Retry after {retry_after}s")
return None
response.raise_for_status()
return response.json()Batch Conversion
Convert multiple files with rate-limit awareness:
import time
from pathlib import Path
import requests
def batch_convert(
file_paths: list[str],
token: str,
delay: float = 1.0,
) -> list[dict]:
results = []
headers = {'Authorization': f'Bearer {token}'}
for path in file_paths:
with open(path, 'rb') as f:
response = requests.post(
'https://markdownanything.com/api/v1/convert',
headers=headers,
files={'file': (Path(path).name, f)},
)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', '60'))
print(f"Rate limited, waiting {retry_after}s...")
time.sleep(retry_after)
continue
response.raise_for_status()
results.append(response.json())
time.sleep(delay) # Respect rate limits
return results