"""API documentation routes for AgentForms.
Serves the interactive API documentation page at /api/docs.
"""
import json
import os
from flask import Blueprint, jsonify, render_template, request
APP_URL = os.environ.get("APP_URL", "https://agentforms.io")
api_docs_bp = Blueprint("api_docs", __name__, url_prefix="/api/docs")
@api_docs_bp.route("/")
def docs_index():
"""GET /api/docs/ — API documentation page."""
return render_template("api_docs.html")
@api_docs_bp.route("/openapi.json")
def openapi_spec():
"""GET /api/docs/openapi.json — OpenAPI 3.0 specification."""
spec = {
"openapi": "3.0.3",
"info": {
"title": "AgentForms API",
"description": "RESTful API for building, managing, and embedding forms. Submit data, retrieve submissions, manage forms, email templates, and campaigns.",
"version": "2.0.0",
"contact": {
"name": "AgentForms Support",
"url": f"{APP_URL}/support",
"email": "agentforms@protonmail.com",
},
},
"servers": [
{"url": APP_URL, "description": "Production"},
{"url": "http://localhost:5060", "description": "Local Development"},
],
"components": {
"securitySchemes": {
"ApiKeyAuth": {
"type": "apiKey",
"in": "header",
"name": "Authorization",
},
"BearerAuth": {"type": "http", "scheme": "bearer"},
}
},
"paths": {
"/api/submit": {
"post": {
"summary": "Submit form data (public)",
"tags": ["Submissions"],
"parameters": [
{
"name": "token",
"in": "query",
"required": True,
"schema": {"type": "string"},
"description": "Form token",
}
],
"requestBody": {
"required": True,
"content": {"application/json": {"schema": {"type": "object", "additionalProperties": True}}},
},
"responses": {
"200": {"description": "Submission created"},
"400": {"description": "Validation error"},
},
}
},
"/api/v2/forms": {
"get": {
"summary": "List forms",
"tags": ["Forms"],
"security": [{"ApiKeyAuth": []}],
"responses": {"200": {"description": "List of forms"}, "401": {"description": "Unauthorized"}},
},
"post": {
"summary": "Create form",
"tags": ["Forms"],
"security": [{"ApiKeyAuth": []}],
"responses": {"201": {"description": "Form created"}, "401": {"description": "Unauthorized"}},
},
},
"/api/v2/forms/{formToken}": {
"get": {
"summary": "Get form details",
"tags": ["Forms"],
"security": [{"ApiKeyAuth": []}],
"parameters": [{"name": "formToken", "in": "path", "required": True, "schema": {"type": "string"}}],
"responses": {"200": {"description": "Form data"}, "404": {"description": "Not found"}},
}
},
"/api/v2/forms/{formToken}/config": {
"get": {
"summary": "Get form configuration",
"tags": ["Forms"],
"security": [{"ApiKeyAuth": []}],
"parameters": [{"name": "formToken", "in": "path", "required": True, "schema": {"type": "string"}}],
"responses": {"200": {"description": "Form config"}, "401": {"description": "Unauthorized"}},
}
},
"/api/v2/forms/{formToken}/submissions": {
"get": {
"summary": "List submissions",
"tags": ["Submissions"],
"security": [{"ApiKeyAuth": []}],
"parameters": [
{"name": "formToken", "in": "path", "required": True, "schema": {"type": "string"}},
{"name": "limit", "in": "query", "schema": {"type": "integer", "default": 50}},
{"name": "offset", "in": "query", "schema": {"type": "integer", "default": 0}},
],
"responses": {
"200": {"description": "List of submissions"},
"401": {"description": "Unauthorized"},
},
}
},
"/api/v2/forms/{formToken}/submissions/{subId}": {
"get": {
"summary": "Get submission",
"tags": ["Submissions"],
"security": [{"ApiKeyAuth": []}],
"parameters": [
{"name": "formToken", "in": "path", "required": True, "schema": {"type": "string"}},
{"name": "subId", "in": "path", "required": True, "schema": {"type": "integer"}},
],
"responses": {"200": {"description": "Submission data"}, "404": {"description": "Not found"}},
}
},
"/api/v2/forms/{formToken}/analytics": {
"get": {
"summary": "Form analytics",
"tags": ["Analytics"],
"security": [{"ApiKeyAuth": []}],
"parameters": [{"name": "formToken", "in": "path", "required": True, "schema": {"type": "string"}}],
"responses": {"200": {"description": "Analytics data"}, "401": {"description": "Unauthorized"}},
}
},
"/api/v2/forms/{formToken}/fields": {
"put": {
"summary": "Update form fields",
"tags": ["Forms"],
"security": [{"ApiKeyAuth": []}],
"parameters": [{"name": "formToken", "in": "path", "required": True, "schema": {"type": "string"}}],
"responses": {"200": {"description": "Fields updated"}, "401": {"description": "Unauthorized"}},
}
},
"/api/v2/templates": {
"get": {
"summary": "List templates",
"tags": ["Templates"],
"security": [{"ApiKeyAuth": []}],
"responses": {"200": {"description": "List of templates"}, "401": {"description": "Unauthorized"}},
},
"post": {
"summary": "Create template",
"tags": ["Templates"],
"security": [{"ApiKeyAuth": []}],
"responses": {"201": {"description": "Template created"}, "401": {"description": "Unauthorized"}},
},
},
"/api/v2/templates/render": {
"post": {
"summary": "Render template",
"tags": ["Templates"],
"security": [{"ApiKeyAuth": []}],
"responses": {"200": {"description": "Rendered template"}, "401": {"description": "Unauthorized"}},
}
},
"/api/v2/email/send": {
"post": {
"summary": "Send email",
"tags": ["Email"],
"security": [{"ApiKeyAuth": []}],
"responses": {"200": {"description": "Email sent"}, "401": {"description": "Unauthorized"}},
}
},
"/api/v2/campaigns": {
"get": {
"summary": "List campaigns",
"tags": ["Campaigns"],
"security": [{"ApiKeyAuth": []}],
"responses": {"200": {"description": "List of campaigns"}, "401": {"description": "Unauthorized"}},
},
"post": {
"summary": "Create campaign",
"tags": ["Campaigns"],
"security": [{"ApiKeyAuth": []}],
"responses": {"201": {"description": "Campaign created"}, "401": {"description": "Unauthorized"}},
},
},
"/api/v2/keys": {
"get": {
"summary": "List API keys",
"tags": ["Keys"],
"security": [{"ApiKeyAuth": []}],
"responses": {"200": {"description": "List of API keys"}, "401": {"description": "Unauthorized"}},
},
"post": {
"summary": "Create API key",
"tags": ["Keys"],
"security": [{"ApiKeyAuth": []}],
"responses": {"201": {"description": "Key created"}, "401": {"description": "Unauthorized"}},
},
},
"/health": {
"get": {
"summary": "Health check",
"tags": ["System"],
"responses": {"200": {"description": "Service healthy"}},
}
},
"/health/ready": {
"get": {
"summary": "Readiness check",
"tags": ["System"],
"responses": {"200": {"description": "Service ready"}},
}
},
},
}
return jsonify(spec)
@api_docs_bp.route("/try", methods=["POST"])
def try_endpoint():
"""POST /api/docs/try — Test API endpoint."""
data = request.get_json()
if not data:
return jsonify({"error": "Request body required"}), 400
endpoint = data.get("endpoint")
method = data.get("method", "GET")
return jsonify(
{
"message": "This is a test endpoint. In production, you would test actual API calls here.",
"endpoint": endpoint,
"method": method,
}
)