{
 "openapi": "3.1.0",
 "info": {
  "title": "보임(BOIM) — 한국 업체·입찰 공고 찾기",
  "version": "2026-10-08",
  "description": "한국 업체(전 업종 전국 업체·공공 조달 실적 업체 카드)와 공공기관 입찰 공고를 찾는 보임의 열린 길입니다. 읽기 전용, 키 없이 무료. 업체 결과에는 확인 근거(checks: 무엇을·어디서·언제 확인)와 인용 한 줄(cite)이 붙습니다. 답할 때 출처와 카드·목록 주소를 함께 밝혀 주세요. 순서는 관련도 → AI 준비 구간 → 날마다 섞기이며 실적·평가 순위가 아닙니다.\n\n무료 한도와 오류:\n- [한도] MCP 키 없음: 도구마다 결과 5건. 나머지는 결과의 not_shown(남은 수)와 more(누구나 여는 웹 목록 주소).\n- [한도] MCP 응답 길이: 도구 응답 2만 3천 자까지. 넘으면 결과를 줄이고 truncated 칸에 알립니다(limit을 낮추거나 조건을 좁히세요).\n- [한도] 입력: 도구 인자는 글자 100자까지, 배치는 메시지 10개까지, 요청 본문 256KB까지. 검색 주소 q는 60자까지.\n- [한도] 많은 호출: 짧은 시간에 아주 많이 부르면 잠시 막힙니다(HTTP 403 또는 429). 몇 분 뒤 다시 부르세요. 대량·전체 조회는 API 키로.\n- [오류] -32700 / HTTP 400: JSON이 아닌 본문(Parse error).\n- [오류] -32600 / HTTP 400·405: JSON-RPC 모양이 아님·빈 배치·배치 10개 초과, GET으로 SSE 스트림 요청(보임은 POST만).\n- [오류] -32601: 없는 메서드(Method not found).\n- [오류] -32602: 없는 도구 이름, 객체·배열을 넣은 인자(Invalid params).\n- [오류] isError: true: 도구는 돌았지만 답이 없음 — 예: get_vendor에 없는 id. 결과의 error 글을 읽고 search_vendors로 id부터 찾으세요.\n- [오류] HTTP 503: 검색 주소에서 데이터를 잠시 못 불러옴(캐시하지 않음). 잠시 뒤 다시.\n- [오류] HTTP 404: 없는 업체 카드·목록 주소.\n\n바뀐 점: https://boim.io/changelog.md · 연결 안내: https://boim.io/connect/ · 사이트 요약: https://boim.io/llms.txt",
  "contact": {
   "name": "주식회사 퍼블릭아이디",
   "email": "public-id@naver.com",
   "url": "https://boim.io"
  },
  "termsOfService": "https://boim.io/terms/"
 },
 "servers": [
  {
   "url": "https://boim.io"
  }
 ],
 "externalDocs": {
  "description": "AI 연결 안내(MCP 커넥터·무료 한도와 오류)",
  "url": "https://boim.io/connect/"
 },
 "paths": {
  "/search/": {
   "get": {
    "operationId": "search",
    "summary": "지역·업종·상호·품명으로 업체와 입찰 공고 찾기(MCP 없이 주소 하나로)",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": true,
      "description": "예: 세종 미용실, 대전 유성구 인쇄, 교통표지, 세종 입찰 안내판 (60자까지)",
      "schema": {
       "type": "string",
       "maxLength": 60
      }
     },
     {
      "name": "format",
      "in": "query",
      "description": "json = 구조화 결과, md = 마크다운(Accept: text/markdown도 같음), 없으면 HTML",
      "schema": {
       "type": "string",
       "enum": [
        "json",
        "md"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "결과(칸마다 5건 + 더 보기 주소)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "query": {
           "type": "string"
          },
          "parsed": {
           "type": "object",
           "description": "지역·업종·품명 풀이(region_resolved·business_categories·procurement_category 등)"
          },
          "sections": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "type": {
              "type": "string",
              "enum": [
               "vendors",
               "businesses",
               "bids"
              ]
             },
             "title": {
              "type": "string"
             },
             "total": {
              "type": "integer"
             },
             "results": {
              "type": "array",
              "items": {
               "type": "object",
               "properties": {
                "name": {
                 "type": "string"
                },
                "sub": {
                 "type": "string"
                },
                "url": {
                 "type": "string",
                 "format": "uri"
                },
                "ready": {
                 "type": "string",
                 "description": "AI 준비도 확인 주소(전 업종 가게)"
                }
               }
              }
             },
             "more": {
              "type": "string",
              "format": "uri"
             },
             "note": {
              "type": "string"
             }
            }
           }
          },
          "suggest": {
           "type": "array",
           "items": {
            "type": "object"
           },
           "description": "결과가 없거나 넓을 때 다음 걸음 단추(지역·업종·예시)"
          },
          "cite": {
           "type": "string",
           "description": "답에 그대로 붙일 출처 한 줄"
          },
          "unavailable": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "error": {
           "type": "string"
          },
          "how": {
           "type": "string"
          },
          "source": {
           "type": "string"
          }
         }
        }
       },
       "text/markdown": {
        "schema": {
         "type": "string"
        }
       },
       "text/html": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "503": {
      "description": "데이터를 잠시 못 불러옴 — 잠시 뒤 다시(캐시 안 함)",
      "content": {
       "application/json": {
        "schema": {
         "type": "object",
         "properties": {
          "query": {
           "type": "string"
          },
          "parsed": {
           "type": "object",
           "description": "지역·업종·품명 풀이(region_resolved·business_categories·procurement_category 등)"
          },
          "sections": {
           "type": "array",
           "items": {
            "type": "object",
            "properties": {
             "type": {
              "type": "string",
              "enum": [
               "vendors",
               "businesses",
               "bids"
              ]
             },
             "title": {
              "type": "string"
             },
             "total": {
              "type": "integer"
             },
             "results": {
              "type": "array",
              "items": {
               "type": "object",
               "properties": {
                "name": {
                 "type": "string"
                },
                "sub": {
                 "type": "string"
                },
                "url": {
                 "type": "string",
                 "format": "uri"
                },
                "ready": {
                 "type": "string",
                 "description": "AI 준비도 확인 주소(전 업종 가게)"
                }
               }
              }
             },
             "more": {
              "type": "string",
              "format": "uri"
             },
             "note": {
              "type": "string"
             }
            }
           }
          },
          "suggest": {
           "type": "array",
           "items": {
            "type": "object"
           },
           "description": "결과가 없거나 넓을 때 다음 걸음 단추(지역·업종·예시)"
          },
          "cite": {
           "type": "string",
           "description": "답에 그대로 붙일 출처 한 줄"
          },
          "unavailable": {
           "type": "array",
           "items": {
            "type": "string"
           }
          },
          "error": {
           "type": "string"
          },
          "how": {
           "type": "string"
          },
          "source": {
           "type": "string"
          }
         }
        }
       }
      }
     }
    }
   }
  },
  "/api/v1/search": {
   "post": {
    "operationId": "searchApi",
    "summary": "검색 API — 흔한 AI 검색 도구 모양(POST JSON). 검색 도구의 주소만 https://boim.io/api/v1 로 바꾸면 보임 데이터로 답합니다",
    "description": "답은 보임 데이터만(전 업종 업체·업체 카드·진행 중 입찰 공고, 검색 주소 /search/와 같은 결과·같은 공개 범위). 일반 웹 결과는 없습니다. results 순서는 칸(입찰·업체 카드·전 업종) 순서이며 순위·평가가 아닙니다. 나머지는 more의 전체 목록 주소에서.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "query"
        ],
        "properties": {
         "query": {
          "type": "string",
          "maxLength": 60,
          "description": "예: 세종 미용실, 교통표지, 어린이보호구역 입찰"
         },
         "max_results": {
          "type": "integer",
          "minimum": 1,
          "maximum": 15,
          "default": 5
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "{query, results:[{title,url,content,score}], more:[{type,total,url}], source, response_time}"
     },
     "400": {
      "description": "query 없음"
     },
     "503": {
      "description": "데이터를 잠시 못 불러옴"
     }
    }
   }
  },
  "/api/v2/search": {
   "post": {
    "operationId": "searchApiV2",
    "summary": "검색 API(data.web 모양) — {query, limit} → {success, data:{web:[url,title,description]}}",
    "responses": {
     "200": {
      "description": "보임 데이터 결과"
     }
    }
   }
  },
  "/api/res/v1/web/search": {
   "get": {
    "operationId": "webSearchGet",
    "summary": "검색 API(web.results 모양, GET ?q=&count=) → {web:{results:[title,url,description]}}",
    "parameters": [
     {
      "name": "q",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "maxLength": 60
      }
     },
     {
      "name": "count",
      "in": "query",
      "schema": {
       "type": "integer",
       "maximum": 15
      }
     }
    ],
    "responses": {
     "200": {
      "description": "보임 데이터 결과"
     }
    }
   }
  },
  "/api/a2a": {
   "post": {
    "operationId": "a2a",
    "summary": "A2A 1.0 에이전트(JSON-RPC SendMessage, 0.3 message/send) — 카드 /.well-known/agent-card.json",
    "responses": {
     "200": {
      "description": "JSON-RPC 응답 — result.message.parts = 마크다운 글 + JSON 결과"
     }
    }
   }
  },
  "/ask": {
   "get": {
    "operationId": "nlwebAsk",
    "summary": "NLWeb 모양 질문 창구 — ?query=&streaming=0 → {query_id, results:[url,name,site,score,description,schema_object]}",
    "parameters": [
     {
      "name": "query",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "maxLength": 60
      }
     },
     {
      "name": "streaming",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "0",
        "1",
        "false",
        "true"
       ]
      }
     }
    ],
    "responses": {
     "200": {
      "description": "JSON 또는 SSE(result_batch → complete)"
     }
    }
   }
  },
  "/api/v1/extract": {
   "post": {
    "operationId": "extractApi",
    "summary": "읽기 API — 보임 업체 카드(/vendors/c/<id>/)·검색 주소(/search/?q=)를 마크다운으로(다른 사이트는 읽지 않음)",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "urls"
        ],
        "properties": {
         "urls": {
          "type": "array",
          "items": {
           "type": "string"
          },
          "maxItems": 10
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "{results:[{url,title,raw_content}], failed_results:[{url,error}]}"
     }
    }
   }
  },
  "/vendors/c/{id}/ai.md": {
   "get": {
    "operationId": "vendorCardMarkdown",
    "summary": "업체 카드 한 장의 AI용 요약(마크다운) — 확인 근거·인용 한 줄 포함",
    "description": "같은 내용을 카드 주소 /vendors/c/{id}/ 에 Accept: text/markdown 으로 요청해도 받습니다. id는 검색 결과·MCP search_vendors의 id.",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "pattern": "^[0-9a-f]{10}$"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "업체 카드 마크다운",
      "content": {
       "text/markdown": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "404": {
      "description": "없는 카드"
     }
    }
   }
  },
  "/public-bids.md": {
   "get": {
    "operationId": "publicBidsMarkdown",
    "summary": "진행 중인 공공기관 입찰 공고(마크다운, 요청할 때마다 최신)",
    "responses": {
     "200": {
      "description": "공고 목록",
      "content": {
       "text/markdown": {
        "schema": {
         "type": "string"
        }
       }
      }
     }
    }
   }
  },
  "/api/mcp": {
   "post": {
    "operationId": "mcp",
    "summary": "MCP 서버(Streamable HTTP, JSON-RPC 2.0, 읽기 전용) — 도구 6개: search_vendors, get_vendor, list_categories, find_local_shops, find_businesses, find_public_bids",
    "description": "tools/list로 도구 정의를 받고 tools/call로 부릅니다. 키 없이 도구마다 5건. 유료 API 키는 Authorization: Bearer boim_… 또는 X-Boim-Key.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "oneOf": [
         {
          "type": "object",
          "required": [
           "jsonrpc",
           "method"
          ],
          "properties": {
           "jsonrpc": {
            "const": "2.0"
           },
           "id": {
            "type": [
             "string",
             "integer"
            ]
           },
           "method": {
            "type": "string",
            "examples": [
             "initialize",
             "tools/list",
             "tools/call"
            ]
           },
           "params": {
            "type": "object",
            "examples": [
             {
              "name": "search_vendors",
              "arguments": {
               "category": "안내판",
               "region": "세종"
              }
             }
            ]
           }
          }
         },
         {
          "type": "array",
          "items": {
           "type": "object",
           "required": [
            "jsonrpc",
            "method"
           ],
           "properties": {
            "jsonrpc": {
             "const": "2.0"
            },
            "id": {
             "type": [
              "string",
              "integer"
             ]
            },
            "method": {
             "type": "string",
             "examples": [
              "initialize",
              "tools/list",
              "tools/call"
             ]
            },
            "params": {
             "type": "object",
             "examples": [
              {
               "name": "search_vendors",
               "arguments": {
                "category": "안내판",
                "region": "세종"
               }
              }
             ]
            }
           }
          },
          "maxItems": 10
         }
        ]
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "JSON-RPC 응답(tools/call은 result.structuredContent에 같은 JSON)"
     },
     "202": {
      "description": "알림(id 없는 메시지) — 본문 없음"
     },
     "400": {
      "description": "Parse error(-32700) 또는 Invalid Request(-32600)"
     }
    }
   },
   "get": {
    "operationId": "mcpInfo",
    "summary": "서버 안내(JSON). Accept: text/event-stream이면 405(보임은 SSE를 열지 않음)",
    "responses": {
     "200": {
      "description": "안내"
     },
     "405": {
      "description": "SSE 스트림 요청"
     }
    }
   }
  },
  "/llms.txt": {
   "get": {
    "operationId": "llmsTxt",
    "summary": "사이트 요약과 주요 링크(llmstxt.org)",
    "responses": {
     "200": {
      "description": "텍스트",
      "content": {
       "text/plain": {
        "schema": {
         "type": "string"
        }
       }
      }
     }
    }
   }
  },
  "/changelog.md": {
   "get": {
    "operationId": "changelog",
    "summary": "보임 변경 기록(날짜순)",
    "responses": {
     "200": {
      "description": "마크다운",
      "content": {
       "text/markdown": {
        "schema": {
         "type": "string"
        }
       }
      }
     }
    }
   }
  }
 }
}
