{"openapi":"3.1.0","info":{"title":"Albion Market API","description":"Public JSON API for Albion Online market search, prices, Black Market arbitrage, and city-to-city routes.\n\n## Authentication\nThis API does not require authentication. Do not send an `Authorization` header.\n\n## Rate limiting\n- **Limit**: 100 requests per minute per client\n- **Headers**: `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (seconds remaining, not a Unix timestamp)\n- **429 body**: `{ error, code: RATE_LIMITED, retryAfter }` plus `Retry-After`\n\n## Agent workflow\n1. `GET /api/items?q=bag` to resolve a display name to a unique item id (`T4_BAG`).\n2. `GET /api/prices?items=T4_BAG&server=west` for raw city/quality prices.\n3. `GET /api/arbitrage?item=T4_BAG` or `GET /api/routes?item=T4_BAG` for computed trades.\n\nBranch on machine-readable `code`, not English `error` text. On `ITEM_NOT_FOUND`, retry with `suggestion` or search `/api/items`.\n\nDiscovery: `/llms.txt`, `/llms-full.txt`, `/openapi.json`, `/api-docs`.","version":"0.11.0","contact":{"name":"Albion Market","url":"https://github.com/decoge/albion-market","email":"security@decoge.dev"},"license":{"name":"MIT","url":"https://github.com/decoge/albion-market/blob/main/LICENSE"}},"externalDocs":{"description":"Human API guide and Albion Online Data Project upstream docs","url":"https://albion-market.onlinetools.directory/api-docs"},"servers":[{"url":"http://localhost:3000","description":"Local development server"},{"url":"https://albion-market.onlinetools.directory","description":"Production environment"}],"security":[],"tags":[{"name":"Health","description":"Health check and documentation links","x-displayName":"Health"},{"name":"Items","description":"Item index search by name or unique id","x-displayName":"Items"},{"name":"Prices","description":"First-class market price collection","x-displayName":"Market prices"},{"name":"Arbitrage","description":"Buy-low / sell-high opportunities across cities","x-displayName":"Arbitrage"},{"name":"Routes","description":"City-to-city trading routes with fees and distance","x-displayName":"Routes"},{"name":"Proxy","description":"Low-level Albion Online Data API proxy used by the web UI","x-displayName":"Market data proxy"}],"paths":{"/api/health":{"get":{"tags":["Health"],"summary":"Get API health status","description":"Returns process health, application version, and links to OpenAPI / llms.txt. No query parameters.","operationId":"getHealth","x-displayName":"Get health","security":[],"responses":{"200":{"description":"API is healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"},"examples":{"ok":{"summary":"Healthy response","value":{"status":"ok","version":"0.11.0","timestamp":"2026-08-27T20:00:00.000Z","uptime":123.45,"docs":{"openapi":"/openapi.json","llms":"/llms.txt","llmsFull":"/llms-full.txt","human":"/api-docs"}}}}}},"headers":{"X-Response-Time":{"description":"Response time in milliseconds","schema":{"type":"string","pattern":"^\\d+ms$","example":"1ms"}},"Cache-Control":{"description":"Health responses must not be cached","schema":{"type":"string","example":"no-cache, no-store, must-revalidate"}}}},"500":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Health check failed","code":"HEALTH_CHECK_FAILED"}}}}}}},"/api/items":{"get":{"tags":["Items"],"summary":"Search the item index by name","description":"Resolves a player-facing name (or a unique id substring match on the display name) to catalog entries. Does not call the Albion Data API. Use the returned `id` values with `/api/prices`, `/api/arbitrage`, and `/api/routes`. Default `limit` is 10 (max 25). When nothing matches, `items` is empty and `suggestion` may contain a close spelling.","operationId":"searchItems","x-displayName":"Search items","security":[],"parameters":[{"name":"q","in":"query","required":true,"description":"Case-insensitive substring match against item display names.","schema":{"type":"string","minLength":1,"example":"bag"},"example":"bag"},{"name":"limit","in":"query","required":false,"description":"Page size. Defaults to 10. Maximum 25.","schema":{"type":"integer","minimum":1,"maximum":25,"default":10},"example":10},{"name":"offset","in":"query","required":false,"description":"Zero-based offset. Defaults to 0.","schema":{"type":"integer","minimum":0,"default":0},"example":0}],"responses":{"200":{"description":"Matching catalog items","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemSearchResponse"},"example":{"query":"bag","count":1,"limit":10,"offset":0,"items":[{"id":"T4_BAG","name":"Adept's Bag","tier":4,"enchantment":0,"icon":"https://render.albiononline.com/v1/item/T4_BAG.png"}],"suggestion":null}}},"headers":{"X-Total-Count":{"description":"Total rows before pagination","schema":{"type":"integer","example":40}},"X-Limit":{"description":"Page size applied to this response","schema":{"type":"integer","example":10}},"X-Offset":{"description":"Offset applied to this response","schema":{"type":"integer","example":0}},"X-RateLimit-Limit":{"description":"Requests per minute limit","schema":{"type":"integer","example":100}},"X-RateLimit-Remaining":{"description":"Remaining requests in the current window","schema":{"type":"integer","example":95}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":60}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Missing q parameter","code":"MISSING_QUERY","details":[{"field":"q","message":"Missing q parameter"}]}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Too many requests. Please wait a moment before searching again. Consider refining your search to be more specific.","code":"RATE_LIMITED","retryAfter":30}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":30}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":30}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Item index is temporarily unavailable. Retry shortly.","code":"ITEM_INDEX_UNAVAILABLE"}}}}}}},"/api/prices":{"get":{"tags":["Prices"],"summary":"List market prices for items","description":"Preferred collection endpoint for raw market prices. Builds an allowlisted Albion Data API request from structured query parameters.\n\n**Batch:** comma-separated unique names in `items` (for example `T4_BAG,T8_SWORD@3`).\n\n**Pagination:** `limit` defaults to 100 (max 500).\n\nSuccess body is a JSON array of `MarketPriceEntry` (snake_case, matching upstream).","operationId":"listMarketPrices","x-displayName":"List market prices","security":[],"externalDocs":{"description":"Albion Online Data Project prices API","url":"https://www.albion-online-data.com/api/"},"parameters":[{"name":"items","in":"query","required":true,"description":"Comma-separated Albion unique item names (not numeric IDs). Example: `T4_BAG`, `T8_SWORD@3`.","style":"form","explode":false,"schema":{"type":"array","minItems":1,"items":{"type":"string","pattern":"^[A-Za-z0-9_@.\\-]+$","example":"T4_BAG"}},"examples":{"single":{"summary":"One item","value":["T4_BAG"]},"batch":{"summary":"Several items","value":["T4_BAG","T5_BAG","T8_SWORD@3"]}}},{"name":"server","in":"query","required":true,"description":"Albion shard to query","schema":{"type":"string","enum":["europe","east","west"]},"example":"west"},{"name":"locations","in":"query","required":false,"description":"Comma-separated city names. Omit for all cities.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/CityName"}},"example":["Caerleon","Bridgewatch"]},{"name":"qualities","in":"query","required":false,"description":"Comma-separated quality levels. 1=Normal … 5=Masterpiece. Omit for all qualities.","style":"form","explode":false,"schema":{"type":"array","items":{"$ref":"#/components/schemas/QualityLevel"}},"example":[1,2]},{"name":"limit","in":"query","required":false,"description":"Page size. Defaults to 100. Maximum 500.","schema":{"type":"integer","minimum":1,"maximum":500,"default":100},"example":100},{"name":"offset","in":"query","required":false,"description":"Zero-based offset. Defaults to 0.","schema":{"type":"integer","minimum":0,"default":0},"example":0}],"responses":{"200":{"description":"Page of market prices. `X-Total-Count` is the unpaginated row count.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketPriceEntry"}},"example":[{"item_id":"T4_BAG","city":"Caerleon","quality":1,"sell_price_min":5200,"sell_price_min_date":"2026-07-07T00:00:00.000Z","sell_price_max":5500,"sell_price_max_date":"2026-07-07T00:00:00.000Z","buy_price_min":5000,"buy_price_min_date":"2026-07-07T00:00:00.000Z","buy_price_max":5100,"buy_price_max_date":"2026-07-07T00:00:00.000Z"}]}},"headers":{"Cache-Control":{"description":"Market data is cacheable for 5 minutes","schema":{"type":"string","example":"public, max-age=300"}},"X-Total-Count":{"description":"Total rows before pagination","schema":{"type":"integer","example":40}},"X-Limit":{"description":"Page size applied to this response","schema":{"type":"integer","example":10}},"X-Offset":{"description":"Offset applied to this response","schema":{"type":"integer","example":0}},"X-RateLimit-Limit":{"description":"Requests per minute limit","schema":{"type":"integer","example":100}},"X-RateLimit-Remaining":{"description":"Remaining requests in the current window","schema":{"type":"integer","example":95}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":60}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Missing items parameter","code":"MISSING_ITEMS","details":[{"field":"items","message":"Missing items parameter"}]}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Too many requests. Please wait a moment before searching again. Consider refining your search to be more specific.","code":"RATE_LIMITED","retryAfter":30}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":30}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":30}}}},"500":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Failed to fetch data from remote server","code":"UPSTREAM_ERROR"}}}},"504":{"description":"Upstream request timed out. Wait `retryAfter` seconds, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryableError"},"example":{"error":"Request timeout","code":"UPSTREAM_TIMEOUT","retryAfter":10}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":10}}}}}}},"/api/arbitrage":{"get":{"tags":["Arbitrage"],"summary":"List buy-low / sell-high opportunities","description":"Computes the lowest sell order vs highest buy order per server and quality for one item. `item` may be a unique name (`T4_BAG`) or a display-name search (`adept bag`). `servers` defaults to all shards (`west,east,europe`). Default `limit` is 10 (max 50). Sorted by profit descending.","operationId":"listArbitrageOpportunities","x-displayName":"List arbitrage opportunities","security":[],"parameters":[{"name":"item","in":"query","required":true,"description":"Unique item name or display name to resolve via the item index.","schema":{"type":"string","minLength":1,"example":"T4_BAG"},"example":"T4_BAG"},{"name":"servers","in":"query","required":false,"description":"Comma-separated shards, or `all`. Defaults to all servers.","schema":{"type":"string","example":"west,europe"},"example":"west"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"example":10},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"example":0}],"responses":{"200":{"description":"Arbitrage quotes for the resolved item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArbitrageResponse"},"example":{"item":{"id":"T4_BAG","name":"Adept's Bag","tier":4,"enchantment":0,"icon":"https://render.albiononline.com/v1/item/T4_BAG.png"},"count":1,"limit":10,"offset":0,"opportunities":[{"server":"west","quality":1,"qualityLabel":"Normal","buyCity":"Caerleon","sellCity":"Black Market","buyPrice":5200,"sellPrice":8000,"profit":2800,"marginPercent":53.846}]}}},"headers":{"X-Total-Count":{"description":"Total rows before pagination","schema":{"type":"integer","example":40}},"X-Limit":{"description":"Page size applied to this response","schema":{"type":"integer","example":10}},"X-Offset":{"description":"Offset applied to this response","schema":{"type":"integer","example":0}},"X-RateLimit-Limit":{"description":"Requests per minute limit","schema":{"type":"integer","example":100}},"X-RateLimit-Remaining":{"description":"Remaining requests in the current window","schema":{"type":"integer","example":95}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":60}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Missing item parameter","code":"MISSING_ITEM","details":[{"field":"item","message":"Missing item parameter"}]}}}},"404":{"description":"Item not found. Retry with `suggestion` or search `/api/items`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"No matching item found. Search with GET /api/items?q= or pass an exact unique name such as T4_BAG.","code":"ITEM_NOT_FOUND","details":[{"field":"item","message":"No item matched \"beg\". Use GET /api/items?q= to search by name."}],"suggestion":"Adept's Bag"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Too many requests. Please wait a moment before searching again. Consider refining your search to be more specific.","code":"RATE_LIMITED","retryAfter":30}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":30}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":30}}}},"500":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Failed to fetch data from remote server","code":"UPSTREAM_ERROR"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Item index is temporarily unavailable. Retry shortly.","code":"ITEM_INDEX_UNAVAILABLE"}}}},"504":{"description":"Upstream request timed out. Wait `retryAfter` seconds, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryableError"},"example":{"error":"Request timeout","code":"UPSTREAM_TIMEOUT","retryAfter":10}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":10}}}}}}},"/api/routes":{"get":{"tags":["Routes"],"summary":"List city-to-city trading routes","description":"Computes profitable origin → destination hops for one item, including follow-up `chains`. `item` may be a unique name or display name. `origin` limits results to one starting city. `feeRate` is a percent (0–100, default 0). `sort` is `profit` (default), `margin`, or `distance`. Default `limit` is 10 (max 50).","operationId":"listTradingRoutes","x-displayName":"List trading routes","security":[],"parameters":[{"name":"item","in":"query","required":true,"description":"Unique item name or display name.","schema":{"type":"string","minLength":1,"example":"T4_BAG"},"example":"T4_BAG"},{"name":"servers","in":"query","required":false,"description":"Comma-separated shards, or `all`. Defaults to all servers.","schema":{"type":"string","example":"europe"},"example":"europe"},{"name":"origin","in":"query","required":false,"description":"Starting city. One of: Brecilien, Bridgewatch, Caerleon, Fort Sterling, Lymhurst, Martlock, Thetford.","schema":{"type":"string","enum":["Brecilien","Bridgewatch","Caerleon","Fort Sterling","Lymhurst","Martlock","Thetford"],"example":"Caerleon"},"example":"Caerleon"},{"name":"qualities","in":"query","required":false,"description":"Comma-separated quality levels (1–5). Omit for all.","schema":{"type":"string","example":"1,2"},"example":"1"},{"name":"minProfit","in":"query","required":false,"description":"Minimum net profit in silver. Defaults to 0.","schema":{"type":"number","minimum":0,"default":0,"example":1000},"example":1000},{"name":"maxDistance","in":"query","required":false,"description":"Maximum hop distance in km. Defaults to 50.","schema":{"type":"number","minimum":0,"default":50,"example":50},"example":50},{"name":"feeRate","in":"query","required":false,"description":"Market tax percent applied to raw profit. Defaults to 0.","schema":{"type":"number","minimum":0,"maximum":100,"default":0,"example":3},"example":3},{"name":"sort","in":"query","required":false,"description":"Sort key for the result list.","schema":{"type":"string","enum":["profit","margin","distance"],"default":"profit"},"example":"profit"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"example":10},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"example":0}],"responses":{"200":{"description":"Processed trading routes for the resolved item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutesResponse"},"example":{"item":{"id":"T4_BAG","name":"Adept's Bag","tier":4,"enchantment":0,"icon":"https://render.albiononline.com/v1/item/T4_BAG.png"},"count":1,"limit":10,"offset":0,"origin":"Caerleon","feeRate":3,"routes":[{"originCity":"Caerleon","destinationCity":"Thetford","quality":1,"qualityLabel":"Normal","buyPrice":5200,"sellPrice":8000,"rawProfit":2800,"netProfit":2716,"marginPercent":53.846,"distance":22,"server":"europe","chains":[]}]}}},"headers":{"X-Total-Count":{"description":"Total rows before pagination","schema":{"type":"integer","example":40}},"X-Limit":{"description":"Page size applied to this response","schema":{"type":"integer","example":10}},"X-Offset":{"description":"Offset applied to this response","schema":{"type":"integer","example":0}},"X-RateLimit-Limit":{"description":"Requests per minute limit","schema":{"type":"integer","example":100}},"X-RateLimit-Remaining":{"description":"Remaining requests in the current window","schema":{"type":"integer","example":95}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":60}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid origin parameter","code":"INVALID_ORIGIN","details":[{"field":"origin","message":"Must be one of: Brecilien, Bridgewatch, Caerleon, Fort Sterling, Lymhurst, Martlock, Thetford"}]}}}},"404":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"No matching item found. Search with GET /api/items?q= or pass an exact unique name such as T4_BAG.","code":"ITEM_NOT_FOUND"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Too many requests. Please wait a moment before searching again. Consider refining your search to be more specific.","code":"RATE_LIMITED","retryAfter":30}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":30}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":30}}}},"500":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Failed to fetch data from remote server","code":"UPSTREAM_ERROR"}}}},"503":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Item index is temporarily unavailable. Retry shortly.","code":"ITEM_INDEX_UNAVAILABLE"}}}},"504":{"description":"Upstream request timed out. Wait `retryAfter` seconds, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryableError"},"example":{"error":"Request timeout","code":"UPSTREAM_TIMEOUT","retryAfter":10}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":10}}}}}}},"/api/proxy":{"get":{"tags":["Proxy"],"summary":"Fetch market data from Albion Online Data API","description":"Low-level proxy used by the web UI. **Deprecated:** agents should call `listMarketPrices` (`GET /api/prices`) instead of assembling a raw upstream URL.","operationId":"getMarketData","x-displayName":"Proxy market data","deprecated":true,"security":[],"parameters":[{"name":"url","in":"query","required":true,"description":"Full HTTPS Albion Online Data API prices URL.","schema":{"type":"string","format":"uri","pattern":"^https://(west|east|europe|www)\\.albion-online-data\\.com/api/v2/stats/prices.*","example":"https://west.albion-online-data.com/api/v2/stats/prices/T4_BAG?locations=Caerleon&qualities=1"},"example":"https://west.albion-online-data.com/api/v2/stats/prices/T4_BAG?locations=Caerleon&qualities=1"},{"name":"limit","in":"query","required":false,"description":"Optional page size (1–500). Omit to return the complete result set.","schema":{"type":"integer","minimum":1,"maximum":500},"example":100},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"example":0}],"responses":{"200":{"description":"Market data array of MarketPriceEntry","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MarketPriceEntry"}}}},"headers":{"X-Total-Count":{"description":"Total rows before pagination","schema":{"type":"integer","example":40}},"X-Limit":{"description":"Page size applied to this response","schema":{"type":"integer","example":10}},"X-Offset":{"description":"Offset applied to this response","schema":{"type":"integer","example":0}},"X-RateLimit-Limit":{"description":"Requests per minute limit","schema":{"type":"integer","example":100}},"X-RateLimit-Remaining":{"description":"Remaining requests in the current window","schema":{"type":"integer","example":95}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":60}}}},"400":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Missing url parameter","code":"MISSING_URL","details":[{"field":"url","message":"Missing url parameter"}]}}}},"403":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid request. This indicates a configuration issue. Please report this if it persists.","code":"HOST_NOT_ALLOWED"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"},"example":{"error":"Too many requests. Please wait a moment before searching again. Consider refining your search to be more specific.","code":"RATE_LIMITED","retryAfter":30}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":30}},"X-RateLimit-Reset":{"description":"Seconds until the current rate limit window resets","schema":{"type":"integer","example":30}}}},"500":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Failed to fetch data from remote server","code":"UPSTREAM_ERROR"}}}},"504":{"description":"Upstream request timed out. Wait `retryAfter` seconds, then retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryableError"},"example":{"error":"Request timeout","code":"UPSTREAM_TIMEOUT","retryAfter":10}}},"headers":{"Retry-After":{"description":"Seconds until retry is allowed","schema":{"type":"integer","example":10}}}}}}}},"components":{"schemas":{"CityName":{"type":"string","description":"Trade city or Black Market","enum":["Black Market","Brecilien","Bridgewatch","Caerleon","Fort Sterling","Lymhurst","Martlock","Thetford"],"example":"Caerleon"},"QualityLevel":{"type":"integer","description":"Item quality (1=Normal, 2=Good, 3=Outstanding, 4=Excellent, 5=Masterpiece)","enum":[1,2,3,4,5],"example":1},"ServerName":{"type":"string","enum":["europe","east","west"],"example":"west"},"Item":{"type":"object","required":["id","name","tier","enchantment","icon"],"properties":{"id":{"type":"string","example":"T4_BAG","description":"Albion unique item name"},"name":{"type":"string","example":"Adept's Bag"},"tier":{"type":"integer","minimum":0,"maximum":8,"example":4},"enchantment":{"type":"integer","minimum":0,"maximum":4,"example":0},"icon":{"type":"string","format":"uri","example":"https://render.albiononline.com/v1/item/T4_BAG.png"}}},"HealthResponse":{"type":"object","required":["status","version","timestamp","uptime","docs"],"properties":{"status":{"type":"string","enum":["ok","degraded","down"]},"version":{"type":"string","pattern":"^\\d+\\.\\d+\\.\\d+$","description":"Application semver"},"timestamp":{"type":"string","format":"date-time"},"uptime":{"type":"number","format":"float","description":"Process uptime in seconds"},"docs":{"type":"object","required":["openapi","llms","llmsFull","human"],"properties":{"openapi":{"type":"string","example":"/openapi.json"},"llms":{"type":"string","example":"/llms.txt"},"llmsFull":{"type":"string","example":"/llms-full.txt"},"human":{"type":"string","example":"/api-docs"}}}}},"ItemSearchResponse":{"type":"object","required":["query","count","limit","offset","items","suggestion"],"properties":{"query":{"type":"string","example":"bag"},"count":{"type":"integer","minimum":0,"description":"Unpaginated match count"},"limit":{"type":"integer","nullable":true},"offset":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/Item"}},"suggestion":{"type":["string","null"],"description":"Spelling suggestion when the result set is empty"}}},"ArbitrageOpportunity":{"type":"object","required":["server","quality","qualityLabel","buyCity","sellCity","buyPrice","sellPrice","profit","marginPercent"],"properties":{"server":{"$ref":"#/components/schemas/ServerName"},"quality":{"$ref":"#/components/schemas/QualityLevel"},"qualityLabel":{"type":"string","example":"Normal"},"buyCity":{"$ref":"#/components/schemas/CityName"},"sellCity":{"$ref":"#/components/schemas/CityName"},"buyPrice":{"type":"integer","minimum":0},"sellPrice":{"type":"integer","minimum":0},"profit":{"type":"integer"},"marginPercent":{"type":"number"}}},"ArbitrageResponse":{"type":"object","required":["item","count","opportunities"],"properties":{"item":{"$ref":"#/components/schemas/Item"},"count":{"type":"integer","minimum":0},"limit":{"type":"integer","nullable":true},"offset":{"type":"integer"},"opportunities":{"type":"array","items":{"$ref":"#/components/schemas/ArbitrageOpportunity"}},"errors":{"type":"array","description":"Per-server upstream failures when some shards still succeeded","items":{"type":"object","required":["server","error","code"],"properties":{"server":{"$ref":"#/components/schemas/ServerName"},"error":{"type":"string"},"code":{"type":"string"}}}}}},"RouteChain":{"type":"object","required":["itemId","itemName","profit","destinationCity","quality"],"properties":{"itemId":{"type":"string"},"itemName":{"type":"string"},"profit":{"type":"integer"},"destinationCity":{"$ref":"#/components/schemas/CityName"},"quality":{"$ref":"#/components/schemas/QualityLevel"}}},"TradingRoute":{"type":"object","required":["originCity","destinationCity","quality","qualityLabel","buyPrice","sellPrice","rawProfit","netProfit","marginPercent","distance","server","chains"],"properties":{"originCity":{"$ref":"#/components/schemas/CityName"},"destinationCity":{"$ref":"#/components/schemas/CityName"},"quality":{"$ref":"#/components/schemas/QualityLevel"},"qualityLabel":{"type":"string"},"buyPrice":{"type":"integer","minimum":0,"description":"Lowest sell order at origin"},"sellPrice":{"type":"integer","minimum":0,"description":"Highest buy order at destination"},"rawProfit":{"type":"integer"},"netProfit":{"type":"integer"},"marginPercent":{"type":"number"},"distance":{"type":"number"},"server":{"$ref":"#/components/schemas/ServerName"},"chains":{"type":"array","items":{"$ref":"#/components/schemas/RouteChain"}}}},"RoutesResponse":{"type":"object","required":["item","count","routes"],"properties":{"item":{"$ref":"#/components/schemas/Item"},"count":{"type":"integer","minimum":0},"limit":{"type":"integer","nullable":true},"offset":{"type":"integer"},"origin":{"type":["string","null"]},"feeRate":{"type":"number"},"routes":{"type":"array","items":{"$ref":"#/components/schemas/TradingRoute"}},"errors":{"type":"array","items":{"type":"object"}}}},"MarketPriceEntry":{"type":"object","required":["item_id","city","quality","sell_price_min","sell_price_min_date","sell_price_max","sell_price_max_date","buy_price_min","buy_price_min_date","buy_price_max","buy_price_max_date"],"description":"One city/quality price snapshot. Property names are snake_case to match the upstream Albion Data API.","properties":{"item_id":{"type":"string","example":"T4_BAG"},"city":{"$ref":"#/components/schemas/CityName"},"quality":{"$ref":"#/components/schemas/QualityLevel"},"sell_price_min":{"type":"integer","minimum":0},"sell_price_min_date":{"type":"string","format":"date-time"},"sell_price_max":{"type":"integer","minimum":0},"sell_price_max_date":{"type":"string","format":"date-time"},"buy_price_min":{"type":"integer","minimum":0},"buy_price_min_date":{"type":"string","format":"date-time"},"buy_price_max":{"type":"integer","minimum":0},"buy_price_max_date":{"type":"string","format":"date-time"}}},"ErrorDetail":{"type":"object","required":["field","message"],"properties":{"field":{"type":"string","example":"item"},"message":{"type":"string"}}},"ErrorResponse":{"type":"object","required":["error","code"],"properties":{"error":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Machine-readable error code for agent recovery","enum":["MISSING_URL","INVALID_URL","URL_TOO_LONG","HOST_NOT_ALLOWED","RATE_LIMITED","UPSTREAM_ERROR","UPSTREAM_TIMEOUT","HEALTH_CHECK_FAILED","MISSING_ITEMS","MISSING_SERVER","INVALID_SERVER","INVALID_LOCATION","INVALID_QUALITY","INVALID_ITEM","INVALID_LIMIT","INVALID_OFFSET","MISSING_QUERY","MISSING_ITEM","ITEM_NOT_FOUND","ITEM_INDEX_UNAVAILABLE","INVALID_ORIGIN","INVALID_SORT","INVALID_FEE_RATE","INVALID_MIN_PROFIT","INVALID_MAX_DISTANCE"]},"details":{"type":"array","description":"Field-level validation errors (present on 400 responses)","items":{"$ref":"#/components/schemas/ErrorDetail"}},"suggestion":{"type":"string","description":"Optional spelling correction on ITEM_NOT_FOUND"},"retryAfter":{"type":"integer","description":"Seconds until retry is allowed"}}},"RateLimitError":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"},{"type":"object","required":["retryAfter"],"properties":{"retryAfter":{"type":"integer","example":30},"code":{"type":"string","enum":["RATE_LIMITED"]}}}]},"RetryableError":{"allOf":[{"$ref":"#/components/schemas/ErrorResponse"},{"type":"object","required":["retryAfter"],"properties":{"retryAfter":{"type":"integer","example":10},"code":{"type":"string","enum":["UPSTREAM_TIMEOUT"]}}}]}}}}