{
  "openapi": "3.1.0",
  "info": {
    "title": "Lee Sugano Digital Solutions - Public Content API",
    "version": "1.0.0",
    "summary": "Public content and lead-capture API for leesugano.com.",
    "description": "Public, unauthenticated API for the Lee Sugano Digital Solutions website -\na Brazilian web, mobile, SaaS and AI development agency based in\nGunma-ken, Isesaki-shi, Japan.\n\nUse these endpoints to read the site's editorial content (blog posts,\ncategories and tags, in Portuguese, English, Japanese and Spanish), to\nrecord reactions on posts, and to open a commercial conversation\n(newsletter signup and solution recommendation).\n\nConventions:\n\n- Every response is `application/json`, errors included.\n- Errors carry `error` (human message), `code` (stable, for logic) and\n  `requestId` (for support).\n- Rate-limited endpoints return `RateLimit-Limit`, `RateLimit-Remaining`\n  and `RateLimit-Reset` on every response, plus `Retry-After` on a 429.\n  Honour them instead of retrying in a loop.\n- The same content is available as Markdown on the site's public URLs\n  via `Accept: text/markdown` or a `.md` suffix.",
    "termsOfService": "https://leesugano.com/termos",
    "contact": {
      "name": "Lee Sugano Digital Solutions",
      "email": "contact@leesugano.com",
      "url": "https://leesugano.com/contact"
    },
    "license": {
      "name": "Reading, indexing and citation permitted with attribution",
      "url": "https://leesugano.com/termos"
    }
  },
  "externalDocs": {
    "description": "Developer and agent documentation",
    "url": "https://leesugano.com/docs"
  },
  "servers": [
    {
      "url": "https://leesugano.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "blog",
      "description": "Editorial content published on the blog."
    },
    {
      "name": "taxonomy",
      "description": "Categories and tags that organise the blog."
    },
    {
      "name": "engagement",
      "description": "Reader reactions on posts."
    },
    {
      "name": "leads",
      "description": "Contact capture and solution recommendation."
    },
    {
      "name": "media",
      "description": "Open Graph image generation."
    }
  ],
  "paths": {
    "/api/posts": {
      "get": {
        "operationId": "listPublishedPosts",
        "tags": [
          "blog"
        ],
        "summary": "List published blog posts",
        "description": "Returns the most recent published posts, already translated into the requested language. The post body is not part of this listing - fetch the post's public URL with `Accept: text/markdown` to read the full text. Cover images stored as data URLs are omitted (`null`).",
        "parameters": [
          {
            "name": "locale",
            "in": "query",
            "required": false,
            "description": "Language of the textual fields. Values outside the list fall back to the default (pt) without error.",
            "schema": {
              "type": "string",
              "enum": [
                "pt",
                "en",
                "ja",
                "es"
              ],
              "default": "pt"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of posts to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 4
            }
          },
          {
            "name": "featured",
            "in": "query",
            "required": false,
            "description": "When `true`, returns only posts flagged as featured.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Published posts, newest first.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PostSummary"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (60 req/min per IP).",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too Many Requests",
                  "code": "RATE_LIMITED"
                }
              }
            }
          },
          "500": {
            "description": "Failed to fetch the posts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to fetch the posts.",
                  "code": "POSTS_FETCH_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      }
    },
    "/api/categories": {
      "get": {
        "operationId": "listCategories",
        "tags": [
          "taxonomy"
        ],
        "summary": "List blog categories",
        "description": "Every existing category, alphabetically. The `slug` is what appears in `/blog/categoria/{slug}`.",
        "responses": {
          "200": {
            "description": "Registered categories.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Category"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (60 req/min per IP).",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too Many Requests",
                  "code": "RATE_LIMITED"
                }
              }
            }
          },
          "500": {
            "description": "Failed to fetch the categories.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to fetch the categories.",
                  "code": "CATEGORIES_FETCH_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      }
    },
    "/api/tags": {
      "get": {
        "operationId": "listTags",
        "tags": [
          "taxonomy"
        ],
        "summary": "List blog tags",
        "description": "Every existing tag, alphabetically. Not every tag has an indexable page: only those with enough published posts appear in the sitemap.",
        "responses": {
          "200": {
            "description": "Registered tags.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Tag"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (60 req/min per IP).",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too Many Requests",
                  "code": "RATE_LIMITED"
                }
              }
            }
          },
          "500": {
            "description": "Failed to fetch the tags.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to fetch the tags.",
                  "code": "TAGS_FETCH_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      }
    },
    "/api/posts/{id}/reactions": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Numeric post identifier (the `id` field of `listPublishedPosts`).",
          "schema": {
            "type": "integer",
            "minimum": 1
          }
        }
      ],
      "get": {
        "operationId": "getPostReactions",
        "tags": [
          "engagement"
        ],
        "summary": "Read a post's reactions",
        "description": "Like and dislike counters for the post, plus the reaction attributed to the caller. The caller is identified by a fingerprint derived from the IP on the server - no cookie, no login.",
        "responses": {
          "200": {
            "description": "Current counters for the post.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReactionState"
                }
              }
            }
          },
          "400": {
            "description": "The `id` given is not a number.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "The `id` given is not a number.",
                  "code": "INVALID_POST_ID",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          },
          "404": {
            "description": "No post exists with that id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "No post exists with that id.",
                  "code": "POST_NOT_FOUND",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (60 req/min per IP).",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (60).",
                "schema": {
                  "type": "integer",
                  "example": 60
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 59
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too Many Requests",
                  "code": "RATE_LIMITED"
                }
              }
            }
          },
          "500": {
            "description": "Failed to fetch the reactions.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to fetch the reactions.",
                  "code": "REACTIONS_FETCH_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "reactToPost",
        "tags": [
          "engagement"
        ],
        "summary": "Add, switch or remove a reaction",
        "description": "Sending the reaction that is already recorded removes it (toggle). Sending the opposite one switches it. The operation is idempotent per fingerprint: one IP cannot inflate the counter.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReactionInput"
              },
              "example": {
                "reactionType": "like"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The post's state after the reaction.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (20).",
                "schema": {
                  "type": "integer",
                  "example": 20
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 19
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReactionResult"
                }
              }
            }
          },
          "400": {
            "description": "`reactionType` missing or outside `like`/`dislike`, or invalid `id`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "`reactionType` missing or outside `like`/`dislike`, or invalid `id`.",
                  "code": "INVALID_REACTION",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          },
          "404": {
            "description": "No post exists with that id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "No post exists with that id.",
                  "code": "POST_NOT_FOUND",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (20 req/min per IP).",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (20).",
                "schema": {
                  "type": "integer",
                  "example": 20
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 19
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too Many Requests",
                  "code": "RATE_LIMITED"
                }
              }
            }
          },
          "500": {
            "description": "Failed to record the reaction.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to record the reaction.",
                  "code": "REACTION_SAVE_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      }
    },
    "/api/newsletter": {
      "post": {
        "operationId": "subscribeToNewsletter",
        "tags": [
          "leads"
        ],
        "summary": "Subscribe an email to the newsletter",
        "description": "The response is identical for a new signup, a reactivated cancellation and an address already subscribed - deliberately, so subscribers cannot be enumerated.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NewsletterInput"
              },
              "example": {
                "email": "pessoa@exemplo.com",
                "name": "Pessoa",
                "source": "agent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signup processed.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (10).",
                "schema": {
                  "type": "integer",
                  "example": 10
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 9
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NewsletterResult"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid email.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Missing or invalid email.",
                  "code": "VALIDATION_ERROR",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (10 req/min per IP).",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (10).",
                "schema": {
                  "type": "integer",
                  "example": 10
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 9
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too Many Requests",
                  "code": "RATE_LIMITED"
                }
              }
            }
          },
          "500": {
            "description": "Failed to process the signup.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to process the signup.",
                  "code": "NEWSLETTER_SUBSCRIBE_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      }
    },
    "/api/start/recommend": {
      "post": {
        "operationId": "recommendSolution",
        "tags": [
          "leads"
        ],
        "summary": "Recommend a solution from a business profile",
        "description": "Takes a short briefing and returns the agency's four service lines ranked by fit, each with an AI-generated reason in the lead's language. The contact is stored before the model call: if the AI fails, the response falls back to a deterministic ranking (`fallback: true`) and the lead is not lost. This endpoint is expensive - honour the 8 req/min limit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecommendInput"
              },
              "example": {
                "name": "Maria",
                "businessName": "Doceria Sakura",
                "niche": "confeitaria artesanal",
                "digitalPresence": "social",
                "mainGoal": "sellOnline",
                "email": "maria@exemplo.com",
                "locale": "pt"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Solutions ranked for the profile given.",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (8).",
                "schema": {
                  "type": "integer",
                  "example": 8
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 7
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecommendResult"
                }
              }
            }
          },
          "400": {
            "description": "Invalid payload. Either an email or a phone number is required.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Invalid payload. Either an email or a phone number is required.",
                  "code": "VALIDATION_ERROR",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (8 req/min per IP).",
            "headers": {
              "RateLimit-Limit": {
                "description": "Requests allowed per IP within the 60s window (8).",
                "schema": {
                  "type": "integer",
                  "example": 8
                }
              },
              "RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 7
                }
              },
              "RateLimit-Reset": {
                "description": "Unix timestamp (seconds) at which the window resets.",
                "schema": {
                  "type": "integer",
                  "format": "int64"
                }
              },
              "x-request-id": {
                "description": "Request identifier; quote it when reporting a problem.",
                "schema": {
                  "type": "string"
                }
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying the request.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Too Many Requests",
                  "code": "RATE_LIMITED"
                }
              }
            }
          },
          "500": {
            "description": "Failed to generate the recommendation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to generate the recommendation.",
                  "code": "START_RECOMMEND_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      }
    },
    "/api/og": {
      "get": {
        "operationId": "renderOpenGraphImage",
        "tags": [
          "media"
        ],
        "summary": "Render a 1200x630 Open Graph image",
        "description": "Renders a PNG in the site's visual identity. Used by the pages' meta tags; public so external tools can preview it.",
        "parameters": [
          {
            "name": "title",
            "in": "query",
            "required": false,
            "description": "Main headline of the image.",
            "schema": {
              "type": "string",
              "default": "Lee Sugano"
            }
          },
          {
            "name": "subtitle",
            "in": "query",
            "required": false,
            "description": "Supporting line below the headline.",
            "schema": {
              "type": "string",
              "default": "Agência de Soluções Digitais Premium"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Visual variant of the card.",
            "schema": {
              "type": "string",
              "enum": [
                "default",
                "service",
                "portfolio",
                "blog"
              ],
              "default": "default"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A 1200x630 PNG image.",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "500": {
            "description": "Failed to render the image.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Failed to render the image.",
                  "code": "OG_IMAGE_FAILED",
                  "requestId": "b0d0f1a2-3c4d-5e6f-7a8b-9c0d1e2f3a4b"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Error shape used by the whole API. `code` is stable and meant for logic; `error` is meant for humans.",
        "required": [
          "error",
          "code"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable message."
          },
          "code": {
            "type": "string",
            "description": "Stable error code (SCREAMING_SNAKE_CASE).",
            "examples": [
              "VALIDATION_ERROR",
              "RATE_LIMITED",
              "NOT_FOUND"
            ]
          },
          "requestId": {
            "type": "string",
            "description": "Request id, also returned in the `x-request-id` header."
          },
          "details": {
            "type": "object",
            "additionalProperties": true,
            "description": "Validation details. Present only in development."
          },
          "documentation": {
            "type": "string",
            "format": "uri",
            "description": "URL of the documentation relevant to this error."
          }
        }
      },
      "PostSummary": {
        "type": "object",
        "description": "A published post, without the body text.",
        "required": [
          "id",
          "title",
          "slug"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "description": "Post identifier."
          },
          "title": {
            "type": "string",
            "description": "Title in the requested language."
          },
          "slug": {
            "type": "string",
            "description": "Slug in the requested language; the public URL is `/{locale}/blog/{slug}`."
          },
          "excerpt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Excerpt in the requested language."
          },
          "coverImage": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Cover image URL. `null` when the cover is embedded as a data URL."
          },
          "publishedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "readTime": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Estimated reading time, in minutes."
          },
          "views": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Accumulated page views."
          },
          "categoryId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "categoryName": {
            "type": [
              "string",
              "null"
            ],
            "description": "Category name in the requested language."
          },
          "categorySlug": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Category": {
        "type": "object",
        "required": [
          "id",
          "name",
          "slug"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "Used in `/blog/categoria/{slug}`."
          }
        }
      },
      "Tag": {
        "type": "object",
        "required": [
          "id",
          "name",
          "slug"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "Used in `/blog/tag/{slug}`."
          }
        }
      },
      "ReactionType": {
        "type": "string",
        "enum": [
          "like",
          "dislike"
        ],
        "description": "Accepted reaction types."
      },
      "ReactionState": {
        "type": "object",
        "required": [
          "likes",
          "dislikes",
          "userReaction"
        ],
        "properties": {
          "likes": {
            "type": "integer",
            "minimum": 0
          },
          "dislikes": {
            "type": "integer",
            "minimum": 0
          },
          "userReaction": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ReactionType"
              },
              {
                "type": "null"
              }
            ],
            "description": "Reaction already recorded for the caller, or `null`."
          }
        }
      },
      "ReactionInput": {
        "type": "object",
        "required": [
          "reactionType"
        ],
        "properties": {
          "reactionType": {
            "$ref": "#/components/schemas/ReactionType"
          }
        }
      },
      "ReactionResult": {
        "type": "object",
        "required": [
          "success",
          "likes",
          "dislikes",
          "userReaction"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "likes": {
            "type": "integer",
            "minimum": 0
          },
          "dislikes": {
            "type": "integer",
            "minimum": 0
          },
          "userReaction": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ReactionType"
              },
              {
                "type": "null"
              }
            ],
            "description": "`null` when the toggle removed the reaction."
          }
        }
      },
      "NewsletterInput": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255
          },
          "name": {
            "type": "string",
            "maxLength": 120
          },
          "source": {
            "type": "string",
            "maxLength": 60,
            "description": "Where the signup came from. Agents should identify themselves here."
          }
        }
      },
      "NewsletterResult": {
        "type": "object",
        "required": [
          "success",
          "message"
        ],
        "properties": {
          "success": {
            "type": "boolean"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "RecommendInput": {
        "type": "object",
        "description": "Business briefing. Either `email` or `phone` is required.",
        "required": [
          "name",
          "niche",
          "digitalPresence",
          "mainGoal"
        ],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 2,
            "maxLength": 120
          },
          "businessName": {
            "type": "string",
            "maxLength": 160
          },
          "niche": {
            "type": "string",
            "minLength": 2,
            "maxLength": 160,
            "description": "Line of business, free text."
          },
          "digitalPresence": {
            "type": "string",
            "enum": [
              "none",
              "social",
              "basicSite",
              "fullSite"
            ],
            "description": "`none` no presence at all; `social` social networks only; `basicSite` an outdated site; `fullSite` a site that already converts."
          },
          "mainGoal": {
            "type": "string",
            "enum": [
              "visibility",
              "sellOnline",
              "automate",
              "organize",
              "unsure"
            ],
            "description": "The business's main goal for the coming months."
          },
          "details": {
            "type": "string",
            "maxLength": 600
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 255
          },
          "phone": {
            "type": "string",
            "pattern": "^\\+?[\\d\\s().-]{8,25}$"
          },
          "locale": {
            "type": "string",
            "enum": [
              "pt",
              "en",
              "ja",
              "es"
            ],
            "default": "pt"
          }
        }
      },
      "RecommendationItem": {
        "type": "object",
        "required": [
          "key",
          "fit"
        ],
        "properties": {
          "key": {
            "type": "string",
            "enum": [
              "website",
              "ecommerce",
              "automation",
              "admin"
            ],
            "description": "One of the agency's service lines."
          },
          "fit": {
            "type": "string",
            "enum": [
              "primary",
              "recommended",
              "later"
            ],
            "description": "How well the solution fits the profile given."
          },
          "reason": {
            "type": "string",
            "description": "Reasoning in the lead's language. Absent when `fallback` is `true`."
          }
        }
      },
      "RecommendResult": {
        "type": "object",
        "required": [
          "items",
          "fallback"
        ],
        "properties": {
          "items": {
            "type": "array",
            "description": "The four service lines, best fit first.",
            "items": {
              "$ref": "#/components/schemas/RecommendationItem"
            }
          },
          "pitch": {
            "type": "string",
            "description": "Personalised summary. Absent when `fallback` is `true`."
          },
          "fallback": {
            "type": "boolean",
            "description": "`true` when the AI failed and the ranking came from the deterministic rule."
          },
          "leadSaved": {
            "type": "boolean",
            "description": "`true` when the contact was stored."
          },
          "requestId": {
            "type": "string"
          }
        }
      }
    }
  },
  "security": []
}
