Export DOCX via REST API
The DOCX export API converts Tiptap JSON documents into .docx (Microsoft Word) files. It uses the same conversion library as the editor extension and produces equivalent DOCX output for standard content.
The REST API supports style overrides, custom-node rendering via the DSL, page size and margins, headers/footers, and element-level overrides (tableOverrides, paragraphOverrides, textRunOverrides, tableCellOverrides, imageOverrides). It does not accept JavaScript-function options. For the function-based custom-node API, use the editor extension, which also works server-side.
Review the postman collection
You can also experiment with the Document Conversion API by heading over to our Postman Collection.
Export DOCX
POST /v2/convert/export/docx
The /v2/convert/export/docx endpoint converts Tiptap documents into DOCX format. Users can POST documents to this endpoint and use various parameters to customize how different document elements are handled during the conversion process.
Export customization support
The /v2/convert/export/docx endpoint accepts style overrides,
page size/margins, headers/footers, the five element-level overrides (tableOverrides,
paragraphOverrides, textRunOverrides, tableCellOverrides, imageOverrides), and
custom-node rendering via the JSON DSL. It does not
accept JavaScript-function options. For the function-based custom-node API, use the editor
extension or the server side export
guide.
Example (cURL)
curl --output example.docx -X POST "https://api.tiptap.dev/v2/convert/export/docx" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-App-Id: YOUR_APP_ID" \
-H "Content-Type: application/json" \
-d '{
"doc": "{\"type\":\"doc\",\"content\":[{\"type\":\"paragraph\",\"attrs\":{\"textAlign\":\"left\"},\"content\":[{\"type\":\"text\",\"text\":\"Welcome to this demonstration of our editor ability to export a wide array of formatting options to DOCX, ensuring that your content retains its intended appearance in Word.\"}]}]}",
"exportType": "blob"
}'Subscription required
This endpoint requires a valid Tiptap subscription. For more details review our pricing page.
Required headers
| Name | Description |
|---|---|
Authorization | The JWT token to authenticate the request. Example: Bearer your-jwt-token |
X-App-Id | The Convert App-ID from the Convert settings page: https://cloud.tiptap.dev/v2/cloud/convert |
Content-Type | Must be application/json |
Body
| Name | Type | Description | Default |
|---|---|---|---|
doc | String | Tiptap's JSON | N/A |
exportType | string | The expected export type | blob |
styleOverrides | Object | Style overrides | {} |
pageSize | Object | Page size configuration | undefined |
pageMargins | Object | Page margins configuration | undefined |
headers | Object | Page header configuration | undefined |
footers | Object | Page footer configuration | undefined |
tableOverrides | Object | Table-level rendering overrides | undefined |
paragraphOverrides | Object | Paragraph-level rendering overrides | undefined |
textRunOverrides | Object | Text run rendering overrides | undefined |
tableCellOverrides | Object | Table cell rendering overrides | undefined |
imageOverrides | Object | Image rendering overrides | undefined |
customNodeDsl | Object | Custom-node DSL rules | undefined |
placeholders | Object | false | Optional { page?, total? } rename map matching Pages.configure({ placeholders }) so renamed tokens (e.g. {p} / {pages}) in plain-text headers/footers become live PAGE / NUMPAGES fields. Pass false to disable substitution entirely (literal {page} / {total} text in the exported .docx). See Custom token names. | undefined |
Page Size Configuration
The pageSize object allows you to customize the dimensions of your exported DOCX document:
| Property | Type | Description | Default |
|---|---|---|---|
width | string | The width of the page. Must be a positive number followed by a valid unit (cm, in, pt, pc, mm, px). | "21.0cm" |
height | string | The height of the page. Must be a positive number followed by a valid unit (cm, in, pt, pc, mm, px). | "29.7cm" |
Example cURL with custom page size:
curl --output example.docx -X POST "https://api.tiptap.dev/v2/convert/export/docx" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-App-Id: YOUR_APP_ID" \
-H "Content-Type: application/json" \
-d '{
"doc": "{\"type\":\"doc\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Document with custom page size\"}]}]}",
"exportType": "blob",
"pageSize": {"width": "21.0cm", "height": "29.7cm"}
}'Page Margins Configuration
The pageMargins object allows you to customize the margins of your exported DOCX document:
| Property | Type | Description | Default |
|---|---|---|---|
top | string | The top margin of the page. Can be negative. Must be a number followed by a valid unit (cm, in, pt, pc, mm, px). | "1.0cm" |
bottom | string | The bottom margin of the page. Can be negative. Must be a number followed by a valid unit (cm, in, pt, pc, mm, px). | "1.0cm" |
left | string | The left margin of the page. Must be a positive number followed by a valid unit (cm, in, pt, pc, mm, px). | "1.0cm" |
right | string | The right margin of the page. Must be a positive number followed by a valid unit (cm, in, pt, pc, mm, px). | "1.0cm" |
Example cURL with custom page margins:
curl --output example.docx -X POST "https://api.tiptap.dev/v2/convert/export/docx" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-App-Id: YOUR_APP_ID" \
-H "Content-Type: application/json" \
-d '{
"doc": "{\"type\":\"doc\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Document with custom margins\"}]}]}",
"exportType": "blob",
"pageMargins": {"top": "2.0cm", "bottom": "2.0cm", "left": "1.5cm", "right": "1.5cm"}
}'Headers and footers
The headers and footers objects allows you to configure a set of headers and footers options for your exported DOCX.
Headers Configuration
The headers object allows you to customize the headers of your exported DOCX document:
| Property | Type | Description |
|---|---|---|
evenAndOddHeaders | boolean | Whether to use different headers for odd and even pages |
differentFirstPage | boolean | Whether to use a different header on the first page. When true, the first value is used on page one instead of default. |
default | string | The standard default header on every page, or header on odd pages when the evenAndOddHeaders option is activated. Accepts a plain text string or stringified Tiptap JSONContent for rich formatting. |
first | string | The header on the first page. Only used when differentFirstPage is set to true. Accepts a plain text string or stringified Tiptap JSONContent for rich formatting. |
even | string | The header on even pages when the evenAndOddHeaders option is activated. Accepts a plain text string or stringified Tiptap JSONContent for rich formatting. |
Plain text vs. Tiptap JSONContent
Each header value can be either a plain text string (produces a simple unstyled header) or a
stringified Tiptap JSONContent object (enables rich formatting such as bold, italic, links,
etc.). When passing JSONContent, stringify the object with JSON.stringify() before sending it in
the request body.
Example cURL with custom headers:
curl --output example.docx -X POST "https://api.tiptap.dev/v2/convert/export/docx" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-App-Id: YOUR_APP_ID" \
-H "Content-Type: application/json" \
-d '{
"doc": "{\"type\":\"doc\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Document with custom headers\"}]}]}",
"exportType": "blob",
"headers": {"evenAndOddHeaders": true, "default": "Default Header", "first": "First Page Header", "even": "Even Page Header"}
}'Footers Configuration
The footers object allows you to customize the footers of your exported DOCX document:
| Property | Type | Description |
|---|---|---|
evenAndOddFooters | boolean | Whether to use different footers for odd and even pages |
differentFirstPage | boolean | Whether to use a different footer on the first page. When true, the first value is used on page one instead of default. |
default | string | The standard default footer on every page, or footer on odd pages when the evenAndOddFooters option is activated. Accepts a plain text string or stringified Tiptap JSONContent for rich formatting. |
first | string | The footer on the first page. Only used when differentFirstPage is set to true. Accepts a plain text string or stringified Tiptap JSONContent for rich formatting. |
even | string | The footer on even pages when the evenAndOddFooters option is activated. Accepts a plain text string or stringified Tiptap JSONContent for rich formatting. |
Plain text vs. Tiptap JSONContent
Each footer value can be either a plain text string (produces a simple unstyled footer) or a
stringified Tiptap JSONContent object (enables rich formatting such as bold, italic, links,
etc.). When passing JSONContent, stringify the object with JSON.stringify() before sending it in
the request body.
`{page}` / `{total}` tokens become live Word fields
The REST API translates {page}, {total}, and the {numpages} synonym inside plain-text
headers/footers into live Word PAGE / NUMPAGES fields in the exported .docx. Custom token
names (e.g. {p} / {pages}) require passing the optional placeholders rename map — see
Custom token names below. Pass "placeholders": false to ship
the tokens as literal text instead.
Custom token names (placeholders)
When the editor renames the built-in tokens via Pages.configure({ placeholders }), forward the same rename map to the REST API so the wire format stays aligned. The wire field has the same name and shape as the editor option:
{
"doc": "{\"type\":\"doc\",\"content\":[]}",
"footers": { "default": "{p} of {pages}" },
"placeholders": { "page": "p", "total": "pages" }
}When the map is omitted, the service falls back to recognizing {page}, {total}, and {numpages} (Word's spelling for the total-pages field, kept as a synonym so direct REST API callers can mirror what /import/docx emits). Renaming total removes the {numpages} synonym so stale tokens render literally — the rename is strict. Pass "placeholders": false to disable substitution on every slot so all {page} / {total} text ships literally with no live fields.
Example cURL with custom footers:
curl --output example.docx -X POST "https://api.tiptap.dev/v2/convert/export/docx" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-App-Id: YOUR_APP_ID" \
-H "Content-Type: application/json" \
-d '{
"doc": "{\"type\":\"doc\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Document with custom footers\"}]}]}",
"exportType": "blob",
"footers": {"evenAndOddFooters": true, "default": "Default Footer", "first": "First Page Footer", "even": "Even Page Footer"}
}'Element Overrides
The five element override objects let you tune how individual DOCX elements (tables, paragraphs, text runs, table cells, images) are rendered. Each override is forwarded to the underlying DOCX conversion library as a base default; per-node values from the document still win where they are computed.
No deep merging
Nested objects inside an override (for example borders, margins, transformation) are replaced entirely, not deep-merged. When customizing one side of a border, provide every side you need so undefined values do not slip through.
tableOverrides
Defaults applied to every table. Most useful properties:
| Property | Type | Description |
|---|---|---|
borders | Object | Per-side definitions for top, bottom, left, right, insideHorizontal, insideVertical. Each accepts { style, size, color }. |
margins | Object | Default cell margins { top, bottom, left, right } (twentieths of a point). |
width | Object | Table width { size, type } where type is "pct", "dxa", or "auto". |
layout | string | "fixed" or "autofit". |
alignment | string | "left" | "center" | "right" | "start" | "end". |
cantSplit | boolean | Prevent the table from splitting across pages. |
visuallyRightToLeft | boolean | Render the table right-to-left. |
paragraphOverrides
Defaults applied to every paragraph. Most useful properties:
| Property | Type | Description |
|---|---|---|
spacing | Object | { before, after, line, lineRule } in twentieths of a point. line is overwritten by computed line height. |
alignment | string | "left" | "center" | "right" | "justified" | "start" | "end". |
indent | Object | { left, right, firstLine, hanging, start, end } in twentieths of a point. |
keepNext | boolean | Keep this paragraph with the next one. |
keepLines | boolean | Keep all lines in the paragraph together. |
pageBreakBefore | boolean | Insert a page break before the paragraph. |
bidirectional | boolean | Render paragraph right-to-left. |
style | string | Reference to a paragraph style id defined in styleOverrides. |
textRunOverrides
Defaults applied to every text run. Per-mark formatting (bold, italic, color, …) still overrides these values. Most useful properties:
| Property | Type | Description |
|---|---|---|
font | string | Font family name. |
size | number | Font size in half-points (24 = 12pt). |
bold | boolean | Render bold by default. |
italics | boolean | Render italic by default. |
underline | Object | { type, color } — e.g. { type: "single", color: "auto" }. |
strike | boolean | Strikethrough. |
color | string | Hex color without the leading # ("FF0000"). |
highlight | string | Predefined highlight color name ("yellow", "green", …). |
superScript | boolean | Render as superscript. |
subScript | boolean | Render as subscript. |
tableCellOverrides
Defaults applied to every table cell. Most useful properties:
| Property | Type | Description |
|---|---|---|
shading | Object | { fill, type, color } — e.g. { fill: "F0F0F0", type: "clear" }. |
verticalAlign | string | "top" | "center" | "bottom". |
borders | Object | Per-side cell border definitions, same shape as tableOverrides.borders. |
margins | Object | Cell padding { top, bottom, left, right } in twentieths of a point. |
width | Object | Cell width { size, type }. |
imageOverrides
Defaults applied to every image. Image dimensions computed from the document (intrinsic size or user-resized values) still win where present. Most useful properties:
| Property | Type | Description |
|---|---|---|
transformation | Object | { width, height, rotation?, flip? } — pixels at 96 dpi. |
altText | Object | { title, description, name }. |
floating | Object | Floating positioning options (anchor, alignment, offset, wrap). |
Example cURL combining multiple element overrides
curl --output example.docx -X POST "https://api.tiptap.dev/v2/convert/export/docx" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-App-Id: YOUR_APP_ID" \
-H "Content-Type: application/json" \
-d '{
"doc": "{\"type\":\"doc\",\"content\":[{\"type\":\"paragraph\",\"content\":[{\"type\":\"text\",\"text\":\"Doc with element-level overrides\"}]}]}",
"tableOverrides": {
"borders": {
"top": { "style": "none" },
"bottom": { "style": "none" },
"left": { "style": "none" },
"right": { "style": "none" },
"insideHorizontal": { "style": "none" },
"insideVertical": { "style": "none" }
}
},
"paragraphOverrides": {
"spacing": { "before": 200, "after": 200 }
},
"textRunOverrides": {
"font": "Arial",
"size": 24
},
"tableCellOverrides": {
"shading": { "fill": "F0F0F0", "type": "clear" },
"verticalAlign": "center"
},
"imageOverrides": {
"transformation": { "width": 400, "height": 300 }
}
}'Response
On success the API returns the DOCX file as a binary download:
- Status:
200 OK - Content-Type:
application/vnd.openxmlformats-officedocument.wordprocessingml.document - Content-Disposition:
attachment; filename=export-{timestamp}.docx
Error responses
| Status | Code | Description |
|---|---|---|
| 400 | NO_DOCUMENT_PROVIDED | No document was provided in the body |
| 422 | FAILED_TO_PARSE_DOCX_FILE | Failed to parse JSON inputs |
| 422 | FAILED_TO_EXPORT_DOCX_FILE | Failed to export DOCX |
| 422 | FAILED_TO_CONVERT_DOCX_TO_BLOB | Failed to convert result type |
Convert a font
POST /v2/convert/fonts/convert
Converts a font into a form that can be embedded into a DOCX file: TTF / OTF uploads are returned unchanged, and WOFF2 uploads are converted to TTF. This is the endpoint the editor extension's embedFonts option calls behind the scenes; you can also call it directly. Available from Convert Service v2.25.0.
The endpoint is stateless — nothing is stored. Each request is converted and the temporary files are cleaned up immediately.
Required headers
Authorization: Bearer <your-jwt>
X-App-Id: <your-app-id>Body
multipart/form-data:
| Field | Type | Description | Required |
|---|---|---|---|
file | File | The font binary (TTF, OTF, or WOFF2). Max 25MB. | Yes |
fontFamily | String | Font family name, used for logging only. | No |
Example (cURL)
curl --output MyFont.ttf -X POST "https://api.tiptap.dev/v2/convert/fonts/convert" \
-H "Authorization: Bearer <your-jwt>" \
-H "X-App-Id: <your-app-id>" \
-F "file=@MyFont.woff2" \
-F "fontFamily=My Font"Response
On success the API returns the embeddable font as a binary download:
- Status:
200 OK - Content-Type:
font/ttf
Error responses
| Status | Code | Description |
|---|---|---|
| 400 | — | Request validation error (e.g. no file field) |
| 413 | FONT_FILE_TOO_LARGE | The uploaded font exceeds the 25MB limit |
| 422 | UNSUPPORTED_FONT_FORMAT | The upload is not a recognized TTF, OTF, or WOFF2 font |
| 422 | FONT_CONVERSION_FAILED | The WOFF2 → TTF conversion produced no output |
| 500 | FONT_CONVERSION_FAILED | Unexpected error during conversion |