Notion to Markdown
curl --request POST \
--url https://api.mark2notion.com/api/notion-to-markdown \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"notionToken": "<string>",
"pageId": "<string>"
}
'import requests
url = "https://api.mark2notion.com/api/notion-to-markdown"
payload = {
"notionToken": "<string>",
"pageId": "<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({notionToken: '<string>', pageId: '<string>'})
};
fetch('https://api.mark2notion.com/api/notion-to-markdown', 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/notion-to-markdown",
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([
'notionToken' => '<string>',
'pageId' => '<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/notion-to-markdown"
payload := strings.NewReader("{\n \"notionToken\": \"<string>\",\n \"pageId\": \"<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/notion-to-markdown")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"notionToken\": \"<string>\",\n \"pageId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mark2notion.com/api/notion-to-markdown")
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 \"notionToken\": \"<string>\",\n \"pageId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"markdown": {
"parent": "# My Page Title\n\nThis is a paragraph with **bold** text and *italic* text.\n\n## Subheading\n\n- List item 1\n- List item 2\n - Nested item\n\n---\n\n```javascript\nconsole.log('Code block');\n```\n\n> This is a quote block\n\n| Column 1 | Column 2 |\n|----------|----------|\n| Cell 1 | Cell 2 |"
},
"pageId": "abc123def456"
}
}
{
"status": "success",
"data": {
"markdown": {
"parent": "# Main Page\n\nThis is the parent page content.\n\n> 📘 Note\n> This is a callout\n",
"Child Page 1": "## Child Page Content\n\nThis is content from the first child page.\n",
"Another Child": "## Another Child Page\n\nContent from another child page.\n"
},
"pageId": "abc123def456"
}
}
API Reference
Notion to Markdown
Convert Notion page content to Markdown format
POST
/
api
/
notion-to-markdown
Notion to Markdown
curl --request POST \
--url https://api.mark2notion.com/api/notion-to-markdown \
--header 'Content-Type: application/json' \
--header 'x-api-key: <x-api-key>' \
--data '
{
"notionToken": "<string>",
"pageId": "<string>"
}
'import requests
url = "https://api.mark2notion.com/api/notion-to-markdown"
payload = {
"notionToken": "<string>",
"pageId": "<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({notionToken: '<string>', pageId: '<string>'})
};
fetch('https://api.mark2notion.com/api/notion-to-markdown', 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/notion-to-markdown",
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([
'notionToken' => '<string>',
'pageId' => '<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/notion-to-markdown"
payload := strings.NewReader("{\n \"notionToken\": \"<string>\",\n \"pageId\": \"<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/notion-to-markdown")
.header("x-api-key", "<x-api-key>")
.header("Content-Type", "application/json")
.body("{\n \"notionToken\": \"<string>\",\n \"pageId\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.mark2notion.com/api/notion-to-markdown")
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 \"notionToken\": \"<string>\",\n \"pageId\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"status": "success",
"data": {
"markdown": {
"parent": "# My Page Title\n\nThis is a paragraph with **bold** text and *italic* text.\n\n## Subheading\n\n- List item 1\n- List item 2\n - Nested item\n\n---\n\n```javascript\nconsole.log('Code block');\n```\n\n> This is a quote block\n\n| Column 1 | Column 2 |\n|----------|----------|\n| Cell 1 | Cell 2 |"
},
"pageId": "abc123def456"
}
}
{
"status": "success",
"data": {
"markdown": {
"parent": "# Main Page\n\nThis is the parent page content.\n\n> 📘 Note\n> This is a callout\n",
"Child Page 1": "## Child Page Content\n\nThis is content from the first child page.\n",
"Another Child": "## Another Child Page\n\nContent from another child page.\n"
},
"pageId": "abc123def456"
}
}
Overview
The notion-to-markdown endpoint retrieves content from a Notion page and converts it to Markdown format. This is useful for exporting Notion content, creating backups, or integrating Notion content with other Markdown-based systems.Supported Block Types
The converter supports a comprehensive set of Notion block types:Text Blocks
- Paragraphs: Standard text blocks
- Headings: H1, H2, H3 (converted to
#,##,###) - Quotes: Blockquote blocks
- Callouts: Notion callouts (converted to GFM-style alerts when possible)
- Code Blocks: With language syntax support
Lists
- Bulleted Lists: Converted to
-items - Numbered Lists: Converted to
1.items - To-do Lists: Converted to
- [ ]or- [x]checkboxes - Nested Lists: Full nesting support
Media & Embeds
- Images: Converted to
format - External Images: Both uploaded and external images supported
Advanced Blocks
- Tables: Full table support with headers
- Dividers: Converted to
--- - Child Pages: Referenced in the output
- Child Databases: Referenced in the output
Text Formatting & Colors
All rich text formatting from Notion is preserved in the Markdown output:- Bold: Converted to
**bold** - Italic: Converted to
*italic* - Code: Converted to
`code` - Strikethrough: Converted to
~~strikethrough~~ - Links: Converted to
[text](url) - Colors: Converted to HTML
<span>tags with inline styles
red,blue,green,yellow,orange,purple,pink,gray,brown
This is <span style="color: red">red text</span> and <span style="color: blue">blue text</span>.
- Works with all block types (paragraphs, headings, lists, quotes, etc.)
- Can be combined with other formatting (bold, italic, code, etc.)
- Multiple colors can be used within a single block
- Background colors (e.g.,
red_background) are not currently supported - Colors are exported as HTML, which requires the Markdown renderer to support inline HTML
Request
string
required
Your Mark2Notion API key
string
Your Notion integration token. Optional when your workspace is connected via OAuth in the dashboard. Pass this if you prefer to authenticate with a manual integration token instead. See Using a Manual Notion Token.
string
required
The URL or page ID of the Notion page to convert. Pass the full
notion.so page URL or just the page ID — both are accepted.Response
string
Will be “success” for successful requests
object
Show data
Show data
object
string
The ID of the page that was converted
Examples
curl -X POST "https://api.mark2notion.com/api/notion-to-markdown" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"pageId": "https://notion.so/Your-Page-Title-abc123def456"
}'
const response = await fetch('https://api.mark2notion.com/api/notion-to-markdown', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
body: JSON.stringify({
pageId: 'https://notion.so/Your-Page-Title-abc123def456'
})
});
const data = await response.json();
console.log(data.data.markdown.parent); // Parent page content
// If there are child pages, they'll be available as separate properties:
// console.log(data.data.markdown['Child Page Name']);
import requests
response = requests.post(
'https://api.mark2notion.com/api/notion-to-markdown',
headers={
'Content-Type': 'application/json',
'x-api-key': 'YOUR_API_KEY'
},
json={
'pageId': 'https://notion.so/Your-Page-Title-abc123def456'
}
)
data = response.json()
print(data['data']['markdown']['parent']) # Parent page content
# If there are child pages, they'll be available as separate keys:
# print(data['data']['markdown']['Child Page Name'])
{
"status": "success",
"data": {
"markdown": {
"parent": "# My Page Title\n\nThis is a paragraph with **bold** text and *italic* text.\n\n## Subheading\n\n- List item 1\n- List item 2\n - Nested item\n\n---\n\n```javascript\nconsole.log('Code block');\n```\n\n> This is a quote block\n\n| Column 1 | Column 2 |\n|----------|----------|\n| Cell 1 | Cell 2 |"
},
"pageId": "abc123def456"
}
}
{
"status": "success",
"data": {
"markdown": {
"parent": "# Main Page\n\nThis is the parent page content.\n\n> 📘 Note\n> This is a callout\n",
"Child Page 1": "## Child Page Content\n\nThis is content from the first child page.\n",
"Another Child": "## Another Child Page\n\nContent from another child page.\n"
},
"pageId": "abc123def456"
}
}
Error Responses
Handle Errors
Understand error responses and how to handle them.
Common Errors
Invalid Notion Token
Invalid Notion Token
Status Code: 401 UnauthorizedThe Notion token provided is invalid or expired. Make sure you’re using a valid integration token.
Page Not Found
Page Not Found
Status Code: 404 Not FoundThe page ID doesn’t exist or your integration doesn’t have access to it. Verify the page ID and ensure the page is shared with your integration.
Access Denied
Access Denied
Status Code: 403 ForbiddenYour Notion integration doesn’t have permission to access this page. Share the page with your integration in Notion.
Response Structure
Themarkdown field in the response is an object that separates parent and child page content:
parent: Contains the main page’s Markdown content[Child Page Title]: If the page has child pages, each will be a separate property named after the child page title, containing that child’s Markdown content
- Access the main content via
data.markdown.parent - Iterate over child pages if they exist
- Maintain the hierarchy of your Notion page structure
Usage Notes
Each notion-to-markdown request counts as 1 API call against your quota, regardless of the page size or number of child pages.
The endpoint returns standard Markdown that’s compatible with GitHub Flavored Markdown (GFM) and most Markdown processors.
Make sure your Notion workspace is connected in the dashboard and has access to the page you want to convert.
Setup Guide
Connect your Notion workspace in the dashboard via OAuth. Then pass your target page as a URL or page ID in thepageId field — no manual integration tokens required.
Use Cases
- Content Backup: Export Notion pages to Markdown for backup purposes
- Static Site Generation: Convert Notion content to Markdown for static site generators
- Documentation Sync: Keep documentation in Notion and export to Markdown-based systems
- Content Migration: Move content from Notion to other platforms
- Version Control: Track Notion content changes in Git using Markdown format