diff --git a/sdk/nodejs/README.md b/sdk/nodejs/README.md
new file mode 100644
index 0000000..61c7da5
--- /dev/null
+++ b/sdk/nodejs/README.md
@@ -0,0 +1,95 @@
+# DocFast Node.js SDK
+
+Official Node.js client for the [DocFast](https://docfast.dev) HTML-to-PDF API.
+
+## Install
+
+```bash
+npm install docfast
+```
+
+Requires Node.js 18+ (uses native `fetch`). Zero runtime dependencies.
+
+## Quick Start
+
+```typescript
+import DocFast from 'docfast';
+
+const client = new DocFast('df_pro_your_api_key');
+
+// HTML to PDF
+const pdf = await client.html('
Hello World
');
+fs.writeFileSync('output.pdf', pdf);
+
+// Markdown to PDF
+const pdf2 = await client.markdown('# Hello\n\nThis is **bold**.');
+fs.writeFileSync('doc.pdf', pdf2);
+
+// URL to PDF
+const pdf3 = await client.url('https://example.com');
+fs.writeFileSync('page.pdf', pdf3);
+```
+
+## API
+
+### `new DocFast(apiKey, options?)`
+
+| Parameter | Type | Description |
+|-----------|------|-------------|
+| `apiKey` | `string` | Your DocFast API key |
+| `options.baseUrl` | `string` | API base URL (default: `https://docfast.dev`) |
+
+### `client.html(html, options?)`
+
+Convert an HTML string to PDF. Returns `Promise`.
+
+### `client.markdown(markdown, options?)`
+
+Convert a Markdown string to PDF. Returns `Promise`.
+
+### `client.url(url, options?)`
+
+Convert a webpage URL to PDF. Returns `Promise`.
+
+### `client.templates()`
+
+List available templates. Returns `Promise`.
+
+### `client.renderTemplate(id, data, options?)`
+
+Render a template with data. Returns `Promise`.
+
+### PDF Options
+
+All conversion methods accept an optional `options` object:
+
+```typescript
+{
+ format: 'A4' | 'Letter' | 'Legal' | 'A3' | 'A5' | 'Tabloid',
+ landscape: boolean,
+ margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' },
+ header: { content: 'Header HTML
', height: '30mm' },
+ footer: { content: 'Footer HTML
', height: '20mm' },
+ scale: 1.0,
+ printBackground: true,
+}
+```
+
+## Error Handling
+
+```typescript
+import DocFast, { DocFastError } from 'docfast';
+
+try {
+ const pdf = await client.html('Test
');
+} catch (err) {
+ if (err instanceof DocFastError) {
+ console.error(err.message); // "Invalid API key"
+ console.error(err.status); // 403
+ }
+}
+```
+
+## License
+
+MIT
diff --git a/sdk/nodejs/package.json b/sdk/nodejs/package.json
new file mode 100644
index 0000000..4c5eb9c
--- /dev/null
+++ b/sdk/nodejs/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "docfast",
+ "version": "0.1.0",
+ "description": "Official Node.js client for the DocFast HTML-to-PDF API",
+ "main": "dist/index.js",
+ "types": "dist/index.d.ts",
+ "files": ["dist"],
+ "engines": { "node": ">=18.0.0" },
+ "scripts": {
+ "build": "tsc",
+ "prepublishOnly": "npm run build"
+ },
+ "keywords": ["pdf", "html-to-pdf", "markdown-to-pdf", "docfast", "api", "document"],
+ "author": "DocFast ",
+ "license": "MIT",
+ "homepage": "https://docfast.dev",
+ "repository": {
+ "type": "git",
+ "url": "https://git.cloonar.com/openclawd/docfast"
+ },
+ "devDependencies": {
+ "typescript": "^5.0.0"
+ }
+}
diff --git a/sdk/nodejs/src/index.ts b/sdk/nodejs/src/index.ts
new file mode 100644
index 0000000..5b2fd8d
--- /dev/null
+++ b/sdk/nodejs/src/index.ts
@@ -0,0 +1,129 @@
+/**
+ * DocFast — Official Node.js SDK
+ * https://docfast.dev
+ */
+
+export interface PdfMargin {
+ top?: string;
+ bottom?: string;
+ left?: string;
+ right?: string;
+}
+
+export interface HeaderFooter {
+ content?: string;
+ height?: string;
+}
+
+export interface PdfOptions {
+ format?: 'A4' | 'Letter' | 'Legal' | 'A3' | 'A5' | 'Tabloid';
+ landscape?: boolean;
+ margin?: PdfMargin;
+ header?: HeaderFooter;
+ footer?: HeaderFooter;
+ scale?: number;
+ printBackground?: boolean;
+}
+
+export interface Template {
+ id: string;
+ name: string;
+ description?: string;
+}
+
+export interface DocFastOptions {
+ baseUrl?: string;
+}
+
+export class DocFastError extends Error {
+ readonly status: number;
+ readonly code?: string;
+
+ constructor(message: string, status: number, code?: string) {
+ super(message);
+ this.name = 'DocFastError';
+ this.status = status;
+ this.code = code;
+ }
+}
+
+export class DocFast {
+ private readonly apiKey: string;
+ private readonly baseUrl: string;
+
+ constructor(apiKey: string, options?: DocFastOptions) {
+ if (!apiKey) throw new Error('API key is required');
+ this.apiKey = apiKey;
+ this.baseUrl = options?.baseUrl?.replace(/\/+$/, '') ?? 'https://docfast.dev';
+ }
+
+ private async request(path: string, body: Record): Promise {
+ const res = await fetch(`${this.baseUrl}${path}`, {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Bearer ${this.apiKey}`,
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(body),
+ });
+
+ if (!res.ok) {
+ let message = `HTTP ${res.status}`;
+ let code: string | undefined;
+ try {
+ const err = await res.json() as { error?: string; code?: string };
+ if (err.error) message = err.error;
+ code = err.code;
+ } catch {}
+ throw new DocFastError(message, res.status, code);
+ }
+
+ const arrayBuffer = await res.arrayBuffer();
+ return Buffer.from(arrayBuffer);
+ }
+
+ private async requestJson(method: string, path: string): Promise {
+ const res = await fetch(`${this.baseUrl}${path}`, {
+ method,
+ headers: { 'Authorization': `Bearer ${this.apiKey}` },
+ });
+
+ if (!res.ok) {
+ let message = `HTTP ${res.status}`;
+ try {
+ const err = await res.json() as { error?: string };
+ if (err.error) message = err.error;
+ } catch {}
+ throw new DocFastError(message, res.status);
+ }
+
+ return res.json() as Promise;
+ }
+
+ /** Convert HTML to PDF */
+ async html(html: string, options?: PdfOptions): Promise {
+ return this.request('/v1/convert/html', { html, options });
+ }
+
+ /** Convert Markdown to PDF */
+ async markdown(markdown: string, options?: PdfOptions): Promise {
+ return this.request('/v1/convert/markdown', { markdown, options });
+ }
+
+ /** Convert a URL to PDF */
+ async url(url: string, options?: PdfOptions): Promise {
+ return this.request('/v1/convert/url', { url, options });
+ }
+
+ /** List available templates */
+ async templates(): Promise {
+ return this.requestJson('GET', '/v1/templates');
+ }
+
+ /** Render a template to PDF */
+ async renderTemplate(id: string, data: Record, options?: PdfOptions): Promise {
+ return this.request(`/v1/templates/${encodeURIComponent(id)}/render`, { data, options });
+ }
+}
+
+export default DocFast;
diff --git a/sdk/nodejs/tsconfig.json b/sdk/nodejs/tsconfig.json
new file mode 100644
index 0000000..84f8181
--- /dev/null
+++ b/sdk/nodejs/tsconfig.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "module": "Node16",
+ "moduleResolution": "Node16",
+ "lib": ["ES2022"],
+ "outDir": "dist",
+ "rootDir": "src",
+ "declaration": true,
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true
+ },
+ "include": ["src"]
+}
diff --git a/sdk/python/README.md b/sdk/python/README.md
new file mode 100644
index 0000000..2bc9635
--- /dev/null
+++ b/sdk/python/README.md
@@ -0,0 +1,103 @@
+# DocFast Python SDK
+
+Official Python client for the [DocFast](https://docfast.dev) HTML-to-PDF API.
+
+## Install
+
+```bash
+pip install docfast
+```
+
+Requires Python 3.8+.
+
+## Quick Start
+
+```python
+from docfast import DocFast
+
+client = DocFast("df_pro_your_api_key")
+
+# HTML to PDF
+pdf = client.html("Hello World
")
+with open("output.pdf", "wb") as f:
+ f.write(pdf)
+
+# Markdown to PDF
+pdf = client.markdown("# Hello\n\nThis is **bold**.")
+
+# URL to PDF
+pdf = client.url("https://example.com")
+```
+
+## Async Usage
+
+```python
+from docfast import AsyncDocFast
+
+async with AsyncDocFast("df_pro_your_api_key") as client:
+ pdf = await client.html("Hello
")
+```
+
+## API
+
+### `DocFast(api_key, *, base_url=None)`
+
+Create a synchronous client. Use as a context manager or call `client.close()`.
+
+### `AsyncDocFast(api_key, *, base_url=None)`
+
+Create an async client. Use as an async context manager.
+
+### Conversion Methods
+
+All methods return PDF bytes and accept optional keyword arguments:
+
+| Method | Input | Description |
+|--------|-------|-------------|
+| `client.html(html, **opts)` | HTML string | Convert HTML to PDF |
+| `client.markdown(markdown, **opts)` | Markdown string | Convert Markdown to PDF |
+| `client.url(url, **opts)` | URL string | Convert webpage to PDF |
+| `client.templates()` | — | List available templates |
+| `client.render_template(id, data, **opts)` | Template ID + data dict | Render template to PDF |
+
+### PDF Options
+
+Pass as keyword arguments to any conversion method:
+
+```python
+pdf = client.html(
+ "Report
",
+ format="A4",
+ landscape=True,
+ margin={"top": "20mm", "bottom": "20mm"},
+ print_background=True,
+)
+```
+
+| Option | Type | Default | Description |
+|--------|------|---------|-------------|
+| `format` | str | `"A4"` | Page size: A4, Letter, Legal, A3, A5, Tabloid |
+| `landscape` | bool | `False` | Landscape orientation |
+| `margin` | dict | — | `{top, bottom, left, right}` in CSS units |
+| `header` | dict | — | `{content, height}` for page header |
+| `footer` | dict | — | `{content, height}` for page footer |
+| `scale` | float | `1.0` | Render scale |
+| `print_background` | bool | `False` | Include background colors/images |
+
+## Error Handling
+
+```python
+from docfast import DocFast, DocFastError
+
+client = DocFast("df_pro_your_api_key")
+
+try:
+ pdf = client.html("Test
")
+except DocFastError as e:
+ print(e) # "Invalid API key"
+ print(e.status) # 403
+```
+
+## License
+
+MIT
diff --git a/sdk/python/docfast/__init__.py b/sdk/python/docfast/__init__.py
new file mode 100644
index 0000000..db58c10
--- /dev/null
+++ b/sdk/python/docfast/__init__.py
@@ -0,0 +1,6 @@
+"""DocFast — Official Python SDK for the HTML-to-PDF API."""
+
+from .client import DocFast, AsyncDocFast, DocFastError
+
+__all__ = ["DocFast", "AsyncDocFast", "DocFastError"]
+__version__ = "0.1.0"
diff --git a/sdk/python/docfast/client.py b/sdk/python/docfast/client.py
new file mode 100644
index 0000000..6a12cf8
--- /dev/null
+++ b/sdk/python/docfast/client.py
@@ -0,0 +1,148 @@
+"""DocFast API clients (sync and async)."""
+
+from __future__ import annotations
+
+from typing import Any, Dict, List, Optional
+from urllib.parse import quote
+
+import httpx
+
+
+class DocFastError(Exception):
+ """Error returned by the DocFast API."""
+
+ def __init__(self, message: str, status: int, code: Optional[str] = None):
+ super().__init__(message)
+ self.status = status
+ self.code = code
+
+
+_KEY_MAP = {"print_background": "printBackground"}
+
+
+def _build_body(key: str, value: str, options: Optional[Dict[str, Any]]) -> Dict[str, Any]:
+ body: Dict[str, Any] = {key: value}
+ if options:
+ body["options"] = {_KEY_MAP.get(k, k): v for k, v in options.items()}
+ return body
+
+
+def _handle_error(response: httpx.Response) -> None:
+ if response.is_success:
+ return
+ message = f"HTTP {response.status_code}"
+ code = None
+ try:
+ data = response.json()
+ if "error" in data:
+ message = data["error"]
+ code = data.get("code")
+ except Exception:
+ pass
+ raise DocFastError(message, response.status_code, code)
+
+
+class DocFast:
+ """Synchronous DocFast client."""
+
+ def __init__(self, api_key: str, *, base_url: Optional[str] = None):
+ if not api_key:
+ raise ValueError("API key is required")
+ self._base_url = (base_url or "https://docfast.dev").rstrip("/")
+ self._client = httpx.Client(
+ base_url=self._base_url,
+ headers={"Authorization": f"Bearer {api_key}"},
+ timeout=120.0,
+ )
+
+ def __enter__(self) -> "DocFast":
+ return self
+
+ def __exit__(self, *args: Any) -> None:
+ self.close()
+
+ def close(self) -> None:
+ self._client.close()
+
+ def _convert(self, path: str, body: Dict[str, Any]) -> bytes:
+ r = self._client.post(path, json=body)
+ _handle_error(r)
+ return r.content
+
+ def html(self, html: str, **options: Any) -> bytes:
+ """Convert HTML to PDF."""
+ return self._convert("/v1/convert/html", _build_body("html", html, options or None))
+
+ def markdown(self, markdown: str, **options: Any) -> bytes:
+ """Convert Markdown to PDF."""
+ return self._convert("/v1/convert/markdown", _build_body("markdown", markdown, options or None))
+
+ def url(self, url: str, **options: Any) -> bytes:
+ """Convert a URL to PDF."""
+ return self._convert("/v1/convert/url", _build_body("url", url, options or None))
+
+ def templates(self) -> List[Dict[str, Any]]:
+ """List available templates."""
+ r = self._client.get("/v1/templates")
+ _handle_error(r)
+ return r.json()
+
+ def render_template(self, template_id: str, data: Dict[str, Any], **options: Any) -> bytes:
+ """Render a template to PDF."""
+ body: Dict[str, Any] = {"data": data}
+ if options:
+ body["options"] = options
+ return self._convert(f"/v1/templates/{quote(template_id, safe='')}/render", body)
+
+
+class AsyncDocFast:
+ """Asynchronous DocFast client."""
+
+ def __init__(self, api_key: str, *, base_url: Optional[str] = None):
+ if not api_key:
+ raise ValueError("API key is required")
+ self._base_url = (base_url or "https://docfast.dev").rstrip("/")
+ self._client = httpx.AsyncClient(
+ base_url=self._base_url,
+ headers={"Authorization": f"Bearer {api_key}"},
+ timeout=120.0,
+ )
+
+ async def __aenter__(self) -> "AsyncDocFast":
+ return self
+
+ async def __aexit__(self, *args: Any) -> None:
+ await self.close()
+
+ async def close(self) -> None:
+ await self._client.aclose()
+
+ async def _convert(self, path: str, body: Dict[str, Any]) -> bytes:
+ r = await self._client.post(path, json=body)
+ _handle_error(r)
+ return r.content
+
+ async def html(self, html: str, **options: Any) -> bytes:
+ """Convert HTML to PDF."""
+ return await self._convert("/v1/convert/html", _build_body("html", html, options or None))
+
+ async def markdown(self, markdown: str, **options: Any) -> bytes:
+ """Convert Markdown to PDF."""
+ return await self._convert("/v1/convert/markdown", _build_body("markdown", markdown, options or None))
+
+ async def url(self, url: str, **options: Any) -> bytes:
+ """Convert a URL to PDF."""
+ return await self._convert("/v1/convert/url", _build_body("url", url, options or None))
+
+ async def templates(self) -> List[Dict[str, Any]]:
+ """List available templates."""
+ r = await self._client.get("/v1/templates")
+ _handle_error(r)
+ return r.json()
+
+ async def render_template(self, template_id: str, data: Dict[str, Any], **options: Any) -> bytes:
+ """Render a template to PDF."""
+ body: Dict[str, Any] = {"data": data}
+ if options:
+ body["options"] = options
+ return await self._convert(f"/v1/templates/{quote(template_id, safe='')}/render", body)
diff --git a/sdk/python/docfast/py.typed b/sdk/python/docfast/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml
new file mode 100644
index 0000000..9e7f4ae
--- /dev/null
+++ b/sdk/python/pyproject.toml
@@ -0,0 +1,26 @@
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[project]
+name = "docfast"
+version = "0.1.0"
+description = "Official Python client for the DocFast HTML-to-PDF API"
+readme = "README.md"
+license = "MIT"
+requires-python = ">=3.8"
+authors = [{ name = "DocFast", email = "support@docfast.dev" }]
+keywords = ["pdf", "html-to-pdf", "markdown-to-pdf", "docfast", "api"]
+classifiers = [
+ "Development Status :: 4 - Beta",
+ "Intended Audience :: Developers",
+ "License :: OSI Approved :: MIT License",
+ "Programming Language :: Python :: 3",
+ "Topic :: Software Development :: Libraries",
+]
+dependencies = ["httpx>=0.24.0"]
+
+[project.urls]
+Homepage = "https://docfast.dev"
+Documentation = "https://docfast.dev/docs"
+Repository = "https://git.cloonar.com/openclawd/docfast"