# Markdown Converter API

Convert documents, images and webpages to Markdown.
Optimized for AI agents, RAG pipelines and LLM processing.
Pay-per-use via x402 v1/v2 or manual payment.

## For autonomous AI agents: use the ready SKILL.md → https://mdapi.io/.well-known/SKILL.md or https://mdapi.io/SKILL.md

~~~meta
version: 1.0.0
base_url: https://mdapi.io
auth: bearer
auth_header: Authorization
content_type: application/json
errors: standard
~~~

## Method Semantics

| Method | Response Format | Notes                                     |
|--------|-----------------|-------------------------------------------|
| GET    | Markdown        | Always returns Markdown, including errors |
| POST   | JSON            | Always returns JSON, including errors     |
| Error  | Same as method  | GET errors = Markdown, POST errors = JSON |

## Response Format Rules

- **GET /** — Returns raw Markdown. Use for direct content.
- **GET /** with errors — Returns Markdown with error description.
- **POST /** — Returns JSON with success, markdown, prompt_result, metadata.
- **result=both** on GET — Returns markdown followed by `## Prompt Result` section.
- **result=both** on POST — Returns JSON with both markdown and prompt_result fields.

## Streaming

Enable streaming with stream=true parameter. Uses SSE format:

1. First message (token info):
```
data: {"type":"token_info","status":"valid","balance":99,"expires":2027-01-01}
```

2. Content chunks:
```
data: {"content":" markdown chunk ","resource":"url","mimetype":"application/pdf"}
```

3. End marker:
```
data: [DONE]
```

Error during streaming ends with error chunk in format: {"error":"message","code":400}

## Global Types

```typescript
interface ConversionRequest {
  url?: string;
  text?: string;
  file?: File;
  filename?: string;
  prompt?: string;
  result?: "markdown" | "prompt" | "both";
  token?: string;
  memo?: string;
}

interface ConversionResponse {
  success: boolean;
  markdown?: string;
  prompt_result?: string;
  resource?: string;
  mimetype?: string;
  token_status?: "free" | "valid" | "invalid";
  token_balance?: number;
  token_expires?: string;
}

interface ErrorResponse {
  error: string;
  code?: string;
  message?: string;
}
```

## Capability: Convert URL

~~~meta
id: convert.url
transport: HTTP GET /
auth: optional
~~~

### Intention

Converts a publicly accessible URL (webpage, PDF, DOCX, image, etc.) to clean Markdown format. This is the primary
endpoint for converting web documents. Free tier available (10 requests/day), paid tier at $0.01/request via x402 protocol.

### Auth Intention

No authentication required for free tier. For paid tier, use Bearer token in Authorization header or ?token query parameter.
A token must be activated first with memo before use—see token activation flow.

### Logic Constraints

- One of url or text must be provided
- Maximum file size: 100MB
- Maximum URL content: 50MB
- Free tier: 10 requests per day (no token required)
- Paid tier: $0.01 per conversion (USDC on Solana)
- Token validity: 1 year from activation
- Rate limit: 10,000 requests/hour

### Input

```typescript
interface ConvertUrlRequest {
  url: string;                                   // URL to convert (required if no text)
  prompt?: string;                               // Custom LLM instructions
  result?: "markdown" | "prompt" | "both";       // Response format
  token?: string;                                // Access token for paid tier
  memo?: string;                                 // Token activation memo
}
```

### Output

```typescript
interface ConvertUrlResponse {
  success: boolean;
  markdown: string;                              // Converted Markdown content
  prompt_result?: string;                        // LLM result (when prompt + result=prompt/both)
  resource: string;                              // Original URL, "text", or filename
  mimetype: string;                              // Source MIME type
  token_status?: "free" | "valid" | "invalid";
  token_balance?: number;                        // Remaining balance (paid tier)
  token_expires?: string;                        // Token expiry timestamp
}
```

### Errors

- 400 Bad Request: Missing url or text parameter
- 401 Unauthorized: Invalid or expired token
- 402 Payment Required: Token requires activation or payment
- 413 Payload Too Large: File exceeds 100MB limit
- 429 Rate Limited: Exceeded rate limit (10,000/hour)

### Example

```bash
# Free conversion
curl "https://mdapi.io/?url=https://example.com/doc.pdf"

# With prompt
curl "https://mdapi.io/?url=https://example.com/doc.pdf&prompt=Summarize&result=both"

# With token
curl "https://mdapi.io/?url=https://example.com/doc.pdf&token=YOUR_TOKEN"
```

## Capability: Convert Text

~~~meta
id: convert.text
transport: HTTP GET /?text=...
auth: optional
~~~

### Intention

Converts direct text content (HTML, XML, JSON, CSV, TXT) to Markdown. Useful for processing
local files or text data without uploading.

### Input

```typescript
interface ConvertTextRequest {
  text: string;                                  // Text content to convert
  prompt?: string;                               // Custom LLM instructions
  result?: "markdown" | "prompt" | "both";
  token?: string;
  memo?: string;
}
```

### Output

```typescript
interface ConvertTextResponse {
  success: boolean;
  markdown: string;
  prompt_result?: string;
  token_status?: "free" | "valid" | "invalid";
}
```

### Example

```bash
curl "https://mdapi.io/?text=Hello+World&prompt=Summarize+this&result=prompt"
```

## Capability: Upload File

~~~meta
id: convert.file
transport: HTTP POST /
auth: optional
content_type: multipart/form-data
~~~

### Intention

Upload a file for conversion. Supports multipart file upload with additional form parameters.
Returns JSON response with conversion results.

### Input

```typescript
interface UploadFileRequest {
  file: File;                                    // File to convert (multipart)
  url?: string;                                  // Alternative: URL to convert
  text?: string;                                 // Alternative: direct text
  prompt?: string;
  result?: "markdown" | "prompt" | "both";
  token?: string;
  memo?: string;
}
```

### Output

```typescript
interface UploadFileResponse {
  success: boolean;
  markdown?: string;
  prompt_result?: string;
  resource?: string;
  mimetype?: string;
  token_status?: "free" | "valid" | "invalid";
  token_balance?: number;
  token_expires?: string;
}
```

### Errors

- 400 Bad Request: No file, url, or text provided
- 413 Payload Too Large: File exceeds 100MB

### Example

```bash
curl -X POST -F "file=@document.pdf" "https://mdapi.io/"
curl -X POST -H "Authorization: Bearer TOKEN" -F "file=@document.pdf" "https://mdapi.io/"

# Token activation
curl -X POST -H "Authorization: Bearer TOKEN" -H "X-Memo-Required: MEMO" -F "file=@doc.pdf" "https://mdapi.io/"
```

## Capability: OpenAI Compatible

~~~meta
id: openai.chat
transport: HTTP POST /v1/chat/completions
auth: optional
~~~

### Intention

OpenAI-compatible API for streaming chat completion with document conversion.
Supports URL extraction, image_url, file uploads, and streaming SSE responses.

### Input

```typescript
interface ChatCompletionRequest {
  model: string;                                 // Model identifier (any string)
  messages: Array<{
    role: "user" | "system" | "assistant";
    content: string | Array<ContentPart>;
  }>;
  stream?: boolean;                              // Enable SSE streaming
  url?: string;                                  // Direct URL to convert
  file?: {
    data: string;                                // Base64 encoded file
    filename: string;
  };
}

type ContentPart =
  | { type: "text"; text: string }
  | { type: "image_url"; image_url: { url: string } }
  | { type: "file"; file: { data: string; filename: string } };
```

### Output

```typescript
interface ChatCompletionResponse {
  id: string;
  object: "chat.completion";
  created: number;
  model: string;
  choices: Array<{
    index: number;
    message: { role: string; content: string };
    finish_reason: "stop" | "length";
  }>;
  usage?: {
    prompt_tokens: number;
    completion_tokens: number;
    total_tokens: number;
  };
}
```

### Example

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://mdapi.io/v1",
    api_key="YOUR_TOKEN"
)

response = client.chat.completions.create(
    model="markdown-v1",
    messages=[{"role": "user", "content": "Convert https://example.com/doc.pdf"}]
)
print(response.choices[0].message.content)
```

## Capability: MCP Server

~~~meta
id: mcp.manifest
transport: HTTP GET /mcp
auth: none
~~~

### Intention

Returns MCP (Model Context Protocol) server manifest with available tools for AI agents.
The convert tool provides unified document conversion through MCP protocol.

### Output

```typescript
interface McpManifest {
  mcp: "1.0.0";
  serverInfo: {
    name: string;
    version: string;
  };
  capabilities: {
    tools: { listChanged: boolean };
    resources: { subscribe: boolean; listChanged: boolean };
  };
  tools: Array<{
    name: string;
    description: string;
    inputSchema: object;
  }>;
  resources: Array<{
    uri: string;
    name: string;
    mimeType: string;
    description: string;
  }>;
}
```

### Example

```json
{
  "mcpServers": {
    "mdapi": {
      "url": "https://mdapi.io/mcp"
    }
  }
}
```

## Capability: MCP Tool Call

~~~meta
id: mcp.tools.call
transport: HTTP POST /mcp
auth: optional
~~~

### Intention

Execute MCP tool calls via JSON-RPC. The convert tool handles all conversion operations.

### Input

```typescript
interface McpToolCallRequest {
  jsonrpc: "2.0";
  id: string | number;
  method: "tools/call";
  params: {
    name: "convert";
    arguments: {
      url?: string;
      text?: string;
      file?: string;
      filename?: string;
      prompt?: string;
      result?: "markdown" | "prompt" | "both";
      token?: string;
      memo?: string;
    };
  };
}
```

### Output

```typescript
interface McpToolCallResponse {
  jsonrpc: "2.0";
  id: string | number;
  result: {
    content: Array<{
      type: "text";
      text: string;  // JSON string with ConversionResponse
    }>;
    isError: boolean;
  };
}
```

## Capability: Health Check

~~~meta
id: system.health
transport: HTTP GET /health
auth: none
~~~

### Intention

Public health check endpoint for monitoring. Returns service status and version.

### Output

```typescript
interface HealthResponse {
  status: string;
  version: string;
}
```

### Example

```bash
curl "https://mdapi.io/health"
# {"status":"ok","version":"1.0.0"}
```

## Capability: AI Discovery

~~~meta
id: agent.discovery
transport: HTTP GET /.well-known/ai-discovery.json
auth: none
~~~

### Intention

Unified AI agent discovery endpoint combining MCP, ACP, A2A, and other protocol manifests.
Agents use this to discover available capabilities and protocols.

### Output

```typescript
interface AiDiscoveryResponse {
  version: string;
  provider: {
    name: string;
    description: string;
    url: string;
  };
  protocols: {
    mcp: { name: string; version: string; manifest: string };
    acp: { name: string; version: string; manifest: string };
    a2a: { name: string; version: string; manifest: string };
    x402: { name: string; version: string; manifest: string };
  };
}
```

## Capability: x402 Payment

~~~meta
id: payment.x402
transport: HTTP GET /.well-known/x402.json
auth: none
~~~

### Intention

x402 v2 payment manifest for autonomous agents. Describes payment requirements,
pricing, and token activation flow.

### Logic Constraints

- Free tier: 10 requests/day
- Paid tier: $0.01/request (USDC on Solana)
- Tokens must be activated before use (token + memo)
- Activated tokens valid for 1 year

### Output

```typescript
interface X402Manifest {
  version: "2.0";
  protocol: "x402";
  provider: { name: string; url: string };
  payment: {
    scheme: string;
    network: string;
    recipient: string;
    token: string;
    minAmount: number;
  };
  pricing: {
    free: { limit: number; window: string };
    paid: { price: number; currency: string };
  };
  activation: {
    required: boolean;
    flow: string[];
  };
}
```

## Lifecycle: Token

~~~states
free -> valid: Token activated with payment
valid -> expired: Token validity period ends
valid -> exhausted: Token balance reaches zero
expired -> valid: Token renewed with payment
exhausted -> valid: Token renewed with payment
~~~

| State     | Terminal | Description                     |
|-----------|----------|---------------------------------|
| free      | no       | Free tier (10 requests/day)     |
| valid     | no       | Paid token activated and usable |
| expired   | yes      | Token validity period ended     |
| exhausted | yes      | Token balance depleted          |

## Payment Modes

mdapi.io supports two distinct payment flows:

### Manual Payment (Human-initiated)

Uses X-* headers for payment requirements:
- X-Token-Required — Token needed for paid tier
- X-Memo-Required — Memo for token activation
- X-Wallet-Address — Solana wallet for payment
- X-QR-Payment — QR code payload for easy payment

Flow:
1. Request conversion - receive 402 with X-* headers
2. User sends USDC to wallet with memo
3. Retry with token + memo to activate
4. After activation, use token only

### Autonomous Payment (Agent-initiated)

Uses PAYMENT-* headers for automated payment:
- PAYMENT-REQUIRED - Payment requirements from service
- PAYMENT-SIGNATURE - Signed payment payload from client
- PAYMENT-RESPONSE - Payment confirmation from service

Flow:
1. Request conversion - receive 402 with PAYMENT-REQUIRED
2. Agent prepares and signs payment
3. Retry with PAYMENT-SIGNATURE header
4. Service verifies and returns PAYMENT-RESPONSE

Do NOT mix these flows. Use X-* for manual, PAYMENT-* for autonomous.

## Envelope: API Response

~~~meta
id: api.response
version: 1.0.0
~~~

### Intention

All API responses follow this envelope structure.

### Schema

```typescript
interface ApiResponse<T = unknown> {
  success: boolean;
  data?: T;
  error?: {
    code: string;
    message: string;
    details?: unknown;
  };
  meta?: {
    token_status?: string;
    token_balance?: number;
    token_expires?: string;
  };
}
```

## Standard Errors

When errors: standard is set, these error codes apply:

| Status | Type              | Description                       |
|--------|-------------------|-----------------------------------|
| 400    | Bad Request       | Missing required parameters       |
| 401    | Unauthorized      | Invalid or expired token          |
| 402    | Payment Required  | Token needs activation or payment |
| 404    | Not Found         | Resource not found                |
| 413    | Payload Too Large | File exceeds 100MB limit          |
| 429    | Rate Limited      | Exceeded rate limit               |
| 500    | Server Error      | Internal error                    |

## Links

- **API docs:** https://mdapi.io
- **MCP server manifest:** https://mdapi.io/mcp
- **Health check:** https://mdapi.io/health
- **API documentation:** https://mdapi.io/llms.txt
- **Full API documentation:** https://mdapi.io/llms-full.txt
- **AI discovery:** https://mdapi.io/.well-known/ai-discovery.json                                        or https://mdapi.io/ai-discovery.json
- **AI agent discovery:** https://mdapi.io/.well-known/agent.json                                         or https://mdapi.io/agent.json
- **A2A agent card:** https://mdapi.io/.well-known/agent-card.json                                        or https://mdapi.io/agent-card.json
- **ACP manifest:** https://mdapi.io/.well-known/acp.json                                                 or https://mdapi.io/acp.json
- **x402 payment manifest:** https://mdapi.io/.well-known/x402.json                                       or https://mdapi.io/x402.json
- **OpenAPI specification (JSON):** https://mdapi.io/.well-known/openapi.json                             or https://mdapi.io/openapi.json
- **OpenAPI specification (YAML):** https://mdapi.io/.well-known/openapi.yaml                             or https://mdapi.io/openapi.yaml
- **MAPI specification (case-insensitive path MAPI.md support):** https://mdapi.io/.well-known/mapi.md    or https://mdapi.io/mapi.md
- **Skill specification (case-insensitive path SKILL.md support):** https://mdapi.io/.well-known/skill.md or https://mdapi.io/skill.md

## Disclaimer

**The service is provided "AS IS".**

