# Isocast — Polymarket weather-signal API for AI agents (v1.0.0) > Agents pay per-signal bundles via x402 and get pushed (Telegram) the instant a city's > daily-high temperature crosses into a new Polymarket bucket — market URL, old/new reading, > and live odds for every bucket. 37 cities. Free to browse (cities, sample, pricing, terms); > paid signal reads settle USDC on Base. Informational data only — not financial or betting advice. ## Base URL - API: https://api.isocast.dev - This document: https://api.isocast.dev/llms.txt · Extended: /llms-full.txt · Topic: /llms/weather-signals - Discovery (JSON): https://api.isocast.dev/discovery - OpenAPI 3.1: https://api.isocast.dev/openapi.json - x402 manifest: https://api.isocast.dev/.well-known/x402 - Agent card (A2A): https://api.isocast.dev/.well-known/agent-card.json - Terms: https://isocast.dev/terms ## What a signal is When a city's observed daily-high temperature crosses out of one Polymarket temperature bucket and into another, Isocast emits ONE signal for that (city, day, transition). It carries: the Polymarket market URL + conditionId, the old and new {reading, unit, bucket}, and live YES/NO/midpoint odds for EVERY bucket (with `dead: true` on buckets the day can no longer reach), plus `bucketsAsOf` (odds freshness, ≤ ~10s) and `observedAt`. `seq` is a monotonic per-city counter; delivery is at-most-once per (city, day, bucket). See /llms/weather-signals for semantics. ## Free endpoints (no auth, no payment) | Method | Path | Description | |--------|------|-------------| | GET | /health | Liveness + payment mode (live\|mock) + OFAC status | | GET | /v1/cities | All active cities (slug, unit, bucketWidth, timezone, latestSeq). 30s cache | | GET | /v1/cities/:slug | One city + today's targetDate + Polymarket marketUrl | | GET | /v1/sample?city=SLUG | Promo signal — fixed seq-1 (never latest); synthetic fallback. `sample:true` | | GET | /v1/signals/meta?city=SLUG | Pricing + payment metadata (unitPriceUsd, minSpendUsd, tiers, payTo, network). Never returns signal rows | | GET | /terms.txt · /terms.json | Terms of Service (also sets X-Terms-URL) | | POST | /v1/delivery/telegram | Register/change Telegram chat_id (FREE, EIP-712 signed) — see below | Every JSON object response also carries a `disclaimer` string. ## Paid flow (x402, USDC on Base, network eip155:8453) Signals are sold in prepaid bundles per city. Two paid routes: - `POST /v1/subscribe?city=SLUG&count=N` — buy the next N signals for a city (N integer ≥ 2, total ≥ $0.01) - `GET /v1/signals?city=SLUG&since=S&count=N` — read signals you're entitled to Walkthrough: 1. `POST /v1/subscribe?city=istanbul&count=20` with no payment → **402** PaymentRequired: ```json { "x402Version": 1, "accepts": [{ "scheme": "exact", "network": "eip155:8453", "price": "$0.1", "payTo": "0x…", "description": "Isocast: next 20 istanbul weather signals", "mimeType": "application/json" }], "extra": { "binding": { "formula": "keccak256(abi.encodePacked(payer, citySlug, uint256 count, bytes32 salt))", "citySlug": "istanbul", "count": 20, "salt": "0x…" } }, "terms": "https://isocast.dev/terms" } ``` 2. Construct the EIP-3009 `exact` USDC authorization on Base. The authorization **nonce** MUST be (formula VERBATIM): nonce = keccak256(abi.encodePacked(payer, citySlug, uint256 count, bytes32 salt)) using the `salt` served in `extra.binding` (salt is server-derived; you cannot compute it yourself). This binds the payment to (payer, citySlug, count) so it can't be replayed against a different city/count. The server recomputes the expected nonce from the recovered payer and the requested (city, count) and rejects any mismatch BEFORE settling. 3. Retry `POST /v1/subscribe?city=istanbul&count=20` with the `X-Payment` header. Server flow is settle-early: verify → OFAC screen → nonce-binding check → settle → record payment → apply entitlement (atomic). On success → **200**: ```json { "ok": true, "city": "istanbul", "count": 20, "unitPriceUsd": 0.005, "amountUsd": 0.1, "latestSeq": 41, "paidThroughSeq": 61, "receiptToken": "…", "txHash": "0x…", "idempotent": false } ``` Entitlement is `paidThroughSeq = max(current, latestSeq) + count`. No expiry. Re-submitting the same settlement is idempotent (nothing re-applied). 4. Poll `GET /v1/signals?city=istanbul&since=41` with `Authorization: Bearer `: returns signals with `since < seq ≤ paidThroughSeq`, ascending, ≤100/page, plus `next_cursor`, `paid_through`, `latest`, `more`. On exhaustion (`since ≥ paidThroughSeq`) → **402** with `paid_through` + `latest` so you know how many more to buy. (You may also pay inline on /v1/signals with an X-Payment header instead of a receipt token.) ## Volume tiers (effective unit price drops with bundle size) | Tier | minCount | $/signal | |------|----------|----------| | Min | 2 | 0.005 | | Starter | 20 | 0.005 | | Standard | 100 | 0.0045 | | Pro | 500 | 0.004 | | Whale | 2000 | 0.0035 | Minimum spend $0.01 USDC. Bundle price range ≈ $0.01–$7.00. ## Telegram delivery (FREE — no payment ever) `POST /v1/delivery/telegram` registers/changes/deletes the chat that receives your entitled signals. Authorised by an EIP-712 signature that must recover to `wallet`: - Domain: `{ name: "Isocast", version: "1", chainId: 8453 }` - primaryType `TelegramDelivery`, fields (in order): `wallet: address`, `chatId: string`, `citySlug: string`, `action: string`, `timestamp: uint256` - Body: `{ wallet, chatId, citySlug, action: "set"|"delete", signature, timestamp }` (`timestamp` = unix seconds, ≤600s skew; empty `citySlug` = all cities; `set` sends a Telegram test message before persisting — unreachable chat → 502.) ## Errors - 400 — count < 2 / non-integer, or below $0.01 min spend (body has `minSpendUsd`) - 402 — payment required / binding mismatch / verification or settlement failed (you were not charged) - 403 — payer wallet sanctioned (refused, never settled) - 404 — unknown/inactive city - 502 — charged but entitlement update failed → `{ refund: "queued" }` - 503 — sanctions screening unavailable (fail-closed, nothing settled) ## Disclaimer Informational data only; not financial or betting advice. No guarantee of accuracy or outcome. User assumes all risk. Prediction markets restricted in some jurisdictions. Terms: https://isocast.dev/terms