> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pdfnoodle.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Convert Markdown to PDF

> Convert Markdown text into a beautifully styled PDF document. Supports full Markdown syntax including headings, lists, tables, code blocks with syntax highlighting, and more.

POST [https://api.pdfnoodle.com/v1/tools/convert-markdown-to-pdf](https://api.pdfnoodle.com/v1/tools/convert-markdown-to-pdf)

## Request

<CodeGroup>
  ````bash cURL theme={null}
  curl --location 'https://api.pdfnoodle.com/v1/tools/convert-markdown-to-pdf' \
  --header 'Authorization: Bearer pdfnoodle_api_123456789' \
  --header 'Content-Type: application/json' \
  --data '{
      "markdown": "# My Report\n\nThis is a **bold** statement.\n\n## Section 1\n\n- Item 1\n- Item 2\n\n```javascript\nconsole.log(\"Hello world\");\n```",
      "pdfOptions": {
          "format": "A4",
          "margin": {
              "top": "20mm",
              "right": "15mm",
              "bottom": "20mm",
              "left": "15mm"
          }
      },
      "finalFilename": "my-report.pdf",
      "expiration": 3600
  }'
  ````

  ```javascript JavaScript theme={null}
  const response = await fetch(
    "https://api.pdfnoodle.com/v1/tools/convert-markdown-to-pdf",
    {
      method: "POST",
      headers: {
        Authorization: "Bearer pdfnoodle_api_123456789",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        markdown:
          "# My Report\n\nThis is a **bold** statement.\n\n## Section 1\n\n- Item 1\n- Item 2",
        pdfOptions: {
          format: "A4",
          margin: {
            top: "20mm",
            right: "15mm",
            bottom: "20mm",
            left: "15mm",
          },
        },
        finalFilename: "my-report.pdf",
        expiration: 3600,
      }),
    }
  );

  const result = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://api.pdfnoodle.com/v1/tools/convert-markdown-to-pdf',
      headers={
          'Authorization': 'Bearer pdfnoodle_api_123456789',
          'Content-Type': 'application/json'
      },
      json={
          'markdown': '# My Report\n\nThis is a **bold** statement.\n\n## Section 1\n\n- Item 1\n- Item 2',
          'pdfOptions': {
              'format': 'A4',
              'margin': {
                  'top': '20mm',
                  'right': '15mm',
                  'bottom': '20mm',
                  'left': '15mm'
              }
          },
          'finalFilename': 'my-report.pdf',
          'expiration': 3600
      }
  )

  result = response.json()
  ```
</CodeGroup>

## Response

<CodeGroup>
  ```json Success (200 OK) theme={null}
  {
    "status": "SUCCESS",
    "url": "https://s3.amazonaws.com/...",
    "fileName": "my-report.pdf",
    "urlValidUntil": "2025-01-01T02:00:00.000Z"
  }
  ```

  ```json Validation Error (400 Bad Request) theme={null}
  {
    "message": "markdown is markdown content cannot be empty"
  }
  ```
</CodeGroup>

