docfast/public/openapi.json
OpenClaw 59cc8f3d0e
All checks were successful
Deploy to Production / Deploy to Server (push) Successful in 2m20s
Session 45: support email, audit fixes (template validation, content-type, admin auth, waitUntil)
- Added support@docfast.dev to footer, impressum, terms, landing page, openapi.json
- Fixed audit #6: Template render validates required fields (400 on missing)
- Fixed audit #7: Content-Type check on markdown/URL routes (415)
- Fixed audit #11: /v1/usage and /v1/concurrency now require ADMIN_API_KEY
- Fixed audit Critical #3: URL convert uses domcontentloaded instead of networkidle0
2026-02-16 19:30:21 +00:00

422 lines
17 KiB
JSON

{
"openapi": "3.0.3",
"info": {
"title": "DocFast API",
"version": "1.0.0",
"description": "Convert HTML, Markdown, and URLs to pixel-perfect PDFs. Built-in invoice & receipt templates.\n\n## Authentication\nAll conversion and template endpoints require an API key via `Authorization: Bearer <key>` or `X-API-Key: <key>` header.\n\n## Rate Limits\n- Free tier: 100 PDFs/month, 10 req/min\n- Pro tier: 10,000 PDFs/month, 30 req/min\n\n## Getting Started\n1. Sign up at [docfast.dev](https://docfast.dev) or via `POST /v1/signup/free`\n2. Verify your email with the 6-digit code\n3. Use your API key to convert documents",
"contact": { "name": "DocFast", "url": "https://docfast.dev", "email": "support@docfast.dev" }
},
"servers": [{ "url": "https://docfast.dev", "description": "Production" }],
"tags": [
{ "name": "Conversion", "description": "Convert HTML, Markdown, or URLs to PDF" },
{ "name": "Templates", "description": "Built-in document templates" },
{ "name": "Account", "description": "Signup, key recovery, and email management" },
{ "name": "Billing", "description": "Stripe-powered subscription management" },
{ "name": "System", "description": "Health checks and usage stats" }
],
"components": {
"securitySchemes": {
"BearerAuth": { "type": "http", "scheme": "bearer", "description": "API key as Bearer token" },
"ApiKeyHeader": { "type": "apiKey", "in": "header", "name": "X-API-Key", "description": "API key via X-API-Key header" }
},
"schemas": {
"PdfOptions": {
"type": "object",
"properties": {
"format": { "type": "string", "enum": ["A4", "Letter", "Legal", "A3", "A5", "Tabloid"], "default": "A4", "description": "Page size" },
"landscape": { "type": "boolean", "default": false, "description": "Landscape orientation" },
"margin": {
"type": "object",
"properties": {
"top": { "type": "string", "example": "20mm" },
"bottom": { "type": "string", "example": "20mm" },
"left": { "type": "string", "example": "15mm" },
"right": { "type": "string", "example": "15mm" }
}
},
"printBackground": { "type": "boolean", "default": true, "description": "Print background graphics" },
"filename": { "type": "string", "default": "document.pdf", "description": "Suggested filename for the PDF" }
}
},
"Error": {
"type": "object",
"properties": {
"error": { "type": "string", "description": "Error message" }
}
}
}
},
"paths": {
"/v1/convert/html": {
"post": {
"tags": ["Conversion"],
"summary": "Convert HTML to PDF",
"description": "Renders HTML content as a PDF. Supports full CSS including flexbox, grid, and custom fonts. Bare HTML fragments are auto-wrapped.",
"security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"allOf": [
{
"type": "object",
"required": ["html"],
"properties": {
"html": { "type": "string", "description": "HTML content to convert", "example": "<h1>Hello World</h1><p>Your first PDF</p>" },
"css": { "type": "string", "description": "Optional CSS to inject (for HTML fragments)" }
}
},
{ "$ref": "#/components/schemas/PdfOptions" }
]
}
}
}
},
"responses": {
"200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
"400": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
"401": { "description": "Missing or invalid API key" },
"415": { "description": "Unsupported Content-Type" },
"429": { "description": "Rate limit exceeded or server busy" }
}
}
},
"/v1/convert/markdown": {
"post": {
"tags": ["Conversion"],
"summary": "Convert Markdown to PDF",
"description": "Converts Markdown content to a beautifully styled PDF with syntax highlighting.",
"security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"allOf": [
{
"type": "object",
"required": ["markdown"],
"properties": {
"markdown": { "type": "string", "description": "Markdown content to convert", "example": "# Hello World\n\nThis is **bold** and this is *italic*.\n\n- Item 1\n- Item 2" },
"css": { "type": "string", "description": "Optional custom CSS" }
}
},
{ "$ref": "#/components/schemas/PdfOptions" }
]
}
}
}
},
"responses": {
"200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
"400": { "description": "Invalid request" },
"401": { "description": "Missing or invalid API key" },
"429": { "description": "Rate limit exceeded" }
}
}
},
"/v1/convert/url": {
"post": {
"tags": ["Conversion"],
"summary": "Convert URL to PDF",
"description": "Fetches a URL and converts the rendered page to PDF. Only http/https URLs are supported. Private/reserved IPs are blocked (SSRF protection).",
"security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"allOf": [
{
"type": "object",
"required": ["url"],
"properties": {
"url": { "type": "string", "format": "uri", "description": "URL to convert", "example": "https://example.com" },
"waitUntil": { "type": "string", "enum": ["load", "domcontentloaded", "networkidle0", "networkidle2"], "default": "networkidle0", "description": "When to consider navigation complete" }
}
},
{ "$ref": "#/components/schemas/PdfOptions" }
]
}
}
}
},
"responses": {
"200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
"400": { "description": "Invalid URL or DNS failure" },
"401": { "description": "Missing or invalid API key" },
"429": { "description": "Rate limit exceeded" }
}
}
},
"/v1/templates": {
"get": {
"tags": ["Templates"],
"summary": "List available templates",
"description": "Returns all available document templates with their field definitions.",
"security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
"responses": {
"200": {
"description": "Template list",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"templates": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string", "example": "invoice" },
"name": { "type": "string", "example": "Invoice" },
"description": { "type": "string" },
"fields": { "type": "array", "items": { "type": "string" } }
}
}
}
}
}
}
}
}
}
}
},
"/v1/templates/{id}/render": {
"post": {
"tags": ["Templates"],
"summary": "Render a template to PDF",
"description": "Renders a template with the provided data and returns a PDF.",
"security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
"parameters": [
{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Template ID (e.g., 'invoice', 'receipt')" }
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": { "type": "object", "description": "Template data fields", "example": { "company": "Acme Corp", "items": [{ "description": "Widget", "quantity": 5, "price": 9.99 }] } }
}
}
}
}
},
"responses": {
"200": { "description": "PDF file", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
"404": { "description": "Template not found" }
}
}
},
"/v1/signup/free": {
"post": {
"tags": ["Account"],
"summary": "Request a free API key",
"description": "Sends a 6-digit verification code to your email. Use `/v1/signup/verify` to complete signup.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["email"],
"properties": {
"email": { "type": "string", "format": "email", "example": "you@example.com" }
}
}
}
}
},
"responses": {
"200": {
"description": "Verification code sent",
"content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "verification_required" }, "message": { "type": "string" } } } } }
},
"409": { "description": "Email already registered" },
"429": { "description": "Too many signup attempts" }
}
}
},
"/v1/signup/verify": {
"post": {
"tags": ["Account"],
"summary": "Verify email and get API key",
"description": "Verify your email with the 6-digit code to receive your API key.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["email", "code"],
"properties": {
"email": { "type": "string", "format": "email" },
"code": { "type": "string", "example": "123456", "description": "6-digit verification code" }
}
}
}
}
},
"responses": {
"200": {
"description": "API key issued",
"content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "verified" }, "apiKey": { "type": "string", "example": "df_free_abc123..." }, "tier": { "type": "string", "example": "free" } } } } }
},
"400": { "description": "Invalid code" },
"410": { "description": "Code expired" },
"429": { "description": "Too many attempts" }
}
}
},
"/v1/recover": {
"post": {
"tags": ["Account"],
"summary": "Request API key recovery",
"description": "Sends a verification code to your registered email. Returns the same response whether or not the email exists (prevents enumeration).",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["email"],
"properties": {
"email": { "type": "string", "format": "email" }
}
}
}
}
},
"responses": {
"200": { "description": "Recovery code sent (if account exists)" },
"429": { "description": "Too many recovery attempts" }
}
}
},
"/v1/recover/verify": {
"post": {
"tags": ["Account"],
"summary": "Verify recovery code and get API key",
"description": "Verify the recovery code to retrieve your API key. The key is shown only in the response — never sent via email.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["email", "code"],
"properties": {
"email": { "type": "string", "format": "email" },
"code": { "type": "string", "example": "123456" }
}
}
}
}
},
"responses": {
"200": {
"description": "API key recovered",
"content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "recovered" }, "apiKey": { "type": "string" }, "tier": { "type": "string" } } } } }
},
"400": { "description": "Invalid code" },
"410": { "description": "Code expired" },
"429": { "description": "Too many attempts" }
}
}
},
"/v1/email-change": {
"post": {
"tags": ["Account"],
"summary": "Request email change",
"description": "Change the email associated with your API key. Sends a verification code to the new email address.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["apiKey", "newEmail"],
"properties": {
"apiKey": { "type": "string", "description": "Your current API key" },
"newEmail": { "type": "string", "format": "email", "description": "New email address" }
}
}
}
}
},
"responses": {
"200": { "description": "Verification code sent to new email" },
"400": { "description": "Invalid input" },
"401": { "description": "Invalid API key" },
"409": { "description": "Email already in use" },
"429": { "description": "Too many attempts" }
}
}
},
"/v1/email-change/verify": {
"post": {
"tags": ["Account"],
"summary": "Verify email change",
"description": "Verify the code sent to your new email to complete the change.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["apiKey", "newEmail", "code"],
"properties": {
"apiKey": { "type": "string" },
"newEmail": { "type": "string", "format": "email" },
"code": { "type": "string", "example": "123456" }
}
}
}
}
},
"responses": {
"200": { "description": "Email updated", "content": { "application/json": { "schema": { "type": "object", "properties": { "status": { "type": "string", "example": "updated" }, "newEmail": { "type": "string" } } } } } },
"400": { "description": "Invalid code" },
"401": { "description": "Invalid API key" },
"410": { "description": "Code expired" }
}
}
},
"/v1/billing/checkout": {
"post": {
"tags": ["Billing"],
"summary": "Start Pro subscription checkout",
"description": "Creates a Stripe Checkout session for the Pro plan ($9/mo). Returns a URL to redirect the user to.",
"responses": {
"200": { "description": "Checkout URL", "content": { "application/json": { "schema": { "type": "object", "properties": { "url": { "type": "string", "format": "uri" } } } } } },
"500": { "description": "Checkout creation failed" }
}
}
},
"/v1/usage": {
"get": {
"tags": ["System"],
"summary": "Get usage statistics",
"description": "Returns your API usage statistics for the current billing period.",
"security": [{ "BearerAuth": [] }, { "ApiKeyHeader": [] }],
"responses": {
"200": { "description": "Usage stats" }
}
}
},
"/health": {
"get": {
"tags": ["System"],
"summary": "Health check",
"description": "Returns service health status. No authentication required.",
"responses": {
"200": { "description": "Service is healthy" }
}
}
}
}
}