Skip to main content
This guide is for integrations that read or write page and comment content with the markdown endpoints, especially code that parses or generates markdown. Enhanced markdown (v1) is deprecated. The next Notion-Version makes Notion-flavored Markdown (v2) the default and rejects markdown_version: "v1". Watch the changelog for the version name and date. You can switch now on any current Notion-Version. The steps below cover the request change, the syntax changes, and how to test.

1. Find where you send markdown

These endpoints accept markdown_version: On POST /v1/pages and the comment endpoints, send markdown_version only with markdown. Sending it with children or rich_text returns a 400 validation_error.

2. Add markdown_version: "v2"

Set the parameter on every request in the table. The version applies to the whole request, so v2 input is parsed as v2 and v2 responses are rendered as v2.
The JavaScript SDK supports markdown_version in @notionhq/client v5.29.0 and later.

3. Update your parser and generator

Compare your code against the syntax differences table below. The biggest changes are structural:
  • Separate blocks with a blank line. In v2, a single newline doesn’t start a new block.
  • Don’t indent children with tabs, except in lists. A block that has children uses its tag form, such as <p>, <quote>, or <toggle>, with the children after a blank line.
  • Put block colors in a color attribute on the block’s tag. v2 saves {color="..."} as literal text.
  • Expect v2 output to use tags for inline formatting, such as <b> and <code>, where v1 used ** and backticks.
For the full v2 syntax, see the Notion-flavored Markdown format reference.

4. Handle new v2 behavior

Parse errors return a 400. When v2 input can’t become the blocks it describes, the request fails with a validation_error whose message starts with Markdown errors blocked parsing. v1 saved the same input as literal text. For example, an image inside a line of text (Text ![chart](https://example.com/chart.png) more) fails in v2. Put each image on its own line with blank lines around it. Updates can return warnings. A PATCH /v1/pages/:page_id/markdown request that succeeds can include a warnings array. Each entry has a code and a message: Log these warnings while you migrate. A deprecated_tag warning means your generator still writes v1 syntax. See Update warnings for the response shape. Meeting note transcripts use a new tag. v2 puts the transcript in <meeting-notes-section-transcript> inside <meeting-notes>. See Transcripts in v2.

5. Test the switch

  1. Pick a page that uses the block types your integration reads or writes.
  2. Retrieve it twice, once with markdown_version=v1 and once with markdown_version=v2. Diff the two outputs and check each difference against the table below.
  3. Run your parser on the v2 output and confirm it finds the same blocks it found in the v1 output.
  4. On a test page, write your generator’s output with PATCH /v1/pages/:page_id/markdown, "type": "replace_content", and "markdown_version": "v2". Check that the response has no warnings. Then retrieve the page with markdown_version=v2 and run your parser on it. Check that it finds the blocks you meant to write. Don’t compare exact text, because v2 output can differ from valid input, such as <b> for **.

Syntax differences

Each row shows the same content in both versions, taken from real API output. Syntax not listed here, such as plain headings, bulleted and numbered list items, - [ ] to-dos, links, images, dividers, fenced code, block equations, citations, and custom emoji, is the same in both versions.

Structure

Blocks

Inline content

Common problems

Content runs together into one block. Your generator puts one newline between blocks. Add a blank line between blocks. A quote swallows the lines after it. A line right after a > line joins the quote. Add a blank line after the quote. Indented text joins its parent paragraph. Tab indentation only nests list items in v2. For other children, use the parent’s tag form, such as <p> or <toggle>. {color="..."} shows up as text on the page. v2 doesn’t read the v1 color syntax and doesn’t warn about it. Move the color into the block’s color attribute. An update fails with Markdown errors blocked parsing. The input mixes syntax that v2 can’t parse, such as an image inside a line of text. The error message says what to fix.