Convert Markdown
curl --request POST \
--url https://api.mark2notion.com/api/convert \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"markdown": "<string>"
}
'import requests
url = "https://api.mark2notion.com/api/convert"
payload = { "markdown": "<string>" }
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({markdown: '<string>'})
};
fetch('https://api.mark2notion.com/api/convert', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mark2notion.com/api/convert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'markdown' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.mark2notion.com/api/convert"
payload := strings.NewReader("{\n \"markdown\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mark2notion.com/api/convert")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"markdown\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mark2notion.com/api/convert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"markdown\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"blocks": [
{
"type": "heading_1",
"heading_1": {
"rich_text": [
{
"type": "text",
"text": {
"content": "My Heading"
}
}
]
}
},
{
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": "This is a "
}
},
{
"type": "text",
"text": {
"content": "bold"
},
"annotations": {
"bold": true
}
},
{
"type": "text",
"text": {
"content": " paragraph with a "
}
},
{
"type": "text",
"text": {
"content": "link",
"link": {
"url": "https://example.com"
}
}
},
{
"type": "text",
"text": {
"content": "."
}
}
]
}
},
{
"type": "bulleted_list_item",
"bulleted_list_item": {
"rich_text": [
{
"type": "text",
"text": {
"content": "List item 1"
}
}
]
}
},
{
"type": "bulleted_list_item",
"bulleted_list_item": {
"rich_text": [
{
"type": "text",
"text": {
"content": "List item 2"
}
}
]
}
}
],
"blockCount": 4
}
}
API Reference
Convert Markdown
Convert Markdown text to Notion block objects
POST
/
api
/
convert
Convert Markdown
curl --request POST \
--url https://api.mark2notion.com/api/convert \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"markdown": "<string>"
}
'import requests
url = "https://api.mark2notion.com/api/convert"
payload = { "markdown": "<string>" }
headers = {
"x-api-key": "<x-api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({markdown: '<string>'})
};
fetch('https://api.mark2notion.com/api/convert', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.mark2notion.com/api/convert",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'markdown' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <x-api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.mark2notion.com/api/convert"
payload := strings.NewReader("{\n \"markdown\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<x-api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.mark2notion.com/api/convert")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"markdown\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mark2notion.com/api/convert")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<x-api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"markdown\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"blocks": [
{
"type": "heading_1",
"heading_1": {
"rich_text": [
{
"type": "text",
"text": {
"content": "My Heading"
}
}
]
}
},
{
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": "This is a "
}
},
{
"type": "text",
"text": {
"content": "bold"
},
"annotations": {
"bold": true
}
},
{
"type": "text",
"text": {
"content": " paragraph with a "
}
},
{
"type": "text",
"text": {
"content": "link",
"link": {
"url": "https://example.com"
}
}
},
{
"type": "text",
"text": {
"content": "."
}
}
]
}
},
{
"type": "bulleted_list_item",
"bulleted_list_item": {
"rich_text": [
{
"type": "text",
"text": {
"content": "List item 1"
}
}
]
}
},
{
"type": "bulleted_list_item",
"bulleted_list_item": {
"rich_text": [
{
"type": "text",
"text": {
"content": "List item 2"
}
}
]
}
}
],
"blockCount": 4
}
}
Overview
The convert endpoint transforms Markdown text into Notion block objects that can be used with the Notion API, our append endpoint, or the append-blocks endpoint when you need to append prebuilt blocks. Our converter supports a comprehensive set of Markdown features including GitHub Flavored Markdown (GFM) alerts, advanced formatting, and intelligent text splitting.Supported Markdown Features
Basic Elements
- Headings:
#,##,###,####,#####,######(H4-H6 map toheading_3) - Paragraphs: Regular text and line breaks
- Text Formatting:
**bold**,*italic*,`code`,~~strikethrough~~ - Colors:
<span style="color: red">colored text</span>(supports 9 Notion colors) - Links:
[text](url)and<https://example.com>autolinks - Images:

