# Qty > Deterministic quantity API for AI agents. Free when the input is a finite number and two known unit codes. Paid, exact USDC, when the text is messy. No accounts, no API keys, no invented numbers. Same input, same output. Payments: exact USDC, same price on every listed network. base eip155:8453 payTo 0x41F7c3FfC3Cda926797Eb388bB65Ccd8A1deC352; solana solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp payTo GhBZyUbBH2qdTbUXtNjFnbiqeh9c7rsReVU6kjJVCbp6. Facilitator: https://facilitator.payai.network. ## When to use free vs paid - Free POST /v1/convert: `{ "value": 10, "from": "mi", "to": "km" }` returns kilometres, a formula, and a definition id. - Free POST /v1/convert rejects `5'11\"` with error code `use_parse`, hinting at POST /v1/parse for $0.002. - Free POST /v1/convert is limited to 60 requests per 60 seconds per client. The next call returns 429 rate_limited. The client address is hashed and not stored. - Paid POST /v1/parse: messy text such as heights, lumber, pace, cooking, prices, recipes, sizes, and dates. - Paid POST /v1/batch: up to 100 texts, flat $0.01. One bad row does not fail the batch. - Paid POST /v1/receipt: canonical JSON and sha256, $0.001. The hash excludes the timestamp. - Dedicated paid routes at $0.002: /v1/compare-prices, /v1/scale-recipe, /v1/size, /v1/date. - POST /v1/date also converts IANA time zones (DST-aware), ISO-8601 durations, and phrases like 5 days from 2026-10-02. Same price, $0.002. - Paid POST /v1/estimate ($0.003): paint, tiles, concrete, and gravel. Coverage assumptions and waste percent are on the result. - Compound units on free convert: US mpg (mpg_us), imperial mpg (mpg_imp), L/100km, kWh/100km, mi/kWh, W/m2, flow (m3/s, L/min), power (W, kW, hp), and gas_mark / gas_mark_fan. - Number words such as two dozen belong on POST /v1/parse. - Unpaid POST and GET on a paid route return HTTP 402 with the price quote. The handler does not run. Settlement happens only after a 2xx. - Tool definitions, same schemas as MCP: /tools/openai.json, /tools/anthropic.json, and a Vercel AI SDK example at /tools/ai-sdk.ts. - Paying client: packages/client (@qty/client), wrapping @x402/fetch. Examples for Base and Solana take a signer and contain no keys. - Prepaid credits are a design note only: /docs/prepaid-credits. Qty does not store balances. ## Determinism - Pure functions. No model calls inside parse or convert. - Temperature is affine. Do not multiply kelvin. - US gallon is 3.785411784 L. Imperial gallon is 4.54609 L. - Foot defaults to the international foot, 0.3048 m. US survey foot is explicit: 1200/3937 m. - Statute mile is 1609.344 m. - Pace is time per distance unless the caller asks for a speed unit. - 2x4x8 ft is three nominal dimensions. Dressed size is not applied unless the text says dressed. - Stick of butter is 113.4 g, labelled as an assumption. - Pinch is null with a reason. - Date maths never reads the clock. Missing reference date is null with a reason. - Working days skip Saturday and Sunday, plus only the caller's holiday list. - Currency is a label. Qty does not convert currencies. - Size tables are Qty size table v1. Ambiguous category is null with a reason. Brand variance is a warning. ## Discovery - OpenAPI: https://qty.vercel.app/openapi.json - Full notes: https://qty.vercel.app/llms-full.txt - Human docs: https://qty.vercel.app/docs - x402 manifest: https://qty.vercel.app/.well-known/x402.json - Agent card: https://qty.vercel.app/.well-known/agent-card.json - MCP: https://qty.vercel.app/mcp - OpenAI tools: https://qty.vercel.app/tools/openai.json - Anthropic tools: https://qty.vercel.app/tools/anthropic.json - Vercel AI SDK example: https://qty.vercel.app/tools/ai-sdk.ts - Prepaid credits design: https://qty.vercel.app/docs/prepaid-credits - Feed: https://qty.vercel.app/v1/feed ## Routes ### GET /health Returns ok. No payment, no Redis, no network. Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "ok": true, "service": "qty", "version": "1.0.0" } ``` ### GET /units Call this before convert when you are unsure of a code. Free. Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "units": [ { "code": "mi", "aliases": [ "mile", "statute mile" ], "dimension": "length", "definitionId": "length.mile.statute" } ] } ``` ### POST /v1/convert Use when you already have a number and two codes from GET /units, such as 10 mi to km or 32 F to C. Temperature is affine. If the text is messy (5'11", a stick of butter, a price, a size, a date), this returns 400 use_parse and you must call POST /v1/parse. Deterministic. assumptions is always an array. Limited to 60 requests per 60 seconds per client. Over the limit returns 429 rate_limited with Retry-After. The hint points at paid POST /v1/batch ($0.01). The client is ipAddress() from @vercel/functions (x-real-ip), otherwise the first public address in x-vercel-forwarded-for, then x-forwarded-for. Ports and non-addresses are ignored. The address is not stored. Responses include x-ratelimit-source (redis, memory, or none), x-ratelimit-key-prefix (first 8 hex chars of the client hash), and x-ratelimit-window (the fixed window id). The counter is shared through the same Redis as the feed (KV_REST_API_* or UPSTASH_REDIS_REST_*). A Redis error does not fail the route. Request: ```json { "value": 10, "from": "mi", "to": "km" } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "result": 16.09344, "from": "mi", "to": "km", "formula": "10 mi × 1.609344 km/mi = 16.09344 km", "definitionId": "length.mile.statute", "assumptions": [] } ``` ### GET /v1/feed Free. Cached for about 2 seconds. Events contain route, kind, from value and unit, to value and unit, or a short category, plus a timestamp. Raw text, receipts, wallets, IPs, and headers are never stored. Empty when Redis is not configured. Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "events": [], "totals": { "all": 0, "routes": {} }, "configured": false } ``` ### POST /v1/parse Interpret messy quantity text into a list of quantities. Call this when convert returns use_parse. Deterministic. Never invents a number: unknown amounts are null with a reason. Same text always returns the same quantities. Does not call a model or any other service. Price: $0.002. Request: ```json { "text": "5'11\"", "to": "cm" } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "quantities": [ { "value": 180.34, "unit": "cm", "siValue": 1.8034, "siUnit": "m", "formula": "5 ft × 0.3048 m + 11 in × 0.0254 m = 1.8034 m; 1.8034 m = 180.34 cm", "definitionId": "length.foot.international", "confidence": 0.98, "warnings": [], "assumptions": [ "Feet and inches use the international foot (0.3048 m) and the international inch (0.0254 m)." ], "reason": null, "label": "height" } ] } ``` ### POST /v1/batch Parse up to 100 messy texts for a flat price. One bad row does not fail the batch. Each row is ok with quantities or ok:false with a stable error code. Deterministic. No per-row upto pricing in v1. Price: $0.01. Request: ```json { "items": [ { "text": "10 mi", "to": "km" }, { "text": "not a quantity" } ] } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "results": [ { "index": 0, "ok": true, "quantities": [] }, { "index": 1, "ok": false, "error": { "code": "unparsed" } } ] } ``` ### POST /v1/receipt Canonical audit JSON plus sha256 of a previous Qty result. Includes input, definition ids, formulas, and a timestamp. The hash ignores the timestamp so the same payload always hashes the same. No chain write. Price: $0.001. Request: ```json { "quantities": [ { "value": 180.34, "unit": "cm", "formula": "5 ft + 11 in", "definitionId": "length.foot.international" } ] } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "document": { "kind": "qty.receipt.v1", "definitions": [], "formulas": [], "timestamp": "2026-10-05T00:00:00.000Z" }, "sha256": "0000000000000000000000000000000000000000000000000000000000000000" } ``` ### POST /v1/compare-prices Normalise unit prices and say which offer is cheaper. Currency is a label only; Qty never converts between currencies. Multipacks are totalled first. Returns price per base unit (litre, kilogram, or each). Price: $0.002. Request: ```json { "offers": [ "£2.50 for 750ml", "£3 for 1L" ] } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "comparison": { "cheaperIndex": 1, "currency": "GBP", "baseUnit": "L" } } ``` ### POST /v1/scale-recipe Scale ingredient amounts by servings or a factor. Cup, tbsp, tsp, and stick convert between us, imperial, and si using the labelled assumption table. Mass and volume convert only for flour, sugar, butter, water, milk, and rice. Anything else is null with a reason. Price: $0.002. Request: ```json { "fromServings": 4, "toServings": 6, "ingredients": [ "2 cups flour", "1 stick of butter" ] } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "recipe": { "factor": 1.5, "definitionId": "recipe.scale.servings.v1" } } ``` ### POST /v1/size Convert shoe and clothing sizes using Qty size table v1. Men's UK 9 shoe is EU 43 and US 10. Ambiguous gender or category returns null and a reason. Brand variance is always a warning. No interpolation. Price: $0.002. Request: ```json { "text": "UK 9 men's shoe", "to": "EU" } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "quantities": [ { "value": 43, "unit": "EU", "definitionId": "size.shoe.men.v1" } ] } ``` ### POST /v1/date Parse ISO-8601 durations, add N days from an explicit date, and convert IANA time zones. Working days skip Saturday and Sunday plus an optional caller holiday list. Daylight-saving gaps and overlaps are reported. There is no built-in holiday calendar. If the text needs a date and none was given, the value is null with a reason. Qty never uses the current clock. Price: $0.002. Request: ```json { "text": "2026-01-15T12:00 America/New_York to Europe/London" } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "quantities": [ { "textValue": "2026-01-15T17:00:00+00:00", "unit": "Europe/London", "definitionId": "date.timezone.v1" } ] } ``` ### POST /v1/estimate Estimate paint, tiles, concrete, or gravel. Paint uses 10 m² per litre per coat and defaults to 2 coats. Tiles default to 0.30 m × 0.30 m. A 25 kg concrete bag yields 0.012 m³. Gravel uses 1600 kg/m³. Waste defaults to 10 percent and is stated on the result. Assumptions are labels, not a quote from a supplier. Price: $0.003. Request: ```json { "kind": "paint", "area": 40, "unit": "m2", "coats": 2, "wastePercent": 10 } ``` Response: ```json { "see": { "llms": "/llms.txt", "llmsFull": "/llms-full.txt", "openapi": "/openapi.json", "docs": "/docs", "x402": "/.well-known/x402.json", "agentCard": "/.well-known/agent-card.json", "mcp": "/mcp", "tools": "/tools/openai.json", "anthropicTools": "/tools/anthropic.json", "aiSdk": "/tools/ai-sdk.ts", "credits": "/docs/prepaid-credits" }, "quantities": [ { "value": 8.8, "unit": "L", "definitionId": "building.paint.v1", "assumptions": [ "Paint coverage is 10 m² per litre per coat (Qty building assumption table v1)." ] } ] } ``` ### POST /mcp Streamable HTTP MCP. Free tools: convert, units. Paid tools reuse x402 and the HTTP prices: parse, batch, receipt, compare-prices, scale-recipe, size, date, estimate. Input schemas match /tools/openai.json. Paid tools do not return results without payment. ## Error codes - use_parse: convert was given messy text. Call POST /v1/parse ($0.002). - unknown_unit: code is not in GET /units. - ambiguous_unit: gallon or cup needs a system. Do not guess. - dimension_mismatch: units do not share a base. - invalid_value: value is not a finite number. - invalid_request: body shape is wrong. - unparsed: text was not recognised. No number was invented. - unknown_amount: the name is known and has no deterministic amount (pinch). - ambiguous: size category or audience is missing. - batch_too_large: more than 100 items. - payment_required: 402. price, payTo, network, and path are in the body. - payee_not_configured: X402_PAY_TO is missing. Paid routes refuse. - rate_limited: POST /v1/convert exceeded 60 requests per 60 seconds. Honor Retry-After, or call paid POST /v1/batch ($0.01). ## Unit codes - m (length) length.meter aliases: meter, metre, meters, metres - cm (length) length.centimeter aliases: centimeter, centimetre, centimeters, centimetres - mm (length) length.millimeter aliases: millimeter, millimetre - um (length) length.micrometer aliases: µm, μm, micrometer, micrometre, micron - km (length) length.kilometer aliases: kilometer, kilometre, kilometers, kilometres - in (length) length.inch aliases: inch, inches - ft (length) length.foot.international aliases: foot, feet, international foot, international feet - us_survey_ft (length) length.foot.us_survey aliases: us survey foot, u s survey foot, survey foot, us survey ft - yd (length) length.yard aliases: yard, yards - mi (length) length.mile.statute aliases: mile, miles, statute mile, statute miles - nmi (length) length.nautical_mile aliases: nautical mile, nautical miles - kg (mass) mass.kilogram aliases: kilogram, kilograms - g (mass) mass.gram aliases: gram, grams - mg (mass) mass.milligram aliases: milligram, milligrams - lb (mass) mass.pound aliases: pound, pounds - oz (mass) mass.ounce aliases: ounce, ounces - st (mass) mass.stone aliases: stone, stones - t (mass) mass.tonne aliases: tonne, tonnes, metric ton, metric tons - ton (mass) mass.ton.short aliases: short ton, us ton, tons - m3 (volume) volume.cubic_meter aliases: cubic meter, cubic metre - L (volume) volume.liter aliases: l, liter, litre, liters, litres - mL (volume) volume.milliliter aliases: ml, milliliter, millilitre - us_gal (volume) volume.gallon.us aliases: us gallon, u s gallon, us gal, gallon, gallons, gal - imp_gal (volume) volume.gallon.imperial aliases: imperial gallon, imp gallon, uk gallon, imp gal, gallon, gallons, gal - us_pt (volume) volume.pint.us aliases: us pint, pint, pints - imp_pt (volume) volume.pint.imperial aliases: imperial pint, imp pint, uk pint, pint, pints - us_qt (volume) volume.quart.us aliases: us quart, quart, quarts - imp_qt (volume) volume.quart.imperial aliases: imperial quart, imp quart, uk quart, quart, quarts - us_floz (volume) volume.fluid_ounce.us aliases: us fl oz, us fluid ounce, fl oz, floz, fluid ounce - imp_floz (volume) volume.fluid_ounce.imperial aliases: imperial fl oz, imp fl oz, uk fl oz, imperial fluid ounce, fl oz, floz, fluid ounce - K (temperature) temperature.kelvin aliases: kelvin, kelvins - C (temperature) temperature.celsius aliases: c, celsius, centigrade, ℃, ºc - F (temperature) temperature.fahrenheit aliases: f, fahrenheit, ℉, ºf - m/s (speed) speed.meter_per_second aliases: mps, meter per second, metres per second - km/h (speed) speed.kilometer_per_hour aliases: kph, kmh, kilometer per hour - mph (speed) speed.mile_per_hour aliases: mile per hour, miles per hour - ft/s (speed) speed.foot_per_second aliases: fps, foot per second - kn (speed) speed.knot aliases: knot, knots, kt - s (time) time.second aliases: sec, second, seconds - ms (time) time.millisecond aliases: millisecond, milliseconds - min (time) time.minute aliases: minute, minutes - h (time) time.hour aliases: hr, hour, hours - d (time) time.day aliases: day, days - wk (time) time.week aliases: week, weeks - m2 (area) area.square_meter aliases: square meter, square metre, m² - cm2 (area) area.square_centimeter aliases: square centimeter - ft2 (area) area.square_foot aliases: square foot, sq ft - acre (area) area.acre aliases: acres - ha (area) area.hectare aliases: hectare, hectares - km2 (area) area.square_kilometer aliases: km², square kilometer, square kilometre - Pa (pressure) pressure.pascal aliases: pa, pascal, pascals - kPa (pressure) pressure.kilopascal aliases: kpa, kilopascal - bar (pressure) pressure.bar aliases: bars - psi (pressure) pressure.psi aliases: pound per square inch - atm (pressure) pressure.atmosphere aliases: atmosphere, atmospheres - J (energy) energy.joule aliases: j, joule, joules - kJ (energy) energy.kilojoule aliases: kj, kilojoule - cal (energy) energy.calorie aliases: calorie, calories - kcal (energy) energy.kilocalorie aliases: kilocalorie, kilocalories - Wh (energy) energy.watt_hour aliases: wh, watt hour - kWh (energy) energy.kilowatt_hour aliases: kwh, kilowatt hour - B (data) data.byte aliases: byte, bytes - kB (data) data.kilobyte aliases: kilobyte, kilobytes - MB (data) data.megabyte aliases: megabyte, megabytes - GB (data) data.gigabyte aliases: gigabyte, gigabytes - TB (data) data.terabyte aliases: terabyte, terabytes - KiB (data) data.kibibyte aliases: kibibyte - MiB (data) data.mebibyte aliases: mebibyte - GiB (data) data.gibibyte aliases: gibibyte - TiB (data) data.tebibyte aliases: tebibyte - b (data) data.bit aliases: bit, bits - kb (data) data.kilobit aliases: kilobit, kilobits - Mb (data) data.megabit aliases: megabit, megabits - Gb (data) data.gigabit aliases: gigabit, gigabits - Tb (data) data.terabit aliases: terabit, terabits - Kibit (data) data.kibibit aliases: kibibit - Mibit (data) data.mebibit aliases: mebibit - Gibit (data) data.gibibit aliases: gibibit - Tibit (data) data.tebibit aliases: tebibit - us_cup (cooking) cooking.cup.us aliases: us cup, cup, cups - imp_cup (cooking) cooking.cup.imperial aliases: imperial cup, imp cup, cup, cups - si_cup (cooking) cooking.cup.metric aliases: metric cup, si cup, cup, cups - us_tbsp (cooking) cooking.tablespoon.us aliases: us tbsp, us tablespoon, tbsp, tablespoon, tablespoons - imp_tbsp (cooking) cooking.tablespoon.imperial aliases: imperial tbsp, imperial tablespoon, tbsp, tablespoon, tablespoons - si_tbsp (cooking) cooking.tablespoon.metric aliases: metric tbsp, si tbsp, tbsp, tablespoon, tablespoons - us_tsp (cooking) cooking.teaspoon.us aliases: us tsp, us teaspoon, tsp, teaspoon, teaspoons - imp_tsp (cooking) cooking.teaspoon.imperial aliases: imperial tsp, tsp, teaspoon, teaspoons - si_tsp (cooking) cooking.teaspoon.metric aliases: metric tsp, si tsp, tsp, teaspoon, teaspoons - us_fl_oz (cooking) cooking.fluid_ounce.us aliases: us fl oz, us fluid ounce - stick_butter (cooking) cooking.butter.stick aliases: stick of butter, stick butter, butter stick - W (power) power.watt aliases: watt, watts - kW (power) power.kilowatt aliases: kilowatt, kilowatts - hp (power) power.horsepower.mechanical aliases: horsepower - W/m2 (irradiance) irradiance.watt_per_square_meter aliases: W/m², watt per square meter - deg (angle) angle.degree aliases: degree, degrees - rad (angle) angle.radian aliases: radian, radians - Hz (frequency) frequency.hertz aliases: hertz - kHz (frequency) frequency.kilohertz aliases: kilohertz - rpm (frequency) frequency.rpm aliases: revolutions per minute - m3/s (flow) flow.cubic_meter_per_second aliases: cubic meters per second - L/min (flow) flow.liter_per_minute aliases: liters per minute, litres per minute - L/100km (fuel) fuel.liter_per_100km aliases: l/100km, liters per 100 km, litres per 100 km - mpg_us (fuel) fuel.mpg.us aliases: us mpg, mpg - mpg_imp (fuel) fuel.mpg.imperial aliases: imperial mpg, imp mpg, uk mpg, mpg - kWh/100km (energy-economy) economy.kwh_per_100km aliases: kwh/100km - mi/kWh (energy-economy) economy.mile_per_kwh aliases: miles per kwh, mi/kwh - gas_mark (temperature) cooking.gas_mark.v1 aliases: gas mark, gasmark - gas_mark_fan (temperature) cooking.gas_mark.fan.v1 aliases: fan gas mark, gas mark fan ## Assumption tables - US stick of butter = 113.4 g. - Flour = 120 g per US cup. Sugar = 200 g per US cup. Rice = 185 g per US cup. - Water = 1 g/ml. Milk = 1.03 g/ml. Butter density follows the stick. - SI cup = 250 ml, SI tablespoon = 15 ml, SI teaspoon = 5 ml. - Men's shoe UK 9 = US 10 = EU 43 = JP 28 cm in size.shoe.men.v1. - US mpg: L/100km = 235.214583333 / mpg. Imperial mpg: 282.481053846 / mpg. - Gas mark 4 is 180°C. A fan oven is 20°C lower. Marks between the table are linear. - Paint is 10 m² per litre per coat. Tiles default to 0.30 m × 0.30 m. Concrete bags yield 0.012 m³. Gravel is 1600 kg/m³. Waste defaults to 10%. ## Feed Successful calls push a sanitised event: route, kind, from value and unit, to value and unit or a short category, timestamp. The list keeps the last 50. Totals are incremented per route. Writes never block the response. Without Redis the feed is empty and the API still works.