Reference

API reference

The complete contract for POST /v1/generate, plus the supporting endpoints, error codes and limits.

Reading this with an AI agent?

The entire documentation lives in one Markdown file, built to be fetched and read by an LLM. Copy the prompt below and paste it into ChatGPT, Claude, Cursor or any agent with web access — it asks the agent to read the file before helping you.

Open the Markdown

https://api.searchops.io/doc/docxapi.md

POST /v1/generate

Base URL https://api.searchops.io. This is the only endpoint needed to generate documents.

Headers

HeaderRequiredValue
x-api-keyyesYour sk_live_… key. May also be sent as api_key in the body, but the header is preferred.
Content-Typeyesapplication/json

Body

FieldTypeDefaultNotes
contentstring—Required. Max 500 KB in UTF-8.
input_typemarkdown | html | jsonmarkdownAlias: input
response_formatbase64 | url | filebase64Alias: format
filenamestringdocument.docx1–120 chars, no /, \ or control characters. .docx appended if missing. Unicode supported.
optionsobject—Validated but currently ignored — see below.

Unknown fields are ignored, not rejected. A typo like file_name instead of filename does not fail the request — the field is dropped and the default is used, so you get document.docx with no error. When a value seems to have no effect, check the spelling against this table.

Responses

file returns raw bytes with these headers:

file response
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Content-Disposition: attachment; filename="report.docx"; filename*=UTF-8''report.docx
X-Generation-Time-Ms: 480

base64 and url return JSON:

url response
{
  "status": "success",
  "format": "url",
  "data": "https://api.searchops.io/v1/download/550e8400-e29b-41d4-a716-446655440000",
  "pages": null,
  "generation_time_ms": 480
}

pages is always null. Download links from url live for 24 hours.

Formatting options are not active

The API accepts and validates an options object — font, font_size, header_text, footer_text, page_size and the four margin_* fields — but it does not change the document yet. Styling comes from a fixed template (Roboto, A4).

When you send it, the API says so: JSON responses gain a warnings array, and file responses gain an X-DocxAPI-Warning header. Do not depend on these fields until this note is removed.

Error codes

error envelope
{ "error": { "code": "INVALID_API_KEY", "message": "Invalid or inactive API key." } }
HTTPcodeMeaningRetry?
400VALIDATION_ERRORBody failed schema validation — usually an unknown field or wrong enumNo
401INVALID_API_KEYMissing, wrong, inactive or deleted keyNo
402CREDITS_EXHAUSTEDMonthly quota used upNo
403DOMAIN_NOT_ALLOWEDRequest origin not on the key's allow-listNo
413CONTENT_TOO_LARGEcontent over 500 KBNo
413OUTPUT_TOO_LARGEGenerated file exceeded the output limitNo
429RATE_LIMIT_EXCEEDEDOver 60 requests/minute for this keyYes
500PANDOC_ERRORConversion failed — usually malformed JSON contentNo
422CONVERSION_ERRORContent could not be converted to block markup (Gutenberg). Not charged.No
503GENERATION_BUSYConversion queue is fullYes
503USAGE_SERVICE_ERRORQuota service temporarily unavailableYes
504GENERATION_TIMEOUTConversion exceeded 30 secondsReduce size first

Every response carries X-Request-Id. Include it when reporting a problem.

Plans and limits

PlanDocuments / monthOverageAPI keys
Free20—1
Starter200$0.051
Pro1,000$0.033
Agency3,000$0.02Unlimited
  • Only successful generations count against quota. Failed requests are logged, not charged.
  • The month is the calendar month in UTC.
  • Free plan documents carry a watermark line at the end.
  • Paid plans keep working past quota and are billed for overage.
  • Extra credits come in blocks of 50 (min 50, max 10,000) and are used after the plan quota.
Technical limitValue
Max content size500 KB
Conversion timeout30 seconds
Rate limit60 requests / minute per API key
Download link lifetime24 hours
Max request body10 MB

POST /v1/gutenberg/convert

Converts the same three input formats into WordPress block markup. Consumes one credit from the same balance as the DOCX endpoint.

Body

FieldTypeDefaultNotes
contentstring—Required. Max 500 KB.
input_formatmarkdown | html | jsonmarkdownAliases: input_type, input
profileportable-articleportable-articleCore blocks only, no theme or plugin dependencies
options.h1_policydemote | keep | removedemoteThe post title already renders as the page H1
options.unknown_node_policyhtml | drop | stricthtmlWhat to do with content that has no block mapping
options.return_astbooleanfalseInclude the canonical tree in the response

Response

FieldMeaning
gutenbergThe block markup. Goes straight into the WordPress content field.
blocksBlock types produced, e.g. core/heading.
validationsyntax and round_trip. Markup that fails either is never returned.
warningsContent that came through in a different shape.
lossesContent that did not come through at all.
serializerProfile, catalog date and API version used.

Conversion runs before the credit is reserved, so invalid input and failed round trips cost nothing. A 422 CONVERSION_ERROR is never charged.

POST /v1/gutenberg/parse

Takes block markup and returns its structure. Useful for diagnosing a post that is already broken. Requires an API key but does not consume credits. Malformed markup returns 400 INVALID_BLOCK_MARKUP with the specific reason.

Supporting endpoints

GET /v1/download/:id

Serves a file produced with response_format: "url". No authentication — the UUID is the capability, so treat the link as a secret. Returns 404 once the 24 hours elapse.

GET /health

No authentication. Useful for monitoring.

GET /health
{
  "status": "ok",
  "pandoc_available": true,
  "version": "3.1.3",
  "generation": { "active": 0, "queued": 0, "max_concurrency": 2, "max_queue": 50 }
}

Dashboard endpoints

The dashboard uses a session JWT rather than an API key: /v1/auth/me, /v1/auth/profile, /v1/keys (including /v1/keys/:id/rotate), /v1/usage and /v1/billing/*. You do not need any of them to generate documents.

Quick reference

cheatsheet
POST https://api.searchops.io/v1/generate
  header  x-api-key: sk_live_…
  body    { content, input_type?, response_format?, filename?, options? }

input_type       markdown | html | json      default markdown   (alias: input)
response_format  base64 | url | file         default base64     (alias: format)
filename         1–120 chars, .docx added    default document.docx
content          required, ≤ 500 KB

GET  /v1/download/:id     24h link from response_format=url
GET  /health              status + conversion queue