Lists
- Bulleted Lists:
- itemor* item - Numbered Lists:
1. item - Nested Lists: Unlimited nesting depth supported
- Mixed Lists: Combine bulleted and numbered at different levels
Code
- Inline Code:
`code` - Code Blocks:
```languagewith syntax highlighting - Indented Code: 4+ space indentation
Advanced Features
- Tables: Full Markdown table support with headers
- Blockquotes:
> quoted text - GFM Alerts:
> [!NOTE],> [!TIP],> [!IMPORTANT],> [!WARNING],> [!CAUTION] - Horizontal Rules:
---,***, or___ - Toggle Blocks: HTML
<details>and<summary>tags for collapsible sections
HTML Color Support
Add colors to your text using standard HTML syntax:This is <span style="color: red">red text</span> and <span style="color: blue">blue text</span>.
red,blue,green,yellow,orange,purple,pink,gray(orgrey),brown
- Works with all block types (headings, lists, quotes, etc.)
- Can be combined with other formatting (bold, italic, etc.)
- Unsupported colors are silently ignored
# Heading with <span style="color: purple">purple text</span>
Paragraph with **bold <span style="color: red">red</span>** text.
- List item with <span style="color: green">green text</span>
Toggle Blocks (Collapsible Sections)
Create collapsible toggle blocks using HTML<details> and <summary> tags:
<details>
<summary>Click to expand</summary>
Content inside the toggle block can include:
- Headings
- Lists
- Paragraphs
- Any other Markdown elements
</details>
- Summary text supports bold (
<b>or<strong>) and italic (<i>or<em>) formatting - Content can include any Markdown elements (headings, lists, code blocks, etc.)
- Nested details blocks are not supported
- Malformed HTML is silently ignored
<details>
<summary><b>Email Summary</b></summary>
## Section 1 Title
- Bullet point 1
- Bullet point 2
## Section 2 Title
- Another bullet point
</details>
<details>
<summary><i>Optional Settings</i></summary>
Configure advanced options here.
</details>
Generated Notion Block Types
| Markdown Element | Notion Block Type | Notes |
|---|---|---|
# Heading | heading_1, heading_2, heading_3 | H4-H6 map to heading_3 |
Text | paragraph | With rich text formatting |
- Item | bulleted_list_item | Unlimited nesting |
1. Item | numbered_list_item | Unlimited nesting |
```code``` | code | With language support |
> Quote | quote | Standard blockquotes |
> [!NOTE] | callout | With icons and colors |
 | image | External images |
| Table | | table | With headers |
--- | divider | Horizontal rules |
<details> | toggle | Collapsible sections with children |
Text Length Handling
Automatic Text Splitting
Content longer than 2000 characters is automatically split across multiplerich_text objects within the same block:
- ✅ No content loss: All text is preserved
- ✅ Smart splitting: Breaks at safe boundaries when possible
- ✅ Maintains formatting: Bold, italic, and other formatting preserved across splits
- ✅ Transparent: The splitting is handled automatically
Example: Long Content
{
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": { "content": "First 2000 characters of content..." }
},
{
"type": "text",
"text": { "content": "...remaining characters continue here" }
}
]
}
}
Request
string
required
Your Mark2Notion API key
string
required
The Markdown content to convert to Notion blocks
Response
string
Will be “success” for successful requests
object
Examples
curl -X POST "https://api.mark2notion.com/api/convert" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"markdown": "# My Heading\n\nThis is a **bold** paragraph with a [link](https://example.com).\n\n> [!NOTE]\n> This is a GitHub-flavored alert that becomes a callout!\n\n- List item 1\n- List item 2\n\n---\n\n## Code Example\n\n```javascript\nconsole.log(\"Hello World!\");\n```"
}'
const response = await fetch('https://api.mark2notion.com/api/convert', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
markdown: `# My Heading
This is a **bold** paragraph with a [link](https://example.com).
> [!NOTE]
> This is a GitHub-flavored alert that becomes a callout!
- List item 1
- List item 2
---
## Code Example
\`\`\`javascript
console.log("Hello World!");
\`\`\``
})
});
const data = await response.json();
console.log(data.data.blocks);
import requests
response = requests.post(
'https://api.mark2notion.com/api/convert',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'markdown': '''# My Heading
This is a **bold** paragraph with a [link](https://example.com).
> [!NOTE]
> This is a GitHub-flavored alert that becomes a callout!
- List item 1
- List item 2
---
## Code Example
```javascript
console.log("Hello World!");
```'''
}
)
data = response.json()
print(data['data']['blocks'])
{
"status": "success",
"data": {
"blocks": [
{
"type": "heading_1",
"heading_1": {
"rich_text": [
{
"type": "text",
"text": {
"content": "My Heading"
}
}
]
}
},
{
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": "This is a "
}
},
{
"type": "text",
"text": {
"content": "bold"
},
"annotations": {
"bold": true
}
},
{
"type": "text",
"text": {
"content": " paragraph with a "
}
},
{
"type": "text",
"text": {
"content": "link",
"link": {
"url": "https://example.com"
}
}
},
{
"type": "text",
"text": {
"content": "."
}
}
]
}
},
{
"type": "bulleted_list_item",
"bulleted_list_item": {
"rich_text": [
{
"type": "text",
"text": {
"content": "List item 1"
}
}
]
}
},
{
"type": "bulleted_list_item",
"bulleted_list_item": {
"rich_text": [
{
"type": "text",
"text": {
"content": "List item 2"
}
}
]
}
}
],
"blockCount": 4
}
}
Error Responses
Handle Errors
Understand error responses and how to handle them.
Usage Notes
Each convert request counts as 1 API call against your quota, regardless of the markdown size.
The returned blocks are standard Notion API block objects and can be used directly with the Notion API.
The convert endpoint returns raw Notion blocks without additional processing. For content that will be sent to Notion, consider using the
/append endpoint for Markdown sources or /append-blocks when you already have block JSON. Both include smart processing for large payloads, text splitting, and validation.