{
  "openapi": "3.1.0",
  "info": {
    "title": "Daiso Finder API",
    "version": "1.0.0",
    "summary": "Find Daiso stores in Korea and check in-store product stock, price, and shelf location.",
    "description": "Daiso Finder (다이소 파인더) is a free, keyless public API for finding Daiso stores in South Korea\nand checking product stock, price, and shelf placement inside a specific store.\n\n## When to use\n\n- A user asks where to buy an item at Daiso, or whether a Daiso store has it in stock right now.\n- A user needs a Daiso store's address, opening hours, coordinates, or store code.\n- A user asks on which floor or zone of a Daiso store an item is shelved.\n\n## Authentication\n\nNone. Every endpoint is anonymous, free, and self-serve — no API key, token, or sign-up.\n\n## Calling order\n\n1. `searchStores` (or `searchNearbyStores`) to obtain a store `code`.\n2. `searchStoreProducts` with that `code` as `branchCode` to list in-stock products.\n3. `getProductAvailability` for one product's stock, shelf placement, and nearby stores that stock it.\n\n## Sandbox\n\n`/api/sandbox/*` mirrors the production endpoints with fixed fixture data and never calls the\nupstream Daiso service. Use it to verify an integration without generating live traffic.\n\n## Rate limits\n\nNo hard quota is enforced. Requests are proxied to the upstream Daiso service, so keep concurrency\nmodest (a few requests per second) and cache store metadata, which changes rarely.",
    "contact": {
      "name": "Daiso Finder support",
      "email": "contact@daiso-finder.kr",
      "url": "https://www.daiso-finder.kr/contact"
    },
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    },
    "termsOfService": "https://www.daiso-finder.kr/privacy",
    "x-repository": "https://github.com/yutaejeong/daiso-finder"
  },
  "servers": [
    {
      "url": "https://www.daiso-finder.kr",
      "description": "Production"
    },
    {
      "url": "https://www.daiso-finder.kr/api/sandbox",
      "description": "Sandbox (fixture data)"
    }
  ],
  "externalDocs": {
    "description": "Daiso Finder developer portal",
    "url": "https://www.daiso-finder.kr/developers"
  },
  "security": [],
  "tags": [
    {
      "name": "stores",
      "description": "Daiso store lookup by keyword or GPS coordinates."
    },
    {
      "name": "products",
      "description": "In-store product stock, price, and shelf placement."
    },
    {
      "name": "meta",
      "description": "Service discovery documents for agents."
    }
  ],
  "paths": {
    "/api": {
      "get": {
        "operationId": "getApiIndex",
        "tags": [
          "meta"
        ],
        "summary": "List API entry points",
        "description": "Returns a machine-readable index of every public endpoint and discovery document, so an agent can bootstrap from a single request.",
        "responses": {
          "200": {
            "description": "API index",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiIndex"
                }
              }
            }
          }
        }
      }
    },
    "/api/branches/search": {
      "get": {
        "operationId": "searchStores",
        "tags": [
          "stores"
        ],
        "summary": "Search Daiso stores by keyword or coordinates",
        "description": "Searches Daiso stores in South Korea. Provide `keyword` for an address or store-name search, or both `curLttd` and `curLitd` for a nearest-first search around a GPS position. Returns at most `pageSize` stores; a full page means more results may exist on the next `currentPage`.",
        "parameters": [
          {
            "name": "keyword",
            "in": "query",
            "required": false,
            "description": "Address, neighborhood, or store name. Required unless coordinates are supplied.",
            "schema": {
              "type": "string",
              "examples": [
                "강남",
                "다이소 명동"
              ]
            }
          },
          {
            "name": "curLttd",
            "in": "query",
            "required": false,
            "description": "Latitude in decimal degrees, for a nearby search.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -90,
              "maximum": 90,
              "examples": [
                37.497175
              ]
            }
          },
          {
            "name": "curLitd",
            "in": "query",
            "required": false,
            "description": "Longitude in decimal degrees, for a nearby search.",
            "schema": {
              "type": "number",
              "format": "double",
              "minimum": -180,
              "maximum": 180,
              "examples": [
                127.027926
              ]
            }
          },
          {
            "name": "currentPage",
            "in": "query",
            "required": false,
            "description": "1-based page number.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "pageSize",
            "in": "query",
            "required": false,
            "description": "Stores per page.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 10
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Matching stores, nearest first for coordinate searches.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Store"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          }
        }
      }
    },
    "/api/branches/{code}": {
      "get": {
        "operationId": "getStore",
        "tags": [
          "stores"
        ],
        "summary": "Get one Daiso store by store code",
        "description": "Returns address, coordinates, and opening hours for a single store. `code` is the `code` field returned by `searchStores`.",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Daiso store code, as returned by `searchStores`.",
            "schema": {
              "type": "string",
              "examples": [
                "11199"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Store details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Store"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          }
        }
      }
    },
    "/api/products": {
      "get": {
        "operationId": "searchStoreProducts",
        "tags": [
          "products"
        ],
        "summary": "Search in-stock products inside one store",
        "description": "Searches the Daiso catalogue for `keyword`, keeps only products that are currently in stock at `branchCode`, and enriches each one with its shelf placement (floor and zone). Set `stream=1` to receive NDJSON progress events instead of a single JSON body, because a page can take several seconds to assemble.",
        "parameters": [
          {
            "name": "branchCode",
            "in": "query",
            "required": true,
            "description": "Store code from `searchStores`. `branchCd` is accepted as a legacy alias.",
            "schema": {
              "type": "string",
              "examples": [
                "11199"
              ]
            }
          },
          {
            "name": "keyword",
            "in": "query",
            "required": true,
            "description": "Product name to search for.",
            "schema": {
              "type": "string",
              "examples": [
                "수세미"
              ]
            }
          },
          {
            "name": "currentPage",
            "in": "query",
            "required": false,
            "description": "1-based page number of the catalogue scan.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "stream",
            "in": "query",
            "required": false,
            "description": "Set to `1` to stream NDJSON progress events. Equivalent to sending `Accept: application/x-ndjson`.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "In-stock products for the store. NDJSON when streaming was requested.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductSearchResult"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "$ref": "#/components/schemas/ProductStreamEvent"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/products/{id}": {
      "get": {
        "operationId": "getProductAvailability",
        "tags": [
          "products"
        ],
        "summary": "Get one product's stock and shelf placement",
        "description": "Returns the stock count and shelf placement of one product at `branchCode`, plus nearby stores that also have it in stock.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Daiso product number, as returned by `searchStoreProducts`.",
            "schema": {
              "type": "string",
              "examples": [
                "1019373"
              ]
            }
          },
          {
            "name": "branchCode",
            "in": "query",
            "required": true,
            "description": "Store code from `searchStores`. `branchCd` is accepted as a legacy alias.",
            "schema": {
              "type": "string",
              "examples": [
                "11199"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Product availability",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductAvailability"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api/sandbox/branches/search": {
      "get": {
        "operationId": "searchSandboxStores",
        "tags": [
          "stores"
        ],
        "summary": "Sandbox copy of searchStores",
        "description": "Same request and response shape as `searchStores`, answered from fixed fixture data without contacting the upstream Daiso service.",
        "parameters": [
          {
            "name": "keyword",
            "in": "query",
            "required": false,
            "description": "Any keyword. Fixture stores are filtered by substring match.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "curLttd",
            "in": "query",
            "required": false,
            "description": "Latitude. Accepted and ignored by the fixture.",
            "schema": {
              "type": "number",
              "format": "double"
            }
          },
          {
            "name": "curLitd",
            "in": "query",
            "required": false,
            "description": "Longitude. Accepted and ignored by the fixture.",
            "schema": {
              "type": "number",
              "format": "double"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fixture stores",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Store"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/api/sandbox/branches/{code}": {
      "get": {
        "operationId": "getSandboxStore",
        "tags": [
          "stores"
        ],
        "summary": "Sandbox copy of getStore",
        "description": "Returns a fixture store. Use `11199` for a hit and any other code for the 404 error shape.",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "description": "Fixture store code.",
            "schema": {
              "type": "string",
              "examples": [
                "11199"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fixture store",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Store"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/sandbox/products": {
      "get": {
        "operationId": "searchSandboxStoreProducts",
        "tags": [
          "products"
        ],
        "summary": "Sandbox copy of searchStoreProducts",
        "description": "Same response shape as `searchStoreProducts`, answered from fixture data. Requires `branchCode` and `keyword` so that the error shapes match production.",
        "parameters": [
          {
            "name": "branchCode",
            "in": "query",
            "required": true,
            "description": "Fixture store code.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "keyword",
            "in": "query",
            "required": true,
            "description": "Any keyword. Fixture products are filtered by substring match.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Fixture products",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductSearchResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/api/mcp": {
      "get": {
        "operationId": "getMcpServerInfo",
        "tags": [
          "meta"
        ],
        "summary": "MCP server metadata",
        "description": "Returns Model Context Protocol server metadata and the tool list. With `Accept: text/event-stream` it opens the Streamable HTTP server-to-client SSE stream instead.",
        "responses": {
          "200": {
            "description": "MCP server metadata",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpServerInfo"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "callMcp",
        "tags": [
          "meta"
        ],
        "summary": "MCP JSON-RPC endpoint (Streamable HTTP)",
        "description": "Model Context Protocol endpoint speaking JSON-RPC 2.0 over Streamable HTTP. Supports `initialize`, `tools/list`, and `tools/call`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "202": {
            "description": "Notification accepted; no response body."
          },
          "400": {
            "description": "Malformed JSON-RPC request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {},
    "schemas": {
      "Store": {
        "type": "object",
        "title": "Store",
        "description": "One Daiso store.",
        "required": [
          "code",
          "name",
          "lat",
          "lng",
          "address",
          "openTime",
          "closeTime"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Store code. Pass this as `branchCode` to the product endpoints.",
            "examples": [
              "11199"
            ]
          },
          "name": {
            "type": "string",
            "description": "Store name.",
            "examples": [
              "강남역점"
            ]
          },
          "lat": {
            "type": "number",
            "format": "double",
            "description": "Latitude."
          },
          "lng": {
            "type": "number",
            "format": "double",
            "description": "Longitude."
          },
          "address": {
            "type": "string",
            "description": "Street address in Korean.",
            "examples": [
              "서울특별시 강남구 강남대로 422 (역삼동)"
            ]
          },
          "openTime": {
            "type": "string",
            "description": "Opening time, HH:MM.",
            "examples": [
              "10:00"
            ]
          },
          "closeTime": {
            "type": "string",
            "description": "Closing time, HH:MM.",
            "examples": [
              "22:00"
            ]
          }
        }
      },
      "Product": {
        "type": "object",
        "title": "Product",
        "description": "A product that is in stock at the requested store.",
        "required": [
          "id",
          "name",
          "price",
          "image",
          "stock",
          "stairNo",
          "zoneNo"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Daiso product number."
          },
          "name": {
            "type": "string",
            "description": "Product name in Korean."
          },
          "price": {
            "type": "integer",
            "description": "Price in KRW."
          },
          "image": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Product image URL, or null when the catalogue has no image."
          },
          "stock": {
            "type": "integer",
            "minimum": 1,
            "description": "Units in stock at the requested store."
          },
          "stairNo": {
            "type": "integer",
            "description": "Floor number inside the store."
          },
          "zoneNo": {
            "type": "integer",
            "description": "Zone number on that floor."
          }
        }
      },
      "ProductSearchResult": {
        "type": "object",
        "title": "ProductSearchResult",
        "required": [
          "products",
          "hasMore",
          "nextPage"
        ],
        "properties": {
          "products": {
            "type": "array",
            "description": "In-stock products, in catalogue relevance order.",
            "items": {
              "$ref": "#/components/schemas/Product"
            }
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether more catalogue pages remain to scan."
          },
          "nextPage": {
            "type": "integer",
            "description": "Value to pass as `currentPage` for the next page."
          }
        }
      },
      "ProductStreamEvent": {
        "title": "ProductStreamEvent",
        "description": "One NDJSON line emitted while `stream=1`. Progress events repeat; exactly one `result` or `error` event ends the stream.",
        "oneOf": [
          {
            "type": "object",
            "title": "ProgressEvent",
            "required": [
              "type",
              "found",
              "target",
              "percent",
              "page",
              "scanned"
            ],
            "properties": {
              "type": {
                "const": "progress"
              },
              "found": {
                "type": "integer",
                "description": "In-stock products confirmed so far."
              },
              "target": {
                "type": "integer",
                "description": "Products wanted for this page."
              },
              "percent": {
                "type": "integer",
                "minimum": 0,
                "maximum": 100
              },
              "page": {
                "type": "integer",
                "description": "Catalogue page being scanned."
              },
              "scanned": {
                "type": "integer",
                "description": "Catalogue entries inspected so far."
              }
            }
          },
          {
            "type": "object",
            "title": "ResultEvent",
            "required": [
              "type",
              "products",
              "hasMore",
              "nextPage"
            ],
            "properties": {
              "type": {
                "const": "result"
              },
              "products": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Product"
                }
              },
              "hasMore": {
                "type": "boolean"
              },
              "nextPage": {
                "type": "integer"
              }
            }
          },
          {
            "type": "object",
            "title": "StreamErrorEvent",
            "required": [
              "type",
              "error"
            ],
            "properties": {
              "type": {
                "const": "error"
              },
              "error": {
                "type": "string"
              },
              "detail": {
                "type": "string"
              }
            }
          }
        ]
      },
      "ProductAvailability": {
        "type": "object",
        "title": "ProductAvailability",
        "required": [
          "stock",
          "stairNo",
          "zoneNo",
          "otherBranches"
        ],
        "properties": {
          "stock": {
            "type": "integer",
            "description": "Units in stock at the requested store. 0 means out of stock."
          },
          "stairNo": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Floor number, or null when placement is unknown."
          },
          "zoneNo": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Zone number, or null when placement is unknown."
          },
          "otherBranches": {
            "type": "array",
            "description": "Nearby stores that also have the product in stock.",
            "items": {
              "$ref": "#/components/schemas/NearbyStoreStock"
            }
          }
        }
      },
      "NearbyStoreStock": {
        "type": "object",
        "title": "NearbyStoreStock",
        "required": [
          "code",
          "name",
          "address",
          "stock",
          "distanceKm"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Store code."
          },
          "name": {
            "type": "string",
            "description": "Store name."
          },
          "address": {
            "type": "string",
            "description": "Street address in Korean."
          },
          "stock": {
            "type": "integer",
            "minimum": 1,
            "description": "Units in stock."
          },
          "distanceKm": {
            "type": [
              "number",
              "null"
            ],
            "description": "Distance from the requested store in kilometres."
          }
        }
      },
      "ApiIndex": {
        "type": "object",
        "title": "ApiIndex",
        "required": [
          "name",
          "description",
          "authentication",
          "endpoints",
          "documentation"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "authentication": {
            "type": "object",
            "required": [
              "type",
              "required"
            ],
            "properties": {
              "type": {
                "type": "string",
                "examples": [
                  "none"
                ]
              },
              "required": {
                "type": "boolean"
              },
              "signup": {
                "type": "string"
              }
            }
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "method",
                "path",
                "operationId",
                "description"
              ],
              "properties": {
                "method": {
                  "type": "string"
                },
                "path": {
                  "type": "string"
                },
                "operationId": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "documentation": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          }
        }
      },
      "McpServerInfo": {
        "type": "object",
        "title": "McpServerInfo",
        "required": [
          "serverInfo",
          "endpoint",
          "tools"
        ],
        "properties": {
          "serverInfo": {
            "type": "object",
            "required": [
              "name",
              "version"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              },
              "description": {
                "type": "string"
              }
            }
          },
          "endpoint": {
            "type": "string",
            "format": "uri"
          },
          "transport": {
            "type": "string",
            "examples": [
              "streamable-http"
            ]
          },
          "protocolVersion": {
            "type": "string"
          },
          "capabilities": {
            "type": "object",
            "additionalProperties": true
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "title": "JsonRpcRequest",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "method": {
            "type": "string",
            "examples": [
              "initialize",
              "tools/list",
              "tools/call"
            ]
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          },
          "id": {
            "type": [
              "string",
              "number",
              "null"
            ]
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "title": "JsonRpcResponse",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "result": {
            "type": "object",
            "additionalProperties": true
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {
                "additionalProperties": true
              }
            }
          },
          "id": {
            "type": [
              "string",
              "number",
              "null"
            ]
          }
        }
      },
      "Error": {
        "type": "object",
        "title": "Error",
        "description": "Every non-2xx response from this API uses this shape.",
        "required": [
          "error",
          "code",
          "message",
          "hint",
          "status",
          "documentation"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable message in Korean, for display to end users."
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code.",
            "enum": [
              "missing_parameter",
              "invalid_parameter",
              "not_found",
              "route_not_found",
              "method_not_allowed",
              "upstream_error",
              "internal_error"
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable message in English, for agents and logs."
          },
          "hint": {
            "type": "string",
            "description": "What to change in order to make the request succeed."
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code, repeated in the body."
          },
          "documentation": {
            "type": "string",
            "format": "uri",
            "description": "Developer documentation URL."
          },
          "detail": {
            "type": "string",
            "description": "Optional upstream or exception detail, for debugging."
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A required parameter is missing or malformed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such store, product, or route.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "UpstreamError": {
        "description": "The upstream Daiso service failed or rejected the request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}