The response contains a `url` pointing to the generated PDF file. While the URL in the response expires after the time specified in `expiration` (default: 1 hour), the file itself is stored persistently and can be downloaded at any time from the [dashboard logs](https://app.pdfnoodle.com/logs).

## Supported Markdown Features

The converter supports the full Markdown specification including:

* **Headings** (H1 through H6)
* **Text formatting** (bold, italic, strikethrough)
* **Lists** (ordered and unordered, nested)
* **Tables**
* **Code blocks** with syntax highlighting (powered by Prism.js)
* **Inline code**
* **Links and images**
* **Blockquotes**
* **Horizontal rules**

<Info>
  Code blocks include automatic syntax highlighting for all major programming languages. Just specify the language after the opening triple backticks (e.g., ` ```javascript `).
</Info>

## Operation Tracking

Each markdown conversion creates a record in your dashboard logs, allowing you to:

* View all past conversions with their status and metadata
* Re-download generated PDFs at any time via the logs table
* Track usage across your team

<Note>
  **Business and Scale plans**: Markdown conversion operations are unlimited and do not count toward your PDF generation quota.

  **Starter plans**: Markdown conversion operations count toward your total volume quota.
</Note>

## Async Mode

By default, the request waits for the conversion to complete before returning a response. If you set `async: true`, the endpoint returns immediately with a `requestId` and `statusUrl` that you can use to poll for the result.

```json Async Response (200 OK) theme={null}
{
  "requestId": "pdfnoodle_request_123456789",
  "statusUrl": "https://api.pdfnoodle.com/v1/tools/status/pdfnoodle_request_123456789",
  "message": "The tool is being executed asynchronously. Check the status using the status URL."
}
```

Use the [Get Tool Status](/api-reference/tools/get-tool-status) endpoint to check the result.

### Request Timeout (>30 seconds)

<Warning>
  Even without `async: true`, if the operation takes more than 30 seconds it will automatically be processed in the background.
</Warning>

If the conversion takes longer than 30 seconds, you'll receive a `202 Accepted` response with a `requestId` and `statusUrl` to poll for the result:

```json Timeout (202 Accepted) theme={null}
{
  "requestId": "pdfnoodle_request_123456789",
  "statusUrl": "https://api.pdfnoodle.com/v1/tools/status/pdfnoodle_request_123456789",
  "message": "Couldn't complete the operation within 30 seconds, it is being processed asynchronously. Check the status using the status URL."
}
```

## Custom CSS

You can inject custom CSS to override the default styling:

```json theme={null}
{
  "markdown": "# Custom Styled Report",
  "customCss": "body { font-family: 'Georgia', serif; } h1 { color: #2563eb; border-bottom: 2px solid #2563eb; }"
}
```

## Parameters

<ParamField body="markdown" type="string" required>
  The Markdown content to convert to PDF. Cannot be empty.
</ParamField>

<ParamField body="customCss" type="string">
  Custom CSS to apply to the rendered PDF. This will be injected alongside the
  default styles, allowing you to override any default styling.
</ParamField>

<ParamField body="pdfOptions" type="object">
  Configuration options for the PDF output. See fields below.
</ParamField>

<ParamField body="pdfOptions.format" type="string" default="Letter">
  Paper format. One of: `Letter`, `Legal`, `Tabloid`, `Ledger`, `A0`, `A1`,
  `A2`, `A3`, `A4`, `A5`, `A6`.
</ParamField>

<ParamField body="pdfOptions.landscape" type="boolean" default="false">
  Set to `true` to use landscape orientation.
</ParamField>

<ParamField body="pdfOptions.scale" type="number" default="1">
  Scale of the webpage rendering. Must be between `0.1` and `2`.
</ParamField>

<ParamField body="pdfOptions.printBackground" type="boolean" default="false">
  Set to `true` to print background graphics and colors.
</ParamField>

<ParamField body="pdfOptions.pageRanges" type="string">
  Paper ranges to print, e.g., `"1-5"` or `"1,3,5-7"`. An empty string means
  all pages are printed.
</ParamField>

<ParamField body="pdfOptions.margin" type="object">
  Page margins. Each value accepts a number (in pixels) or a string with units
  (`px`, `in`, `cm`, `mm`).
</ParamField>

<ParamField body="pdfOptions.margin.top" type="string | number">
  Top margin. Default: `0`
</ParamField>

<ParamField body="pdfOptions.margin.right" type="string | number">
  Right margin. Default: `0`
</ParamField>

<ParamField body="pdfOptions.margin.bottom" type="string | number">
  Bottom margin. Default: `0`
</ParamField>

<ParamField body="pdfOptions.margin.left" type="string | number">
  Left margin. Default: `0`
</ParamField>

<ParamField body="finalFilename" type="string">
  The desired filename for the generated PDF. Must end with `.pdf`. If not
  provided, a random filename will be generated.
</ParamField>

<ParamField body="expiration" type="number" default="3600">
  Number of seconds that the generated signed URL will take to expire. Must be
  between 60 (1 minute) and 604800 (7 days). Default: 3600 (1 hour).
</ParamField>

<ParamField body="async" type="boolean" default="false">
  If `true`, the request returns immediately with a `requestId` and `statusUrl`
  instead of waiting for the operation to complete. You can then poll the
  [Get Tool Status](/api-reference/tools/get-tool-status) endpoint to check
  when the result is ready.
</ParamField>
