{"openapi":"3.0.0","info":{"title":"Bluby API","version":"1.0.0","description":"Connect with Bluby and access approved nutrition data."},"servers":[{"url":"https://api.blubyai.com"}],"components":{"schemas":{"HealthResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"service":{"type":"string","enum":["bluby-api"]}},"required":["status","service"]}},"required":["data"]},"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"}},"required":["code","message","requestId"]}},"required":["error"]},"ConnectStatusResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"status":{"type":"string"},"redirectUrl":{"type":"string"}},"required":["status"]}},"required":["data"]},"TokenResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"]},"expires_in":{"type":"number"},"refresh_token":{"type":"string"},"scope":{"type":"string"}},"required":["access_token","token_type","expires_in","scope"]}},"required":["data"]},"DataResponse":{"type":"object","properties":{"data":{"nullable":true}}},"FoodSearchResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/FoodItem"}}},"required":["items"]}},"required":["data"]},"FoodItem":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"barcode":{"type":"string"},"calories":{"type":"number"},"protein":{"type":"number"},"carbs":{"type":"number"},"fat":{"type":"number"},"processed":{"type":"string"},"source":{"type":"string"}},"required":["name","calories","protein","carbs","fat"]}},"parameters":{}},"paths":{"/health":{"get":{"responses":{"200":{"description":"API health","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/v1/connect":{"get":{"parameters":[{"schema":{"type":"string","minLength":1,"example":"early-access-client"},"required":true,"name":"client_id","in":"query"},{"schema":{"type":"string","minLength":1,"example":"https://example.com/callback"},"required":true,"name":"redirect_uri","in":"query"},{"schema":{"type":"string","minLength":1,"example":"food:read profile:read"},"required":true,"name":"scope","in":"query"},{"schema":{"type":"string"},"required":false,"name":"state","in":"query"},{"schema":{"type":"string"},"required":false,"name":"code_challenge","in":"query"},{"schema":{"type":"string","enum":["S256","plain"]},"required":false,"name":"code_challenge_method","in":"query"},{"schema":{"type":"string","example":"Example App"},"required":false,"name":"client_name","in":"query"}],"responses":{"200":{"description":"QR/manual-code approval page","content":{"text/html":{"schema":{"type":"string"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/connect/status":{"get":{"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"request_id","in":"query"}],"responses":{"200":{"description":"Current connect request status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectStatusResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/token":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["authorization_code"]},"client_id":{"type":"string"},"code":{"type":"string"},"code_verifier":{"type":"string"}},"required":["grant_type","client_id","code"]}}}},"responses":{"200":{"description":"Access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/token/refresh":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","enum":["refresh_token"]},"refresh_token":{"type":"string"}},"required":["grant_type","refresh_token"]}}}},"responses":{"200":{"description":"Refreshed access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/token/revoke":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]}}}},"responses":{"200":{"description":"Token revoked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/food/search":{"get":{"parameters":[{"schema":{"type":"string","minLength":1},"required":true,"name":"q","in":"query"},{"schema":{"type":"number","minimum":1,"maximum":50},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Food search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodSearchResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/food/barcode/{barcode}":{"get":{"parameters":[{"schema":{"type":"string","minLength":3},"required":true,"name":"barcode","in":"path"}],"responses":{"200":{"description":"Food item by barcode","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FoodSearchResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/me":{"get":{"responses":{"200":{"description":"/v1/me response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/me/profile":{"get":{"responses":{"200":{"description":"/v1/me/profile response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/me/meals":{"get":{"responses":{"200":{"description":"/v1/me/meals response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true}}}}},"responses":{"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"/v1/me/meals is reserved for the stable v1 write contract","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/me/pantry":{"get":{"responses":{"200":{"description":"/v1/me/pantry response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":{"nullable":true}}}}},"responses":{"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"/v1/me/pantry is reserved for the stable v1 write contract","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/v1/me/micronutrients":{"get":{"responses":{"200":{"description":"/v1/me/micronutrients response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Missing or invalid access token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Token is valid but not allowed for this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"501":{"description":"Endpoint is reserved but not implemented yet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}