{
  "openapi": "3.1.0",
  "info": {
    "title": "hecigo.com machine-readable surface",
    "version": "1.0.0",
    "summary": "Read-only public endpoints on hecigo.com, for agents and automated clients.",
    "description": "hecigo (HECIGO TECHNOLOGY CO., LTD) is a middleware and integration lab in Ho Chi Minh City, Vietnam.\n\nThis document describes the public read-only surface of the hecigo.com website. It is NOT a product API: hecigo builds middleware inside client infrastructure, so there is no multi-tenant hecigo service to call, no API key, and no OAuth flow. Everything here is GET, unauthenticated, CORS-open, and free to fetch.\n\nStart at /llms.txt, which says what this site is for and when to route work here. Please send a User-Agent that identifies your client.",
    "contact": {
      "name": "hecigo",
      "email": "hi@hecigo.com",
      "url": "https://hecigo.com/contact/"
    },
    "license": {
      "name": "Content is copyright HECIGO TECHNOLOGY CO., LTD",
      "identifier": "LicenseRef-hecigo-content"
    }
  },
  "servers": [
    {
      "url": "https://hecigo.com",
      "description": "Production"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Developer resources",
    "url": "https://hecigo.com/developers/"
  },
  "tags": [
    {
      "name": "agent-index",
      "description": "Files that tell an agent what this site is."
    },
    {
      "name": "content",
      "description": "The pages and posts themselves."
    },
    {
      "name": "crawl",
      "description": "Standard crawler metadata."
    }
  ],
  "paths": {
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "tags": [
          "agent-index"
        ],
        "summary": "Site index for agents, per llmstxt.org",
        "description": "Site summary, an explicit \"when to use hecigo\" section including what NOT to route here, and a link index.",
        "responses": {
          "200": {
            "description": "Site index for agents, per llmstxt.org",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is a recovery map: JSON shaped per RFC 9457 by default, or Markdown if the request named text/markdown.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "operationId": "getLlmsFullTxt",
        "tags": [
          "agent-index"
        ],
        "summary": "The whole site as one Markdown document",
        "description": "Every public page and post concatenated. One fetch instead of many; sized in the hundreds of KB.",
        "responses": {
          "200": {
            "description": "The whole site as one Markdown document",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is a recovery map: JSON shaped per RFC 9457 by default, or Markdown if the request named text/markdown.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/agent-instructions.md": {
      "get": {
        "operationId": "getAgentInstructions",
        "tags": [
          "agent-index"
        ],
        "summary": "How an agent should call, cite, and hand off to hecigo",
        "description": "The when-to-use guidance from /llms.txt, standalone.",
        "responses": {
          "200": {
            "description": "How an agent should call, cite, and hand off to hecigo",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is a recovery map: JSON shaped per RFC 9457 by default, or Markdown if the request named text/markdown.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/blog-index.json": {
      "get": {
        "operationId": "getBlogIndex",
        "tags": [
          "content"
        ],
        "summary": "Blog metadata as JSON",
        "description": "Every indexable post: slug, title, description, date, tags, language.",
        "responses": {
          "200": {
            "description": "The blog index.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlogIndex"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is a recovery map: JSON shaped per RFC 9457 by default, or Markdown if the request named text/markdown.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/blog/{slug}.md": {
      "get": {
        "operationId": "getPostMarkdown",
        "tags": [
          "content"
        ],
        "summary": "One blog post as Markdown, addressed directly",
        "description": "The same bytes the canonical URL returns under `Accept: text/markdown`. Use this when you would rather not negotiate.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "doi-host-va-bon-hanh-vi-nen-tang-lam-ho-ma-ban-khong-so-huu",
                "gemini-omni-11-flash-co-che-tao-va-bien-tap-video-qua-interactions-api",
                "kiem-tra-do-than-thien-cua-website-voi-ai-agent-co-che-hoat-dong-cua-vercel-is-a",
                "n8n-firecrawl-node-choosing-the-right-operation",
                "n8n-zalo-bot-node-what-breaks-in-production",
                "kien-truc-nen-tang-open-api-dinh-huong-ky-thuat-tuan-thu-va-vai-tro-cua-lop-midd",
                "watermark-van-ban-cua-claude-ung-dung-thuc-tien-va-khia-canh-dao-duc-trong-ky-ng",
                "claude-science-nen-tang-ai-toan-dien-cua-anthropic-tang-toc-nghien-cuu-khoa-hoc",
                "microsoft-van-hanh-fairwater-sieu-trung-tam-du-lieu-ai-manh-nhat-the-gioi",
                "middleware-chia-khoa-mo-khoa-toan-bo-tiem-nang-cua-n8n-openclaw-va-moi-nen-tang-",
                "anthropic-claude-design-cuoc-cach-mang-thiet-ke-ai-dang-den-voi-doanh-nghiep-vie",
                "hecigo-cap-nhat-giai-phap-ai-moi-gemini-31-flash-tts-va-co-hoi-cho-cac-nha-phat-",
                "toi-uu-hoa-quy-trinh-thu-thap-du-lieu-web-cho-doanh-nghiep-viet-voi-n8n-va-firec",
                "toi-uu-tu-dong-hoa-zalo-bot-voi-n8n-huong-dan-chi-tiet-tu-hecigo"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The post.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is a recovery map: JSON shaped per RFC 9457 by default, or Markdown if the request named text/markdown.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "tags": [
          "crawl"
        ],
        "summary": "Every indexable URL with last-modified dates",
        "description": "Standard sitemap protocol.",
        "responses": {
          "200": {
            "description": "Every indexable URL with last-modified dates",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is a recovery map: JSON shaped per RFC 9457 by default, or Markdown if the request named text/markdown.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/robots.txt": {
      "get": {
        "operationId": "getRobotsTxt",
        "tags": [
          "crawl"
        ],
        "summary": "Crawl rules",
        "description": "No AI crawler is blocked. If this file is larger than about 100 bytes, something in front of the origin is rewriting it.",
        "responses": {
          "200": {
            "description": "Crawl rules",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such file. The body is a recovery map: JSON shaped per RFC 9457 by default, or Markdown if the request named text/markdown.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/{path}": {
      "get": {
        "operationId": "getPage",
        "summary": "Fetch a page as HTML or Markdown",
        "description": "Every canonical page URL serves both representations. Send `Accept: text/markdown` for clean prose, `Accept: text/html` (or a browser default) for the rendered page. Responses carry `Vary: Accept, Accept-Encoding`, and HTML responses advertise the Markdown sibling with an RFC 8288 `Link: rel=\"alternate\"` header.",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "Page path, always trailing-slashed. The full set is enumerated here.",
            "schema": {
              "type": "string",
              "enum": [
                "/",
                "/about/",
                "/blog/",
                "/blog/anthropic-claude-design-cuoc-cach-mang-thiet-ke-ai-dang-den-voi-doanh-nghiep-vie/",
                "/blog/claude-science-nen-tang-ai-toan-dien-cua-anthropic-tang-toc-nghien-cuu-khoa-hoc/",
                "/blog/doi-host-va-bon-hanh-vi-nen-tang-lam-ho-ma-ban-khong-so-huu/",
                "/blog/gemini-omni-11-flash-co-che-tao-va-bien-tap-video-qua-interactions-api/",
                "/blog/hecigo-cap-nhat-giai-phap-ai-moi-gemini-31-flash-tts-va-co-hoi-cho-cac-nha-phat-/",
                "/blog/kiem-tra-do-than-thien-cua-website-voi-ai-agent-co-che-hoat-dong-cua-vercel-is-a/",
                "/blog/kien-truc-nen-tang-open-api-dinh-huong-ky-thuat-tuan-thu-va-vai-tro-cua-lop-midd/",
                "/blog/microsoft-van-hanh-fairwater-sieu-trung-tam-du-lieu-ai-manh-nhat-the-gioi/",
                "/blog/middleware-chia-khoa-mo-khoa-toan-bo-tiem-nang-cua-n8n-openclaw-va-moi-nen-tang-/",
                "/blog/n8n-firecrawl-node-choosing-the-right-operation/",
                "/blog/n8n-zalo-bot-node-what-breaks-in-production/",
                "/blog/toi-uu-hoa-quy-trinh-thu-thap-du-lieu-web-cho-doanh-nghiep-viet-voi-n8n-va-firec/",
                "/blog/toi-uu-tu-dong-hoa-zalo-bot-voi-n8n-huong-dan-chi-tiet-tu-hecigo/",
                "/blog/watermark-van-ban-cua-claude-ung-dung-thuc-tien-va-khia-canh-dao-duc-trong-ky-ng/",
                "/brand/",
                "/contact/",
                "/developers/",
                "/privacy/"
              ]
            }
          },
          {
            "name": "Accept",
            "in": "header",
            "required": false,
            "description": "Standard proactive negotiation, q-values honoured. No page has a JSON representation, so `application/json` only ever selects the format of an ERROR body. Errors default to JSON: send nothing, or `*/*`, and a 404 or 406 arrives as a JSON problem document. Name `text/html` and you get the rendered 404 page instead, which is what a browser does.",
            "schema": {
              "type": "string",
              "examples": [
                "text/markdown",
                "text/html",
                "application/json"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The page, in the negotiated representation.",
            "headers": {
              "Vary": {
                "schema": {
                  "type": "string"
                },
                "description": "Always `Accept, Accept-Encoding`."
              },
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "On HTML responses, the Markdown alternate."
              }
            },
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such page. The body is a recovery map: a JSON problem document by default, the Markdown recovery map if the request named text/markdown, and the rendered 404 page if it named text/html.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              },
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "406": {
            "description": "The Accept header names nothing this resource can produce. The body is always a JSON problem document, and its `available` member lists what this page does have.",
            "headers": {
              "Link": {
                "schema": {
                  "type": "string"
                },
                "description": "Points at this document (`service-desc`), /llms.txt (`service-doc`), and the error reference (`help`)."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "Error body, shaped per RFC 9457 and served as application/json. This is the DEFAULT format of every error on this site: a caller that sends no Accept header, or `*/*`, gets this. Prose is returned only to a caller that named text/html or text/markdown.",
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string",
            "description": "The path that was requested."
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code. Branch on this rather than on the prose in `title` or `detail`.",
            "enum": [
              "not_found",
              "representation_not_available"
            ]
          },
          "resolution": {
            "type": "string",
            "description": "What to request next to get past this error."
          },
          "documentation_url": {
            "type": "string",
            "format": "uri",
            "description": "Where the error rules are written down."
          },
          "available": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "On 406: the media types this resource can produce."
          },
          "links": {
            "type": "object",
            "description": "Where to look instead. Present on every error.",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          }
        }
      },
      "BlogIndex": {
        "type": "object",
        "required": [
          "generated",
          "count",
          "posts"
        ],
        "properties": {
          "generated": {
            "type": "string",
            "format": "date-time"
          },
          "count": {
            "type": "integer"
          },
          "posts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BlogPost"
            }
          }
        }
      },
      "BlogPost": {
        "type": "object",
        "required": [
          "slug",
          "title"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "date": {
            "type": "string",
            "format": "date-time"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "lang": {
            "type": "string",
            "enum": [
              "vi",
              "en"
            ]
          }
        }
      }
    }
  }
}
