DocX API

Why n8n can’t create formatted Google Docs (and how to fix it with one HTTP request)

Índice

If you’ve ever tried to generate a formatted document from an n8n workflow, you already know the pain. Your workflow collects data, processes it, maybe even runs it through an LLM — and then you need to put it into a Google Doc or Word file with proper headings, tables, and formatting.

And that’s where everything falls apart.

This is one of the most common frustrations in the n8n community. People build great automations and then hit a wall when they need a formatted document as output. I built DocxAPI to solve this. But first, let me walk through why the existing options don’t work.

The problem: n8n + Google Docs formatting is broken

The n8n Google Docs node can create documents and insert text. But it inserts plain text only. If you pass Markdown or HTML, it shows up as raw source code in the document. No headings, no bold, no tables — just a wall of unformatted text.

This isn’t a bug in n8n. It’s a limitation of how the Google Docs API works. The API requires you to send structured JSON requests for every formatting operation — one request to insert text, another to apply bold, another to set heading level, another to create a table. For a simple document with a heading, two paragraphs, and a table, you might need 20+ API calls, each with precise character offsets that break if anything shifts.

People on the n8n community forum have been asking about this for years:

  • “H1, H2, and H3 are not being formatted, and instead come out as plain text”
  • “When the HTML gets inserted into the Google Doc, it appears as plain text without any formatting”
  • “I’d like to take the content for a document and put it into a Google Doc with formatting. Can’t figure out how to do that with the docs/drive nodes.”

The workarounds people have tried:

1. Google Docs API with manual formatting requests

You can technically use the HTTP Request node to send batch update requests to the Google Docs API. You’d need to calculate character positions for every piece of text, then send separate updateParagraphStyle, updateTextStyle, and insertTable requests.

This works for static templates where you know the exact structure. It breaks the moment your content is dynamic — which is the whole point of automation.

2. Creating a Google Docs template and using find-and-replace

This is the most popular workaround. You create a Google Doc template with placeholders like {{name}} and {{amount}}, then use n8n to copy the template and replace the placeholders with real data.

It works for simple cases. But it can’t handle:

  • Dynamic tables (rows that change based on data)
  • Content generated by LLMs (variable length, variable structure)
  • Conditional sections (show/hide based on data)

3. HTML-to-Google-Docs conversion via Firebase/external service

Some people have built Firebase functions that convert Markdown to Google Docs format. These work but require you to set up and maintain your own cloud function, handle Google OAuth, and deal with the quirks of the Docs API formatting model.

4. Converting to .docx and uploading to Google Drive

This is actually the cleanest path. Google Drive automatically converts .docx files to Google Docs format when uploaded, and the formatting carries over correctly. The problem is: how do you generate a formatted .docx file from n8n in the first place?

The solution: generate a .docx and let Google Drive handle the rest

Instead of fighting the Google Docs API, skip it entirely. Generate a properly formatted .docx file and upload it to Google Drive. Drive converts it to Google Docs format automatically, and all your formatting — headings, tables, bold, lists, images — comes through perfectly.

DocxAPI does exactly this. It’s a REST API that takes Markdown, HTML, or structured JSON and returns a formatted .docx file. One HTTP request, one document.

Endpoint: POST https://api.searchops.io/v1/generate

The free tier gives you 50 documents per month, no credit card required.

How to set it up in n8n

Step 1: Get your API key

  1. Go to api.searchops.io/dashboard/login.html
  2. Sign in with Google
  3. Click “+ Create new API Key”
  4. Set a label (e.g., “My n8n instance”) and your n8n domain
  5. Copy the key (sk_live_...) — it’s only shown once

Step 2: Add the HTTP Request node

Add an HTTP Request node to your workflow with this configuration:

FieldValue
MethodPOST
URLhttps://api.searchops.io/v1/generate
Headerx-api-key: your sk_live_... key
Body typeJSON
ResponseFile

Step 3: Configure the request body

ParameterRequiredValuesDescription
inputYesmarkdown, html, jsonFormat of the content you’re sending
contentYesstringThe content to convert
formatNofile, base64, urlHow to receive the document (default: base64)

For n8n, use "format": "file" with the node’s response type set to File. This gives you a binary .docx that you can pass directly to a Google Drive node, Gmail node, or any other node that accepts file input.

Example: Markdown to .docx to Google Drive

Here’s the body for the HTTP Request node:

{
  "input": "markdown",
  "content": "# Monthly Report\n\n## Summary\n\nTotal revenue: **$62,250**\n\n| Month | Revenue |\n|-------|--------|\n| Jan | $21,000 |\n| Feb | $19,000 |\n| Mar | $22,250 |\n\n### Notes\n\n- Target met every month\n- **12%** growth vs previous quarter",
  "format": "file"
}

This generates a .docx with proper headings, a formatted table, bold text, and a bullet list. Connect the HTTP Request node to a Google Drive “Upload File” node, and you have a perfectly formatted Google Doc.

The workflow looks like this:

[Trigger] → [Process data] → [HTTP Request: DocxAPI] → [Google Drive: Upload] → [Done]

The key insight: Google Drive handles the .docx → Google Docs conversion perfectly. All the formatting that the Google Docs API can’t easily create? Drive imports it flawlessly from .docx.

Example: HTML to .docx

If your workflow already produces HTML (common with LLM outputs or template engines):

{
  "input": "html",
  "content": "<h1>Project Proposal</h1><p>Dear client,</p><p>Please find our proposal for the <strong>XYZ</strong> project.</p><table><tr><th>Item</th><th>Cost</th></tr><tr><td>Development</td><td>$15,000</td></tr><tr><td>Maintenance</td><td>$2,000/mo</td></tr></table>",
  "format": "file"
}

Tables, headings, bold — all rendered correctly in the output .docx.

Real workflow: LLM content → formatted Google Doc

This is probably the most common use case. You have an AI agent that generates content in Markdown, and you need it in a Google Doc for review.

[Trigger] → [AI Agent / LLM node] → [HTTP Request: DocxAPI] → [Google Drive: Upload] → [Gmail: Send link]

In the HTTP Request node, reference the LLM output dynamically:

{
  "input": "markdown",
  "content": "{{ $json.output }}",
  "format": "file"
}

The client gets a link to a formatted Google Doc they can comment on, suggest edits, and share — not a raw Markdown file they can’t open.

Quick test with cURL

Before building the full workflow, verify it works:

curl -X POST https://api.searchops.io/v1/generate \
  -H "Content-Type: application/json" \
  -H "x-api-key: sk_live_your_key_here" \
  -d '{"input":"markdown","content":"# Test\n\nIt works!\n\n| A | B |\n|---|---|\n| 1 | 2 |","format":"file"}' \
  --output test.docx

Open test.docx — if you see a formatted heading and table, you’re good to go.

Ready-to-paste n8n node

In the DocxAPI dashboard (api.searchops.io/dashboard), under Quick Start → n8n tab, there’s a “Copy ready-to-paste node” button. It copies the HTTP Request node JSON pre-configured with your API key. Paste it into your n8n canvas with Ctrl+V.

Pricing

PlanPriceDocs/month
Free$050
Starter$9/mo200
Pro$29/mo1,000
Agency$59/mo3,000

You can also buy credits on demand ($0.05/doc) without subscribing to a plan. All plans include all input formats and all formatting options.

Links

DocxAPI is built by SearchOps, a Brazilian agency specializing in SEO, automation, and developer tools.