uYao › Docs
uYao Developer Resources and Public API
uYao helps independent pharmacies in Taiwan turn shelf scans, expiry dates, and nearby medicine requests into work a pharmacist can approve. Store OS is a prototype, not a shipped replacement for a pharmacy counter, a POS, or the national insurance claim system.
This site does not sell medicine online. Catalog records are partner-listed product details, not live inventory, not a price, and not a promise that a pharmacy has the item today. A pharmacist confirms supply, substitution, pickup, and any medication question.
Nothing here is a diagnosis or medication advice. Dosage, suitability, and what to take stay with a licensed pharmacist. Prescription medicine is out of scope.
Public contact is email only: uyao@agentmail.to. There is no public street address or phone number on this site, and this page does not invent one.
What this site will not claim: No live stock, availability, or shelf count for any pharmacy. No diagnosis, prescription, or dosage recommendation. Store OS is a prototype. Treat demo work items as demonstration data. GET /api/catalog and GET /api/pharmacies repeat public page fields only.
uYao developer resources live at predictable first-party URLs: /docs, /openapi.json, and /llms.txt. The public read contract is two GET endpoints. Do not treat any other path on this host as a supported agent API.
GET /api/catalog returns partner-listed catalog records. Each response includes a disclaimer. The payload has product copy the catalog pages already render. It does not include price, stock, availability, or an inventory scan timestamp.
GET /api/pharmacies returns public pharmacy records assembled from Taiwan government open data. A listing is not a uYao partnership and not proof of stock. When hoursSource is nhi, those hours are National Health Insurance dispensing hours, not a promise the store is open.
Every public GET is rate limited per client IP. Successful responses and 429 responses send RateLimit-Policy and RateLimit using the current IETF HTTPAPI draft syntax; legacy RateLimit-Limit, RateLimit-Remaining, and RateLimit-Reset fields remain for compatibility. A 429 also sends Retry-After. Failures use RFC 9457 application/problem+json with type, title, status, detail, code, message, and resolution fields; the existing error field remains for compatibility.
API versioning uses the optional X-uYao-API-Version request header. Omit it for the current contract, or send 1.1.0 explicitly. Every response returns X-uYao-API-Version. Unsupported versions return a structured 400 problem.
No endpoint is deprecated today. The Link response header points to this policy without marking an endpoint deprecated. If a contract is retired, uYao will publish a migration path here, then send the standards-based Deprecation header and a Sunset date before removal.
Send Accept: application/json for JSON (the default) or Accept: text/markdown for a markdown rendering of the same records. Responses include Vary: Accept.
These GETs are not live inventory. They cannot diagnose. Store OS remains a prototype, so nothing in the catalog payload means a pharmacist has confirmed a sale.
Public GET endpoints
These two reads are the public contract. They are not live inventory. OpenAPI for just these paths is below; the host also serves the fuller /openapi.json, which marks site-form POST routes x-internal.
GET /api/catalog
Partner-listed catalog records. No price, stock, or availability field.
curl -sS https://uyaohealth.com/api/catalog
GET /api/pharmacies
Public pharmacy records from Taiwan open data. A listing is not stock.
curl -sS https://uyaohealth.com/api/pharmacies
Structured API errors
API failures use RFC 9457 application/problem+json. Every problem includes type, title, status,detail, code, message, and a machine-actionable resolution. The original errorcode remains for existing clients. Unknown /api/* paths use the same JSON format instead of an HTML app shell.
{
"type": "https://uyaohealth.com/docs#api-errors",
"title": "Unknown API endpoint",
"status": 404,
"code": "unknown_endpoint",
"message": "Unknown API endpoint",
"resolution": "Read /docs or /openapi.json and use a documented endpoint."
}Versioning and deprecation
Send X-uYao-API-Version: 1.1.0 to pin the current contract, or omit it to use the current version. Every public API response returns that header. Unsupported versions return a structured 400 problem.
No endpoint is deprecated today. The response Link header makes this policy discoverable and does not itself mark a resource as deprecated. Before removing a version, uYao will publish a migration path here, send a standards-based Deprecation header, and announce the removal date with Sunset.
OpenAPI (these two GETs only)
{
"openapi": "3.1.0",
"info": {
"title": "uYao public read API",
"version": "1.1.0",
"summary": "GET /api/catalog and GET /api/pharmacies only. Not live inventory.",
"description": "Public read contract for agents. Two GET endpoints.\n\n- uYao has no live inventory for any pharmacy. This API never returns price, stock, or availability, and no response may be presented as confirmed stock.\n- These responses repeat fields the catalog and pharmacy pages already render.\n- They are not a diagnosis API and not a Store OS control plane. Store OS is a prototype.\n- Site-form POST endpoints exist on this host for humans; they are not part of this document.\n- Clients may send X-uYao-API-Version: 1.1.0. Omitting the header selects the current version for backward compatibility. Every response returns the selected version. Before a version is retired, uYao will publish the migration path at /docs and signal it with the Deprecation and Sunset response headers.",
"contact": {
"email": "uyao@agentmail.to",
"url": "https://uyaohealth.com/en"
},
"license": {
"name": "Catalog and pharmacy data are published for reference; attribute uYao when reused.",
"url": "https://uyaohealth.com/en/evidence"
}
},
"servers": [
{
"url": "https://shop.uyaohealth.com",
"description": "Consumer host. Serves the catalog and pharmacy endpoints."
},
{
"url": "https://uyaohealth.com",
"description": "Company host. Same API surface."
}
],
"externalDocs": {
"url": "https://uyaohealth.com/docs",
"description": "Human-readable notes for these two GETs"
},
"tags": [
{
"name": "catalog",
"description": "Partner-listed catalog items. Read-only. Not live inventory."
},
{
"name": "pharmacies",
"description": "Public pharmacy records. Read-only. Not live inventory."
}
],
"paths": {
"/api/catalog": {
"get": {
"tags": [
"catalog"
],
"operationId": "listCatalog",
"summary": "List every catalog item",
"description": "Returns the catalog records partner pharmacies provided. uYao has no live inventory for any pharmacy. This API never returns price, stock, or availability, and no response may be presented as confirmed stock. Cached at the edge for one hour and CORS-open. No authentication and no cookies. Rate-limited per client IP; successful and quota-checked error responses carry RateLimit-Policy and RateLimit using the current IETF HTTPAPI draft syntax, plus legacy compatibility fields. A 429 also carries Retry-After. The response contains only data these pages already render publicly.",
"parameters": [
{
"name": "X-uYao-API-Version",
"in": "header",
"required": false,
"description": "Optional API contract version. Omit it to use the current 1.1.0 contract. Unsupported values return an RFC 9457 JSON problem.",
"schema": {
"type": "string",
"enum": [
"1.1.0"
],
"default": "1.1.0"
}
},
{
"name": "locale",
"in": "query",
"required": false,
"description": "Response language. Anything other than `en` returns Traditional Chinese.",
"schema": {
"type": "string",
"enum": [
"zh",
"en"
],
"default": "zh"
}
}
],
"responses": {
"200": {
"description": "The full catalog. Not live inventory.",
"headers": {
"X-uYao-API-Version": {
"schema": {
"type": "string",
"enum": [
"1.1.0"
]
},
"description": "The API contract version used for this response."
},
"Link": {
"schema": {
"type": "string"
},
"description": "Link to the versioning and deprecation policy. This link alone does not mean the endpoint is deprecated."
},
"RateLimit-Policy": {
"schema": {
"type": "string",
"example": "\"public-read\";q=120;w=3600"
},
"description": "Stable public-read quota policy using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit": {
"schema": {
"type": "string",
"example": "\"public-read\";r=119;t=3600"
},
"description": "Remaining public-read quota and effective window using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit-Limit": {
"schema": {
"type": "integer",
"example": 120
},
"description": "Legacy compatibility field: request quota for the window."
},
"RateLimit-Remaining": {
"schema": {
"type": "integer",
"example": 119
},
"description": "Legacy compatibility field: requests remaining in the window."
},
"RateLimit-Reset": {
"schema": {
"type": "integer",
"example": 3600
},
"description": "Legacy compatibility field: seconds until the quota window resets."
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/CatalogList"
}
},
"text/markdown": {
"schema": {
"type": "string"
}
}
}
},
"400": {
"description": "Unsupported API version. RFC 9457 JSON problem.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Rate limited. JSON error body plus RateLimit headers.",
"headers": {
"X-uYao-API-Version": {
"schema": {
"type": "string",
"enum": [
"1.1.0"
]
},
"description": "The API contract version used for this response."
},
"Link": {
"schema": {
"type": "string"
},
"description": "Link to the versioning and deprecation policy. This link alone does not mean the endpoint is deprecated."
},
"RateLimit-Policy": {
"schema": {
"type": "string",
"example": "\"public-read\";q=120;w=3600"
},
"description": "Stable public-read quota policy using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit": {
"schema": {
"type": "string",
"example": "\"public-read\";r=119;t=3600"
},
"description": "Remaining public-read quota and effective window using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit-Limit": {
"schema": {
"type": "integer",
"example": 120
},
"description": "Legacy compatibility field: request quota for the window."
},
"RateLimit-Remaining": {
"schema": {
"type": "integer",
"example": 119
},
"description": "Legacy compatibility field: requests remaining in the window."
},
"RateLimit-Reset": {
"schema": {
"type": "integer",
"example": 3600
},
"description": "Legacy compatibility field: seconds until the quota window resets."
},
"Retry-After": {
"schema": {
"type": "integer",
"example": 3600
},
"description": "Seconds the client should wait before retrying after a 429 response."
}
},
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
},
"/api/pharmacies": {
"get": {
"tags": [
"pharmacies"
],
"operationId": "listPharmacies",
"summary": "List public pharmacy records",
"description": "Pharmacy records assembled from Taiwan government open data. The pharmacist-in-charge name is deliberately not exposed. When `hoursSource` is `nhi`, hours are National Health Insurance dispensing hours and are not store opening hours. Cached at the edge for one hour and CORS-open. No authentication and no cookies. Rate-limited per client IP; successful and quota-checked error responses carry RateLimit-Policy and RateLimit using the current IETF HTTPAPI draft syntax, plus legacy compatibility fields. A 429 also carries Retry-After. The response contains only data these pages already render publicly.",
"parameters": [
{
"name": "area",
"in": "query",
"required": false,
"description": "Restrict to one service area.",
"schema": {
"type": "string",
"enum": [
"datong",
"linkou",
"luzhou",
"xinzhuang",
"zhongshan",
"shilin",
"xitun",
"miaoli",
"yilan",
"luodong"
]
}
},
{
"name": "X-uYao-API-Version",
"in": "header",
"required": false,
"description": "Optional API contract version. Omit it to use the current 1.1.0 contract. Unsupported values return an RFC 9457 JSON problem.",
"schema": {
"type": "string",
"enum": [
"1.1.0"
],
"default": "1.1.0"
}
},
{
"name": "locale",
"in": "query",
"required": false,
"description": "Response language. Anything other than `en` returns Traditional Chinese.",
"schema": {
"type": "string",
"enum": [
"zh",
"en"
],
"default": "zh"
}
}
],
"responses": {
"200": {
"description": "Matching pharmacy records.",
"headers": {
"X-uYao-API-Version": {
"schema": {
"type": "string",
"enum": [
"1.1.0"
]
},
"description": "The API contract version used for this response."
},
"Link": {
"schema": {
"type": "string"
},
"description": "Link to the versioning and deprecation policy. This link alone does not mean the endpoint is deprecated."
},
"RateLimit-Policy": {
"schema": {
"type": "string",
"example": "\"public-read\";q=120;w=3600"
},
"description": "Stable public-read quota policy using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit": {
"schema": {
"type": "string",
"example": "\"public-read\";r=119;t=3600"
},
"description": "Remaining public-read quota and effective window using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit-Limit": {
"schema": {
"type": "integer",
"example": 120
},
"description": "Legacy compatibility field: request quota for the window."
},
"RateLimit-Remaining": {
"schema": {
"type": "integer",
"example": 119
},
"description": "Legacy compatibility field: requests remaining in the window."
},
"RateLimit-Reset": {
"schema": {
"type": "integer",
"example": 3600
},
"description": "Legacy compatibility field: seconds until the quota window resets."
}
},
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PharmacyList"
}
}
}
},
"400": {
"description": "Unknown area slug. JSON error body.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Rate limited. JSON error body plus RateLimit headers.",
"headers": {
"X-uYao-API-Version": {
"schema": {
"type": "string",
"enum": [
"1.1.0"
]
},
"description": "The API contract version used for this response."
},
"Link": {
"schema": {
"type": "string"
},
"description": "Link to the versioning and deprecation policy. This link alone does not mean the endpoint is deprecated."
},
"RateLimit-Policy": {
"schema": {
"type": "string",
"example": "\"public-read\";q=120;w=3600"
},
"description": "Stable public-read quota policy using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit": {
"schema": {
"type": "string",
"example": "\"public-read\";r=119;t=3600"
},
"description": "Remaining public-read quota and effective window using the current IETF HTTPAPI RateLimit draft syntax."
},
"RateLimit-Limit": {
"schema": {
"type": "integer",
"example": 120
},
"description": "Legacy compatibility field: request quota for the window."
},
"RateLimit-Remaining": {
"schema": {
"type": "integer",
"example": 119
},
"description": "Legacy compatibility field: requests remaining in the window."
},
"RateLimit-Reset": {
"schema": {
"type": "integer",
"example": 3600
},
"description": "Legacy compatibility field: seconds until the quota window resets."
},
"Retry-After": {
"schema": {
"type": "integer",
"example": 3600
},
"description": "Seconds the client should wait before retrying after a 429 response."
}
},
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"Error": {
"type": "object",
"description": "RFC 9457 problem details with stable uYao compatibility fields and a machine-actionable resolution hint.",
"properties": {
"type": {
"type": "string",
"format": "uri-reference"
},
"title": {
"type": "string"
},
"status": {
"type": "integer",
"minimum": 400,
"maximum": 599
},
"detail": {
"type": "string"
},
"error": {
"type": "string",
"description": "Backward-compatible stable error code."
},
"code": {
"type": "string",
"description": "Stable machine-readable error code."
},
"message": {
"type": "string",
"description": "Short human-readable error summary."
},
"resolution": {
"type": "string",
"description": "Action the caller can take to resolve the error."
}
},
"required": [
"type",
"title",
"status",
"detail",
"error",
"code",
"message",
"resolution"
]
},
"ResponseEnvelope": {
"type": "object",
"properties": {
"version": {
"type": "string",
"description": "Payload shape version."
},
"locale": {
"type": "string",
"enum": [
"zh",
"en"
]
},
"disclaimer": {
"type": "string",
"description": "Boundary text that must survive any summary of this response. Present on every read response."
}
},
"required": [
"version",
"locale",
"disclaimer"
]
},
"CatalogList": {
"allOf": [
{
"$ref": "#/components/schemas/ResponseEnvelope"
},
{
"type": "object",
"properties": {
"count": {
"type": "integer"
},
"items": {
"type": "array",
"items": {
"$ref": "#/components/schemas/CatalogItem"
}
}
},
"required": [
"count",
"items"
]
}
]
},
"CatalogItem": {
"type": "object",
"description": "A catalog record. Carries no price, stock, or availability, by design.",
"properties": {
"slug": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri",
"description": "Canonical page for this item."
},
"name": {
"type": "string"
},
"catalogRecordUpdatedOn": {
"type": "string",
"format": "date",
"description": "Date when this catalog record's public product content last changed. This is not an inventory scan timestamp, stock freshness signal, or availability confirmation."
},
"nameEn": {
"type": "string",
"description": "Present only when a real English product name exists."
},
"form": {
"type": "string"
},
"spec": {
"type": "string"
},
"drugClass": {
"type": "string",
"description": "Regulatory class. `待確認` / `Classification pending` means public data cannot determine it; it is never guessed."
},
"category": {
"type": "string"
},
"ingredients": {
"type": "array",
"items": {
"type": "string"
}
},
"nutritionFocus": {
"type": "string",
"description": "Everyday nutrition positioning. Not an approved indication and not a treatment claim."
},
"manufacturer": {
"type": "string"
},
"origin": {
"type": "string"
},
"licenseNo": {
"type": "string",
"description": "Ministry of Health and Welfare licence number. Omitted rather than guessed when unknown."
},
"image": {
"type": "object",
"properties": {
"url": {
"type": "string",
"format": "uri"
},
"kind": {
"type": "string",
"enum": [
"illustration",
"packshot"
],
"description": "`illustration` is a generated image and does not depict real packaging. `packshot` is a real photograph."
},
"alt": {
"type": "string"
}
},
"required": [
"url",
"kind",
"alt"
]
},
"source": {
"type": "object",
"description": "Where the product details came from.",
"properties": {
"label": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"kind": {
"type": "string",
"enum": [
"public",
"partner"
]
}
},
"required": [
"label"
]
}
},
"required": [
"slug",
"url",
"name",
"catalogRecordUpdatedOn",
"form",
"spec",
"drugClass",
"category",
"ingredients",
"nutritionFocus"
]
},
"PharmacyList": {
"allOf": [
{
"$ref": "#/components/schemas/ResponseEnvelope"
},
{
"type": "object",
"properties": {
"count": {
"type": "integer"
},
"pharmacies": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Pharmacy"
}
}
},
"required": [
"count",
"pharmacies"
]
}
]
},
"Pharmacy": {
"type": "object",
"description": "A public pharmacy record. The pharmacist-in-charge name is deliberately not exposed.",
"properties": {
"slug": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"name": {
"type": "string"
},
"area": {
"type": "string",
"enum": [
"datong",
"linkou",
"luzhou",
"xinzhuang",
"zhongshan",
"shilin",
"xitun",
"miaoli",
"yilan",
"luodong"
]
},
"district": {
"type": "string"
},
"address": {
"type": "string"
},
"phone": {
"type": "string"
},
"nhiCode": {
"type": [
"string",
"null"
],
"description": "National Health Insurance institution code. Stable across renames."
},
"nhiContracted": {
"type": "boolean"
},
"businessStatus": {
"type": [
"string",
"null"
],
"description": "Google business status. Anything other than `OPERATIONAL` needs care."
},
"hoursSource": {
"type": "string",
"enum": [
"google",
"nhi",
"partner",
"none"
],
"description": "`nhi` means National Health Insurance dispensing hours, which are not store opening hours. Never present them as a guarantee that the pharmacy is open."
},
"hours": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string"
},
"hours": {
"type": "string"
}
},
"required": [
"label",
"hours"
]
}
},
"mapsUrl": {
"type": "string",
"format": "uri"
},
"location": {
"type": [
"object",
"null"
],
"properties": {
"lat": {
"type": "number"
},
"lng": {
"type": "number"
}
},
"required": [
"lat",
"lng"
]
}
},
"required": [
"slug",
"url",
"name",
"area",
"district",
"address",
"nhiCode",
"nhiContracted",
"businessStatus",
"hoursSource",
"hours",
"mapsUrl",
"location"
]
}
}
}
}