{
  "openapi": "3.1.0",
  "info": {
    "title": "SHAART Agency public API",
    "version": "1.0.0",
    "description": "Read-only public API. JSON endpoints under /api/v1 expose pricing, capabilities, contact options and blog posts. Any public page can also be fetched as Markdown with Accept: text/markdown or a .md suffix. No authentication. Errors use RFC 9457 application/problem+json with a stable `code`. Versioning: the major version is in the path (/api/v1); breaking changes ship as /api/v2 and v1 stays available for at least 6 months after that. Deprecation: before v1 is retired its responses carry Deprecation (RFC 9745) and Sunset (RFC 8594) headers at least 6 months ahead; policy at /developers#deprecation. An MCP server with the same data is at /api/mcp.",
    "contact": {
      "name": "Anthony Hunt",
      "email": "info@anthonyhunts.com",
      "url": "https://www.anthonyhunts.com/developers"
    }
  },
  "externalDocs": {
    "description": "Developer guide",
    "url": "https://www.anthonyhunts.com/developers"
  },
  "servers": [
    {
      "url": "https://www.anthonyhunts.com"
    }
  ],
  "paths": {
    "/api/v1/pricing": {
      "get": {
        "operationId": "getPricing",
        "summary": "List public plans and add-ons with prices in USD",
        "description": "Fixed-price plans and add-ons. Custom projects are quoted after a free call and are not listed.",
        "tags": [
          "pricing"
        ],
        "parameters": [
          {
            "name": "plan",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "consultoria",
                "consultoria-avanzada",
                "digitalizate-basico",
                "taller-cerebro-digital",
                "addon-whatsapp",
                "addon-gbp",
                "addon-ads"
              ]
            },
            "description": "Return only this plan or add-on"
          }
        ],
        "responses": {
          "200": {
            "description": "Plans and add-ons",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingResponse"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/capabilities": {
      "get": {
        "operationId": "listCapabilities",
        "summary": "List the services this business provides",
        "description": "What an agent can ask this business for, with the URL of the page that describes each capability.",
        "tags": [
          "services"
        ],
        "parameters": [
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "ai-agents",
                "ai-training",
                "automation",
                "booking",
                "chatbot",
                "chatgpt",
                "claude",
                "contact",
                "crm",
                "funnels",
                "gohighlevel",
                "landing-page",
                "lead-follow-up",
                "meta-ads",
                "puerto-rico",
                "seo",
                "tracking",
                "voice-ai",
                "website",
                "whatsapp"
              ]
            },
            "description": "Return only services with this tag"
          }
        ],
        "responses": {
          "200": {
            "description": "Capabilities",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapabilityList"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contact": {
      "get": {
        "operationId": "getContactOptions",
        "summary": "Get contact and booking options",
        "description": "Email, phone, WhatsApp and booking URL. Booking and payment are completed by a person.",
        "tags": [
          "contact"
        ],
        "parameters": [
          {
            "name": "channel",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "email",
                "phone",
                "whatsapp",
                "booking"
              ]
            },
            "description": "Return only this contact channel"
          }
        ],
        "responses": {
          "200": {
            "description": "Contact options",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/posts": {
      "get": {
        "operationId": "listPosts",
        "summary": "List published blog posts, newest first, with cursor pagination",
        "description": "Pass next_cursor from the previous page as cursor. next_cursor is null on the last page.",
        "tags": [
          "content"
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            },
            "description": "Page size"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque cursor taken from next_cursor"
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "es",
                "en"
              ],
              "default": "es"
            },
            "description": "Language of the posts"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of posts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid limit, cursor or lang",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/batch": {
      "post": {
        "operationId": "batchGet",
        "summary": "Run up to 20 read requests in one call",
        "description": "Each item is a GET path under /api/v1. Items succeed or fail independently; each response carries its own status and body.",
        "tags": [
          "batch"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BatchRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One response per request, in order",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid batch body",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/ask": {
      "post": {
        "operationId": "askSite",
        "summary": "NLWeb: natural-language search over the site",
        "description": "Returns the most relevant pages (services, pricing, posts) with schema.org objects. Set streaming: true for Server-Sent Events (start, result, complete).",
        "tags": [
          "search"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AskRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ranked results",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AskResponse"
                }
              }
            }
          },
          "400": {
            "description": "Missing query",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/{path}": {
      "get": {
        "operationId": "getPageMarkdown",
        "summary": "Get any public page as Markdown",
        "description": "Send Accept: text/markdown, or append .md to the path. Unknown paths return 404 with a Markdown body and recovery links.",
        "tags": [
          "content"
        ],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Page path, e.g. about, servicios, blog/{slug}"
          },
          {
            "name": "Accept",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "text/markdown"
              ]
            },
            "description": "Must be text/markdown"
          }
        ],
        "responses": {
          "200": {
            "description": "Page as Markdown",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Unknown path, Markdown error body with recovery links",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "BatchRequest": {
        "type": "object",
        "required": [
          "requests"
        ],
        "properties": {
          "requests": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "type": "object",
              "required": [
                "path"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "path": {
                  "type": "string",
                  "description": "GET path under /api/v1, with query string"
                }
              }
            }
          }
        }
      },
      "BatchResponse": {
        "type": "object",
        "required": [
          "responses"
        ],
        "properties": {
          "responses": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "id",
                "status",
                "body"
              ],
              "properties": {
                "id": {
                  "type": "string"
                },
                "status": {
                  "type": "integer"
                },
                "body": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "AskRequest": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "string",
            "description": "Question in natural language, Spanish or English"
          },
          "streaming": {
            "type": "boolean",
            "default": false
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50,
            "default": 10
          },
          "query_id": {
            "type": "string"
          }
        }
      },
      "AskResponse": {
        "type": "object",
        "required": [
          "query_id",
          "_meta",
          "results"
        ],
        "properties": {
          "query_id": {
            "type": "string"
          },
          "query": {
            "type": "string"
          },
          "_meta": {
            "type": "object",
            "properties": {
              "response_type": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string",
                  "format": "uri"
                },
                "name": {
                  "type": "string"
                },
                "site": {
                  "type": "string"
                },
                "score": {
                  "type": "number"
                },
                "description": {
                  "type": "string"
                },
                "schema_object": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details",
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": [
              "not_found",
              "plan_not_found",
              "invalid_batch",
              "invalid_limit",
              "invalid_cursor",
              "invalid_lang",
              "method_not_allowed",
              "internal_error"
            ]
          },
          "docs": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Tier": {
        "type": "object",
        "required": [
          "id",
          "name",
          "currency",
          "one_time",
          "monthly",
          "includes",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "name_es": {
            "type": "string"
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          },
          "one_time": {
            "type": [
              "number",
              "null"
            ],
            "description": "One-time price in USD"
          },
          "monthly": {
            "type": [
              "number",
              "null"
            ],
            "description": "Monthly price in USD"
          },
          "unit": {
            "type": [
              "string",
              "null"
            ]
          },
          "summary": {
            "type": "string"
          },
          "includes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "excludes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "PricingResponse": {
        "type": "object",
        "required": [
          "currency",
          "plans",
          "addons"
        ],
        "properties": {
          "currency": {
            "type": "string"
          },
          "updated": {
            "type": "string",
            "format": "date"
          },
          "plans": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tier"
            }
          },
          "addons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Tier"
            }
          }
        }
      },
      "Capability": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "CapabilityList": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Capability"
            }
          }
        }
      },
      "Contact": {
        "type": "object",
        "required": [
          "email",
          "booking"
        ],
        "properties": {
          "organization": {
            "type": "string"
          },
          "person": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "whatsapp": {
            "type": "string",
            "format": "uri"
          },
          "booking": {
            "type": "string",
            "format": "uri"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "Post": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "url"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "published": {
            "type": "string",
            "format": "date"
          },
          "updated": {
            "type": "string",
            "format": "date"
          },
          "tag": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "markdown_url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "PostPage": {
        "type": "object",
        "required": [
          "data",
          "total",
          "next_cursor"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Post"
            }
          },
          "total": {
            "type": "integer"
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      }
    }
  }
}