For curious neighbours

Local weather, made useful.

The public API serves current conditions and minute history. Approved neighbours can request the full 2.5-second wind feed through a shared Tailscale service.

01 · Public API

No key required.

Read-only endpoints use JSON, explicit units, ISO timestamps, archive coverage, and permissive CORS. Minute requests are capped at 31 days, hourly requests at 366 days, and longer windows use daily resolution. Add bucketMinutes=15 to combine minute readings into compact 15-minute trend points, or format=csv to download the selected range.

GET/api/v1/current
GET/api/v1/history?from=&to=&resolution=minute&bucketMinutes=
GET/api/v1/records?period=all|year|month
GET/api/v1/events?type=&from=&to=
GET/api/v1/forecast
GET/api/v1/air-quality
GET/api/v1/summary
curl https://coltonweather.com/api/v1/current

const response = await fetch(
  "https://coltonweather.com/api/v1/current"
);
const weather = await response.json();
02 · Response schema

Stable, versioned JSON.

Missing measurements are returned as null, never invented. Device IDs, exact coordinates, and private network details are omitted.

{
  "schemaVersion": "1.0",
  "mode": "live",
  "observedAt": "2026-07-25T23:14:00.000Z",
  "freshnessSeconds": 2,
  "conditions": {
    "temperatureF": 68.4,
    "feelsLikeF": 68.4,
    "humidityPct": 62,
    "windSpeedMph": 11.2,
    "windDirectionDeg": 247,
    "solarRadiationWm2": 426,
    "uvIndex": 4.2
  },
  "quality": {
    "fresh": true,
    "rapidFeedConnected": true
  }
}

/api/v1/summary returns the short observational phrase generated about every 30 minutes. Treat generatedAt as the freshness authority; clients should hide phrases older than their own display limit.

{
  "schemaVersion": "1.0",
  "text": "Soft gray air settles damply over the Oakland Hills.",
  "generatedAt": "2026-07-27T16:30:00.000Z",
  "imageCapturedAt": "2026-07-27T16:29:42.000Z",
  "model": "gemini-2.5-flash",
  "weatherSource": "Davis WeatherLink Live"
}

/api/v1/air-quality uses schema 1.1. When available, current is an EPA-corrected, 10-minute PM2.5 reading from nearby PurpleAir sensor 72609 while hourly remains the Open-Meteo / CAMS modeled outlook. Check currentSource and forecastSource before labeling either value.

{
  "schemaVersion": "1.1",
  "mode": "hybrid",
  "current": {
    "time": "2026-07-28T15:20:00.000Z",
    "usAqi": 31,
    "pm25": 5.6
  },
  "currentSource": {
    "kind": "sensor",
    "source": "PurpleAir",
    "sensorIndex": 72609,
    "averagingMinutes": 10,
    "correction": "EPA extended cf_atm"
  },
  "forecastSource": {
    "source": "Open-Meteo",
    "provider": "CAMS",
    "modelResolutionKm": 45
  }
}
03 · Rapid feed

Wind every 2.5 seconds.

The LAN broadcast comes from a Davis WeatherLink Live gateway (SKU 6100) and terminates at the home collector. Tailscale then shares only that collector—not the camera, WeatherLink device, or home subnet.

  • WebSocket: wss://collector.<tailnet>.ts.net/v1/live
  • UDP: send {"type":"subscribe","ttl":60} to collector port 22222 and renew once a minute.
  • REST snapshot: /v1/current
04 · Freshness

Stale is a real state.

Every response includes source and receipt times. Wind and rain rapid packets are normally 2.5 seconds apart; the full current-conditions document is polled every 10 seconds. Clients should check quality.fresh andfreshnessSeconds.