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 httpx

Sync 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 data
import 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 data

Async 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