{"openapi":"3.1.0","info":{"title":"Weather Data Market API","version":"v1","summary":"Consensus weather data for 172 cities, bought with XRP on the XRP Ledger.","description":"Paths are listed under /api/v1. The unversioned /api/... form is the same handler and keeps working, but new integrations should use the versioned path so a future breaking change can ship as v2 without moving anyone. Response bodies are documented with worked examples at https://weathermarket.io/docs rather than as schemas here - a schema we cannot keep current would be worse than none.\n\nRate limits, per caller per minute: quote 30, purchase history 20, token minting 10, download 60, agent top-up 20. Over the limit you get 429 with Retry-After in seconds. The limit is shared across instances, so retrying from a different connection does not reset it.\n\nIdempotency: /api/purchases/claim and /api/agent/topup are keyed by the on-chain transaction hash and enforced by a unique constraint, not by a read-then-write check. Submitting the same hash twice - even concurrently - credits or delivers exactly once; the loser gets 409. Safe to retry on network failure: if the first attempt actually landed, the retry returns 409 rather than doubling anything.","contact":{"name":"Wellbian Labs (platform operator)","email":"admin@wellbianlabs.io","url":"https://weathermarket.io"},"termsOfService":"https://weathermarket.io/terms"},"servers":[{"url":"https://weathermarket.io"}],"components":{"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Human-readable reason. Not a stable machine code - branch on the status"},"retryAfterSeconds":{"type":"integer","description":"Present on 429"},"availableFrom":{"type":"string","description":"Present on 425 - the first date the dataset can be fetched"}}},"PriceTable":{"type":"object","required":["day","month","year","perDay","monthDays","yearDays"],"description":"Term prices per city. Not linear - 1, 30 and 365 days have their own price and any other length is charged at the daily rate.","properties":{"day":{"type":"string"},"month":{"type":"string"},"year":{"type":"string"},"perDay":{"type":"string"},"monthDays":{"type":"integer"},"yearDays":{"type":"integer"},"note":{"type":"string"}}},"City":{"type":"object","required":["id","slug","name","lat","lon","products"],"properties":{"id":{"type":"integer"},"slug":{"type":"string","description":"Use this with every other endpoint"},"name":{"type":"string","description":"English name"},"nameKo":{"type":"string"},"nameEn":{"type":"string","deprecated":true,"description":"Duplicate of name - will be removed"},"lat":{"type":"number"},"lon":{"type":"number"},"pricePerDayUsdt":{"type":"string","description":"The price table's daily rate, same for every city"},"products":{"type":"array","items":{"type":"string"}}}},"CitiesResponse":{"type":"object","required":["cities","pricing"],"properties":{"pricing":{"$ref":"#/components/schemas/PriceTable"},"cities":{"type":"array","items":{"$ref":"#/components/schemas/City"}}}},"Quote":{"type":"object","required":["quoteId","quoteIdHash","city","from","to","days","priceUsdt","expiresAt"],"properties":{"quoteId":{"type":"string"},"quoteIdHash":{"type":"string","description":"keccak256 of quoteId - used only by the Flare (testnet) FTSOv2 market path"},"product":{"type":"string"},"fields":{"type":["string","null"]},"city":{"type":"string"},"cityId":{"type":"integer"},"cities":{"type":"array","items":{"type":"string"},"description":"Bundle quotes only"},"cityIds":{"type":"array","items":{"type":"integer"},"description":"Bundle quotes only"},"from":{"type":"string"},"to":{"type":"string"},"fromDateInt":{"type":"integer"},"toDateInt":{"type":"integer"},"days":{"type":"integer"},"priceUsdt":{"type":"string","description":"USD price, decimal string. Paid in XRP - see xrpl.amount.drops"},"pricing":{"$ref":"#/components/schemas/PriceTable"},"cheaper":{"type":["object","null"],"description":"Set when splitting the range into discounted blocks costs less"},"xrpl":{"type":["object","null"],"description":"How to pay in XRP: destination, destinationTag (required), amount.drops fixed for ten minutes at rate.usdPerXrp (FTSOv2). Null only when the rate could not be read."},"flare":{"type":["object","null"]},"expiresAt":{"type":"string","description":"Quote validity. Expiry is judged by the payment block's timestamp, not by when you call claim"}}},"PaymentInstructions":{"type":"object","required":["method","network","destination","destinationTag","pricePerCallUsd","minTopupUsd"],"properties":{"method":{"type":"string","description":"xrp-payment"},"network":{"type":"string"},"destination":{"type":"string","description":"XRPL account to pay"},"destinationTag":{"type":"integer","description":"Always 402 for a top-up - a quote tag would be a subscription payment"},"pricePerCallUsd":{"type":"string","description":"Compute top-up amounts from this - never hardcode"},"minTopupUsd":{"type":"string"},"minTopupXrp":{"type":["string","null"],"description":"minTopupUsd at the current rate; credits are computed at the rate when the payment is verified"},"rate":{"type":["object","null"],"description":"{ usdPerXrp, feed: 'XRP/USD', source: 'ftsov2'|'env', at }"},"howTo":{"type":"string"},"pricePerCallUsdt":{"type":"string","description":"Deprecated alias of pricePerCallUsd"},"minTopupUsdt":{"type":"string","description":"Deprecated alias of minTopupUsd"}}},"TopupInfo":{"type":"object","required":["payment"],"properties":{"payment":{"$ref":"#/components/schemas/PaymentInstructions"}}},"Verdict":{"type":"string","enum":["verified","single_source","mixed","mismatch","unverified","low_consensus"],"description":"Cross-check result for the hour. Only the two measurement feeds count toward it. 'verified' means a strict majority agreed and at least two corroborated."},"IndexCity":{"type":"object","required":["city","date","wdi","tdi","index"],"description":"Free tier carries city, date, index values and WDI/TDI only. nSources, verdict, settlementEligible and the per-source fields are present only with a credential (subscription or x-api-key).","properties":{"city":{"type":"string"},"cityName":{"type":"string"},"date":{"type":"string"},"wdi":{"type":"number"},"tdi":{"type":"number"},"index":{"type":"object","description":"Consensus values - temperature, humidity, wind, precipitation"},"metrics":{"type":"object","description":"Dispersion per metric"},"observed":{"type":["object","null"],"description":"Measurement-only values, for comparison with the model-led consensus"},"perSource":{"type":"object","description":"Raw value per source feed"},"nSources":{"type":"integer"},"outlierSources":{"type":"array","items":{"type":"string"}},"confidence":{"type":"string"},"verdict":{"$ref":"#/components/schemas/Verdict"},"settlementEligible":{"type":"boolean","description":"True only when verdict is 'verified'. Branch on this rather than re-deriving the rule - it is the same rule the docs describe, moved into a value."},"settlementReason":{"type":["string","null"],"description":"Why it is not eligible. null when it is."},"settlementByMetric":{"type":"object","description":"The same judgement per metric. settlementEligible goes false when any one metric falls outside tolerance, so a contract settling on rain or temperature alone should branch on this instead - a wind disagreement accounts for 23.7% of measurement rejections.","properties":{"temp":{"type":"boolean"},"humidity":{"type":"boolean"},"wind":{"type":"boolean"},"rain":{"type":"boolean"}}},"corroboration":{"type":["object","null"]}}},"IndexResponse":{"type":"object","required":["runId","asOf","cities"],"properties":{"runId":{"type":"string"},"asOf":{"type":"string"},"method":{"type":"string"},"freeTier":{"type":"object","description":"Present on free-tier responses: what is included, the hourly budget and what to buy"},"attribution":{"type":"object"},"verdictMethod":{"type":"object"},"indexSpec":{"type":"object"},"observedIndex":{"type":"object"},"cities":{"type":"array","items":{"$ref":"#/components/schemas/IndexCity"}}}},"Health":{"type":"object","required":["status","checkedAt","commit","data","anchoring"],"properties":{"status":{"type":"string","enum":["ok","warn","fail"]},"checkedAt":{"type":"string"},"commit":{"type":"string","description":"Short git commit of the deployment serving this response - compare across paths to prove one build"},"build":{"type":"object","description":"Operator sessions only","required":["commit"],"properties":{"commit":{"type":"string"},"branch":{"type":"string"},"region":{"type":"string"}}},"data":{"type":"object"},"payment":{"type":["object","null"],"description":"Last end-to-end purchase check"},"lastPurchase":{"type":["object","null"],"description":"Most recent real purchase, read straight from the ledger. smokeOlderThanLastPurchase flags that the published smoke result predates it and may not reflect current prices."},"anchoring":{"type":"object"}}}},"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"x-api-key"},"bearerToken":{"type":"http","scheme":"bearer","description":"Subscription access token"},"walletSignature":{"type":"apiKey","in":"header","name":"x-wallet-signature","description":"personal_sign of `WeatherMarket auth <address> <ts>`, sent with x-wallet-address and x-wallet-ts. Valid 10 minutes. The older query form (?address=&ts=&sig=) still works and is not scheduled for removal, but should not be used for new integrations: a query string is recorded by browser history, referrers, proxies and access logs, and the signature stays valid for ten minutes after landing there. Note the signed message binds only the address and timestamp - not the domain, chain or request path - so treat it as proof of wallet control, not as authorisation for a specific action."}}},"paths":{"/api/v1/catalog":{"get":{"summary":"City catalog - continents › countries › cities, sources & attribution","parameters":[],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/cities":{"get":{"summary":"Flat city list with product availability, plus the current price table (1 USD for a day, 25 for 30 days, 200 for a year, paid in XRP; any other length at the daily rate). `station` carries the city's METAR station with its IANA timezone, `effectiveFrom` (the first date that station has been the city's reference), `history` (every earlier mapping with its dates) and `planned` (an announced change that has not taken effect yet). `name` is English; `nameKo` carries the Korean name. `nameEn` is retained as a duplicate of `name` and is deprecated","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CitiesResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/quote":{"get":{"summary":"Quote + quoteId (10 min TTL). Start within the next 90 days, run up to 365 days from that start. Pass `cities=a,b,c` instead of `city` for a bundle settled in one transaction","parameters":[{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"},{"name":"cities","in":"query","required":false,"description":"Comma-separated slugs for a bundle quote","schema":{"type":"string"},"example":"seoul,tokyo"},{"name":"from","in":"query","required":true,"description":"Start date, YYYY-MM-DD","schema":{"type":"string"},"example":"2026-08-01"},{"name":"to","in":"query","required":true,"description":"End date, YYYY-MM-DD","schema":{"type":"string"},"example":"2026-08-31"},{"name":"product","in":"query","required":false,"description":"subscription - the only product sold. It must run exactly 30 or 365 days; other lengths are billed at the daily rate and would cost more than the 30-day term for the same access. The standalone dataset product was retired: what you buy is API access, and the data for the days accumulated so far comes as CSV from /api/sub/{purchaseId}/history?format=csv","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/purchases/claim":{"post":{"summary":"{ txHash, quoteId } → on-chain verification → a subscription certificate with a one-time `accessToken`. Send that token as `Authorization: Bearer`; the purchase ID is an identifier, not a credential. **Datasets are no longer sold** - the branch that returns a delivery receipt exists only for purchases made before the product was withdrawn, and those still download from /api/v1/download. What replaces it: a subscription serves values live for its term, and the days accumulated so far come as CSV from /api/v1/sub/history?format=csv","parameters":[],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/purchases":{"get":{"summary":"Purchase history via wallet signature (free re-download)","security":[{"walletSignature":[]}],"parameters":[{"name":"x-wallet-address","in":"header","required":true,"description":"Buying wallet, lowercase","schema":{"type":"string"}},{"name":"x-wallet-ts","in":"header","required":true,"description":"Unix milliseconds, valid 10 minutes","schema":{"type":"string"}},{"name":"x-wallet-signature","in":"header","required":true,"description":"personal_sign of `WeatherMarket auth <address> <ts>`","schema":{"type":"string"}},{"name":"address","in":"query","required":false,"description":"Deprecated - use x-wallet-address. A query string is recorded by browser history, referrers, proxies and access logs, and the signature stays valid for ten minutes after that","schema":{"type":"string"}},{"name":"ts","in":"query","required":false,"description":"Deprecated - use x-wallet-ts","schema":{"type":"string"}},{"name":"sig","in":"query","required":false,"description":"Deprecated - use x-wallet-signature","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/purchases/{purchaseId}/token":{"post":{"summary":"Mint a new download access token. Requires a signature from the purchasing wallet (x-wallet-address, x-wallet-ts, x-wallet-signature headers) or the session of the account that bought it - the purchase ID alone is not enough. The token is returned once and only its hash is stored; issuing a new one does not revoke existing tokens","parameters":[{"name":"purchaseId","in":"path","required":true,"description":"From the claim response","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/download/{purchaseId}":{"get":{"summary":"**Retired product - existing purchases only.** Datasets are no longer sold; this path serves purchases made before withdrawal and is kept so that data already paid for is not lost. Available once the purchased period has ended - 425 with an `availableFrom` date before that. Hourly is the unit: one purchased day is 24 rows at UTC hours. Requires a credential (access token, wallet signature, or the session that bought it). For current data, buy a subscription and use /api/v1/sub/live, or per-call metering.","parameters":[{"name":"purchaseId","in":"path","required":true,"description":"From the claim response - an identifier, not a credential","schema":{"type":"string"}},{"name":"token","in":"query","required":false,"description":"Access token from the claim response (or send it as Authorization: Bearer). Instead of this you may sign with the purchasing wallet (x-wallet-* headers) or use the session of the account that bought it. Without one of the three the request is 401","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"csv | json","schema":{"type":"string"}},{"name":"granularity","in":"query","required":false,"description":"hourly (default) | daily - CSV holds one table, so this picks which","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/download/{purchaseId}/settlement":{"get":{"summary":"Per-metric settlement eligibility for every hour of the purchase. The single settlementEligible flag goes false when any one metric falls outside tolerance - and 23.7% of measurement rejections are a wind disagreement alone - so a contract settling on rain or temperature would lose hours that are fine for it. This sits beside the dataset rather than inside it: dataset columns feed the SHA-256, and adding one would change the bytes of purchases already made. Same credential and same delivery gate as the download","security":[{"walletSignature":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"description":"From the claim response","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/agent/topup":{"get":{"summary":"Prepaid per-call metering (HTTP 402; the same 402 also carries an x402 v2 PAYMENT-REQUIRED header for pay-per-call on the XRP Ledger): GET payment info (XRP destination, DestinationTag 402, rate) · POST { txHash, address, ts, sig, pubKey } after an XRP payment → credits + API key","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupInfo"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}},"post":{"summary":"Prepaid per-call metering (HTTP 402; the same 402 also carries an x402 v2 PAYMENT-REQUIRED header for pay-per-call on the XRP Ledger): GET payment info (XRP destination, DestinationTag 402, rate) · POST { txHash, address, ts, sig, pubKey } after an XRP payment → credits + API key","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupInfo"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/agent/oracle":{"get":{"summary":"Metered call (0.04 USD, paid in XRP): consensus index + verdict + rain Y/N; 402 with payment info when drained","security":[{"apiKey":[]}],"parameters":[{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/index":{"get":{"summary":"Public oracle feed. Free tier: the current consensus value and indices for the city you name (a 10-city sample without `city`), up to 120 requests an hour, then 429 with Retry-After. Free rows carry `index`, `wdi`, `tdi` only. With a subscription token or metered key on the same request the rows also carry per-source readings with observation times, outliers, corroboration counts, the measurement-only figure and the cross-check determination (`verdict`, `settlementEligible`, `settlementReason`, `settlementByMetric`). The consensus rule is proprietary; every run is hash-anchored on-chain","parameters":[{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/forecast":{"get":{"summary":"Daily forecast. Free tier: the next 3 days for the city you name. With a subscription token or metered key: the full 16 days plus the hourly forecast. Not metered - forecast is not accumulated data","parameters":[{"name":"city","in":"query","required":true,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/determinations":{"post":{"summary":"Open a determination (POST) - a verdict on a condition you set: { city, metric: temp|humi|wind|rain, op: gt|gte|lt|lte, threshold, targetHour, label? }. After the target hour the next run resolves it to met, not_met or withheld with a report of the reasons. Included with a subscription covering the city; otherwise paid from metered credits (price in the 402). Signed-in members with a linked wallet pay from the same credits on /determinations. GET lists the determinations opened with the same credential or session","security":[{"apiKey":[]}],"parameters":[],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}},"get":{"summary":"Open a determination (POST) - a verdict on a condition you set: { city, metric: temp|humi|wind|rain, op: gt|gte|lt|lte, threshold, targetHour, label? }. After the target hour the next run resolves it to met, not_met or withheld with a report of the reasons. Included with a subscription covering the city; otherwise paid from metered credits (price in the 402). Signed-in members with a linked wallet pay from the same credits on /determinations. GET lists the determinations opened with the same credential or session","security":[{"apiKey":[]}],"parameters":[],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/determinations/{id}":{"get":{"summary":"One determination: status, outcome (met · not_met · withheld) and the report - consensus value, condition, supporting and disagreeing observation counts, contributing and excluded source counts, reason. The rule that produced it is not disclosed","security":[{"apiKey":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"From the POST response","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sandbox/quote":{"get":{"summary":"Sandbox quote - same shape, same validation and the same live price table as /api/quote, but nothing is written and no chain is involved. Exists because trying the flow used to cost real USDT and gas, which is a poor reason not to integrate. It cannot serve real data; that is the point, not a limitation","parameters":[{"name":"city","in":"query","required":false,"description":"Slug, or cities= for a bundle","schema":{"type":"string"}},{"name":"from","in":"query","required":true,"description":"YYYY-MM-DD","schema":{"type":"string"}},{"name":"to","in":"query","required":true,"description":"YYYY-MM-DD","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sandbox/claim":{"post":{"summary":"Sandbox claim - { quoteId, txHash }. The hash is only checked for shape; no chain call is made. The response lists differencesFromLive so you do not build against behaviour the real path does not have","parameters":[],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sandbox/download/{id}":{"get":{"summary":"Sandbox dataset - synthetic hourly rows, deterministic for a given city and date, with verdicts mixed to match the real distribution measured on 2026-08-06 (71% verified) so your settlement branch gets exercised - the live figure moves, and /api/v1/quality is what reports it now. Applies the same 425 delivery gate as the live download","parameters":[{"name":"id","in":"path","required":true,"description":"purchaseId from the sandbox claim","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/quality":{"get":{"summary":"Per-city settlement quality - the share of hours over the last 7 and 30 days whose verdict was 'verified', with a per-verdict breakdown and an A/B/C grade. Use this to see how much of a period you are about to buy would actually be settle-eligible; the ratio varies a lot by city because the measurement network around each one does","parameters":[{"name":"city","in":"query","required":false,"description":"City slug - omit for every city","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/index/history":{"get":{"summary":"Consensus and WDI/TDI time series per collection run. Paid: subscription (unlimited for covered cities) or metered key (one credit per call - the form for republishing to your own customers). 402 without a credential","security":[{"bearerToken":[]}],"parameters":[{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"},{"name":"limit","in":"query","required":false,"description":"Runs to return, up to 500 (default 96)","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/index/sources":{"get":{"summary":"Per-source raw readings behind each run's consensus, with the outliers that were excluded. Paid, same credentials as history. The rule that decides exclusion is not returned","security":[{"bearerToken":[]}],"parameters":[{"name":"city","in":"query","required":true,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"},{"name":"limit","in":"query","required":false,"description":"Runs to return, up to 500 (default 48)","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/realtime":{"get":{"summary":"5-minute METAR observation records (7-day window, paginated). Paid, same credentials as history","security":[{"bearerToken":[]}],"parameters":[{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"},{"name":"page","in":"query","required":false,"description":"1-based page number","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/index/snapshots":{"get":{"summary":"Snapshot list with the anchor transactions on each ledger. Pass `sha256` (or `runId`) to look up one run instead of the recent list - a settlement contract holding only `DeterminationRegistry.determinations(h).snapshotSha256` needs this to find the XRPL transaction it must attest before `isSettlementGrade` can turn true","parameters":[{"name":"limit","in":"query","required":false,"description":"Recent runs to return, up to 200 (default 50)","schema":{"type":"string"}},{"name":"sha256","in":"query","required":false,"description":"Look up one run by its canonical snapshot hash (0x prefix optional)","schema":{"type":"string"}},{"name":"runId","in":"query","required":false,"description":"Look up one run by its run identifier","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/index/snapshot/{runId}":{"get":{"summary":"Canonical snapshot bytes - SHA-256 matches the on-chain anchor. Paid: the snapshot covers every city, so a metered key (one credit) or a subscription covering the whole catalogue. Without a credential the 402 still carries sha256 and the anchor tx, so the commitment is checkable by anyone","security":[{"apiKey":[]}],"parameters":[{"name":"runId","in":"path","required":true,"description":"From /api/index/snapshots","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sub/live":{"get":{"summary":"Subscriber live index + verdict oracle. One key opens every city the paying wallet subscribes to - name the city with ?city=. Buying another city adds it to the same key with no new credential","security":[{"bearerToken":[]}],"parameters":[{"name":"city","in":"query","required":true,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sub/forecast":{"get":{"summary":"Subscriber forecast (Open-Meteo + KWeather, nSources per row), any covered city. tz=station re-cuts the daily rows on the station's local calendar day and adds a local time to every hourly row","security":[{"bearerToken":[]}],"parameters":[{"name":"city","in":"query","required":true,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"},{"name":"tz","in":"query","required":false,"description":"utc (default) or station - the day boundary; every response says which in dayBasis","schema":{"type":"string"}},{"name":"units","in":"query","required":false,"description":"metric (default: °C, m/s, mm) or imperial (°F, mph, in) - converted once, on our side; the units block says which","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sub/history":{"get":{"summary":"Subscriber history within the subscribed window, any covered city. format=csv returns a file. tz=station re-cuts the rows on the station's local calendar day (daylight saving applied) with UTC bounds per row","security":[{"bearerToken":[]}],"parameters":[{"name":"city","in":"query","required":true,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"},{"name":"from","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string"}},{"name":"format","in":"query","required":false,"description":"csv for a downloadable file","schema":{"type":"string"}},{"name":"tz","in":"query","required":false,"description":"utc (default) or station - the day boundary; every response says which in dayBasis","schema":{"type":"string"}},{"name":"units","in":"query","required":false,"description":"metric (default) or imperial (°F, mph, in)","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/metar-watch/report":{"get":{"summary":"Public, free. How the METAR feed prediction markets settle on actually behaves, measured every minute: per station the delay from observation to NOAA receipt, late reports, silent stretches, and reports corrected after publication (original text kept). Our own watcher's outages are reported and excluded","parameters":[{"name":"days","in":"query","required":false,"description":"Window in days, 1-30 (default 7; never before the one-minute watcher started)","schema":{"type":"string"}},{"name":"icao","in":"query","required":false,"description":"One station, e.g. KJFK","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/forecast-watch/report":{"get":{"summary":"Public, free. Forecast Watch: each weather model's own forecast for a station's local day, archived once a day 1 to 7 days ahead (ECMWF, NOAA GFS, DWD ICON, UKMO, Météo-France, JMA, ECCC GEM and the Open-Meteo blend) scored against the anchored station record once the day is final and settleable. Per source and lead day: MAE and bias of the daily high and low (°C), share within 1/2 °C, rain yes/no hit rate; per station the next-day daily-high MAE by source and the days each source was scored on. WeatherNext 3 is listed as pending until its data access is granted","parameters":[{"name":"days","in":"query","required":false,"description":"Trailing window in days up to today, 7-90 (default 30); ignored when from/to are given","schema":{"type":"string"}},{"name":"icao","in":"query","required":false,"description":"One station, e.g. KJFK","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"Fixed window: first station-local day (YYYY-MM-DD), with `to`. The response says window: fixed and repeats the bounds as windowStart / windowEnd (exclusive)","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"Fixed window: last station-local day, inclusive; at most 90 days after `from`","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/station/{icao}/daily/record":{"get":{"summary":"The canonical bytes of a station day's record (every METAR text, extremes, finality reasons; keys sorted, no whitespace). For an anchored day these are the exact bytes whose SHA-256 was written to SnapshotAnchor on Flare: hash the body, compare with X-Record-Sha256, and call isAnchored(sha256) on-chain to verify without us. Paid, same credentials as history","security":[{"bearerToken":[]}],"parameters":[{"name":"icao","in":"path","required":true,"description":"ICAO station code","schema":{"type":"string"}},{"name":"date","in":"query","required":true,"description":"YYYY-MM-DD, station-local","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/station/{icao}/observations":{"get":{"summary":"The station's METAR observations as received - raw text, observation time in UTC and station-local time, derived temperature/dewpoint/humidity/wind and whether precipitation was reported. from/to are station-local dates. Paid, same credentials as history","security":[{"bearerToken":[]}],"parameters":[{"name":"icao","in":"path","required":true,"description":"ICAO station code from /api/cities (e.g. KMIA)","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"YYYY-MM-DD, station-local","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"YYYY-MM-DD, station-local","schema":{"type":"string"}},{"name":"page","in":"query","required":false,"description":"1-based page number","schema":{"type":"string"}},{"name":"pageSize","in":"query","required":false,"description":"up to 500 (default 100)","schema":{"type":"string"}},{"name":"units","in":"query","required":false,"description":"metric (default: °C, m/s) or imperial (°F, mph); raw METAR text is never converted","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/station/{icao}/daily":{"get":{"summary":"One station-local calendar day (local midnight to midnight, daylight saving applied): high and low with the observation that produced each, wind max/mean, humidity mean, precipitation-reported count, the exact UTC window, and every observation of the day. finality says whether the day is open / provisional / final (3-hour correction hold after local midnight) and settleable (final with no report gap beyond the station's normal interval + 30 min); revision, lastChangedAt and corrections make any change after first publication detectable; anchor carries the Flare SnapshotAnchor transaction once the final record is written on-chain. values.metarDerived and values.nwsOfficial sit side by side (the NWS CLI side is null until ingestion; official.status says so). qc attaches per-report quality flags (good / suspect / bad with reasons: physical limits, dewpoint above temperature, temperature step, persistence) beside the record without changing its bytes, flags the reports behind the extremes, and gives the extremes excluding bad reports. Paid, same credentials as history","security":[{"bearerToken":[]}],"parameters":[{"name":"icao","in":"path","required":true,"description":"ICAO station code from /api/cities (e.g. KMIA)","schema":{"type":"string"}},{"name":"date","in":"query","required":false,"description":"YYYY-MM-DD, station-local (default: the station's today)","schema":{"type":"string"}},{"name":"units","in":"query","required":false,"description":"metric (default: °C, m/s, mm) or imperial (°F, mph, in). The anchored record and its SHA-256 stay metric","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/station/{icao}/days":{"get":{"summary":"One row per station-local calendar day over a range (up to 62 days): the same extremes, finality, revision, anchor status and official.status as /daily, without the per-report lists, plus a summary with the period's highest tmax and lowest tmin, the days that are not final or not settleable, and the days whose extremes came from a suspect or bad report (qc per row). One call for a month market; settle only when summary.allSettleable is true. Paid, same credentials as history","security":[{"bearerToken":[]}],"parameters":[{"name":"icao","in":"path","required":true,"description":"ICAO station code from /api/cities (e.g. KJFK)","schema":{"type":"string"}},{"name":"from","in":"query","required":true,"description":"YYYY-MM-DD, station-local","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"YYYY-MM-DD, station-local (default: the station's today)","schema":{"type":"string"}},{"name":"units","in":"query","required":false,"description":"metric (default) or imperial (°F, mph, in)","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sub/{purchaseId}/live":{"get":{"summary":"Same data, addressed by purchase. Kept for existing integrations - prefer /api/sub/live","security":[{"bearerToken":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"description":"Subscription purchase ID","schema":{"type":"string"}},{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sub/{purchaseId}/forecast":{"get":{"summary":"Same data, addressed by purchase - prefer /api/sub/forecast","security":[{"bearerToken":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"description":"Subscription purchase ID","schema":{"type":"string"}},{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sub/{purchaseId}/history":{"get":{"summary":"Same data, addressed by purchase - prefer /api/sub/history","security":[{"bearerToken":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"description":"Subscription purchase ID","schema":{"type":"string"}},{"name":"city","in":"query","required":false,"description":"City slug from /api/cities","schema":{"type":"string"},"example":"seoul"},{"name":"from","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"YYYY-MM-DD","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/sub/{purchaseId}/token":{"post":{"summary":"Issue, list and revoke subscription access tokens. The plaintext is returned once; only its SHA-256 is stored. A token minted from any active subscription opens every city that wallet subscribes to","security":[{"walletSignature":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"description":"Subscription purchase ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}},"get":{"summary":"Issue, list and revoke subscription access tokens. The plaintext is returned once; only its SHA-256 is stored. A token minted from any active subscription opens every city that wallet subscribes to","security":[{"walletSignature":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"description":"Subscription purchase ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}},"delete":{"summary":"Issue, list and revoke subscription access tokens. The plaintext is returned once; only its SHA-256 is stored. A token minted from any active subscription opens every city that wallet subscribes to","security":[{"walletSignature":[]}],"parameters":[{"name":"purchaseId","in":"path","required":true,"description":"Subscription purchase ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/health":{"get":{"summary":"Public: overall status, data age against the expected hourly interval, low-consensus city count, anchoring backlog, and whether payment is operational. 503 when unhealthy. Deployment identifiers, transaction hashes and internal remediation steps are returned only with an admin credential - a status endpoint should say whether the service works, not describe how it is built","parameters":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Health"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}},"/api/v1/mcp":{"post":{"summary":"MCP server (Streamable HTTP). Free read-only tools: list_cities, get_consensus_index, get_source_breakdown, get_forecast, verify_snapshot, get_pricing","parameters":[],"responses":{"200":{"description":"Success"},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid credential","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Payment required (metered endpoints)"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already processed. Claims and top-ups are keyed by transaction hash, so the same hash is only ever honoured once. Do not retry - the first request already took effect. (On /claim this also covers 'awaiting confirmation', which you may retry.)"},"425":{"description":"Too early - the purchased period has not ended. The body carries availableFrom; schedule for that date rather than retrying"},"429":{"description":"Rate limited. Retry-After carries the seconds to wait; honour it rather than retrying immediately","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait"},"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests per minute for this path"}}},"503":{"description":"Not available yet - retry after the interval in Retry-After"}}}}}}