✈
    TravelmodeDevelopers
    🔎/
    🔑Manage API Keys
    Feature
    🌦️Weather🛂Visa🧩Platform🧭Trips🤖Agent Runs📅Events

    Weather Intelligence API · v1

    📖Overview🧪API Reference (Try It)
    Guides
    🚀Getting Started🔐Authentication⏱️Rate Limits📡Endpoints⚠️Errors🪝Watch Webhooks💳Billing🧊Cache & Freshness📝Attribution
    ⬇️Download openapi.yaml
    Developers / Weather / Endpoints

    Endpoints

    Last verified: 2026-05-03 (Task #334 — docs accuracy pass).

    Reference for every Weather Intelligence endpoint. The OpenAPI spec in openapi.yaml is the source of truth for full schemas — the sections here cover the human-readable summary, the required scope, and at least one paired request + response example per endpoint.

    Response envelope

    Every successful response returns:

    {
      "data": <endpoint-specific payload>,
      "meta": {
        "request_id": "uuid",
        "generated_at": "iso-8601",
        "environment": "production",
        "cache_status": "HIT|MISS|STALE|MIXED",
        "snapshot_id": "uuid",
        "billing_units": 1,
        "items_analyzed": 1,
        "segments_analyzed": 0,
        "units": "metric",
        "language": "en"
      }
    }
    

    meta.cache_status, meta.snapshot_id, meta.items_analyzed, and meta.segments_analyzed are populated only on the endpoints they make sense for. Errors share the same meta block but ship the payload under error instead of data (see errors.md).

    Standard headers on every response

    HeaderNotes
    X-Request-IdSame value as meta.request_id.
    X-Cache-StatusSame value as meta.cache_status (when applicable).
    X-Weather-Snapshot-IdSame value as meta.snapshot_id (when applicable).
    X-RateLimit-LimitCap for the requests quota dimension on the calling plan.
    X-RateLimit-RemainingRequests left in the current monthly window.
    X-RateLimit-ResetUnix-seconds when the monthly window rolls over.

    Current weather

    GET /v1/weather/current  ·  Scope: weather:read  ·  Bills: 1 unit

    Query parameters

    NameRequiredNotes
    latyes-90 to 90
    lngyes-180 to 180
    unitsnometric (default), imperial, standard
    languagenoBCP-47 (en, en-GB, …)
    activity_typenoFree-form. Unknown values fall back to the outdoor default profile.

    Request

    curl -s "https://api.travelmode.ai/v1/weather/current?lat=48.8566&lng=2.3522" \
      -H "Authorization: Bearer tm_weather_..."
    

    Response (200 OK)

    {
      "data": {
        "location": {
          "lat": 48.8566, "lng": 2.3522,
          "geohash": "u09tu", "geohash_precision": 5,
          "timezone": "Europe/Paris", "place_type": "city"
        },
        "current": {
          "observed_at": "2026-04-25T18:00:00.000Z",
          "temperature": 14.2, "feels_like": 12.9,
          "humidity_pct": 71, "pressure_hpa": 1013,
          "wind": { "speed_ms": 4.1, "gust_ms": 7.2, "direction_deg": 220 },
          "cloud_cover_pct": 75, "visibility_m": 10000,
          "uv_index": 1, "precipitation_mm": 0.2,
          "condition": { "code": "500", "label": "light rain", "icon": "10d" }
        },
        "alerts": [],
        "risk": { "level": "low", "reasons": [], "recommendation": null, "activity_type": null },
        "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
        "provider": "openweather",
        "provider_version": "onecall/3.0",
        "attribution": "Weather data provided by OpenWeather",
        "fetched_at": "2026-04-25T18:01:13.412Z"
      },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-04-25T18:01:13.500Z",
        "environment": "production",
        "cache_status": "HIT",
        "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
        "billing_units": 1,
        "units": "metric",
        "language": "en"
      }
    }
    

    Forecast

    GET /v1/weather/forecast  ·  Scope: weather:read  ·  Bills: 1 unit (daily) / 2 units (hourly)

    Query parameters

    NameRequiredNotes
    latyes
    lngyes
    daysno1–8 (default 7). Clamped to provider max.
    granularitynodaily (default) or hourly.
    units, languagenoSame as current.

    Request

    curl -s "https://api.travelmode.ai/v1/weather/forecast?lat=48.8566&lng=2.3522&days=3&granularity=daily" \
      -H "Authorization: Bearer tm_weather_..."
    

    Response (200 OK)

    {
      "data": {
        "location": { "lat": 48.8566, "lng": 2.3522, "geohash": "u09tu", "geohash_precision": 5, "timezone": "Europe/Paris", "place_type": "city" },
        "granularity": "daily",
        "days": 3,
        "hourly": null,
        "daily": [
          {
            "local_date": "2026-04-26",
            "sunrise": "2026-04-26T04:55:00.000Z",
            "sunset":  "2026-04-26T18:55:00.000Z",
            "temperature": { "min": 8.1, "max": 16.4 },
            "feels_like":  { "min": 6.9, "max": 15.2 },
            "humidity_pct": 65,
            "wind": { "speed_ms": 3.2, "gust_ms": 6.1, "direction_deg": 200 },
            "cloud_cover_pct": 40,
            "precipitation_mm": 1.2,
            "precipitation_probability_pct": 35,
            "uv_index_max": 5,
            "condition": { "code": "500", "label": "light rain", "icon": "10d" }
          }
        ],
        "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
        "provider": "openweather",
        "provider_version": "onecall/3.0",
        "attribution": "Weather data provided by OpenWeather",
        "fetched_at": "2026-04-25T18:01:13.412Z"
      },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-04-25T18:01:13.500Z",
        "environment": "production",
        "cache_status": "HIT",
        "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
        "billing_units": 1,
        "items_analyzed": 3,
        "units": "metric",
        "language": "en"
      }
    }
    

    The daily array is shown trimmed to one entry for brevity — a real days=3 response carries three entries (and days=7 carries seven).


    Timeline

    POST /v1/weather/timeline  ·  Scope: weather:timeline  ·  Bills: 2 units × items_analyzed

    Accepts up to 100 items per call. Each item gets weather + risk; the response also carries an aggregate summary (overall risk, main issue, best outdoor window).

    activity_type is free-form. Canonical MVP values: walking, walking_tour, hiking, beach, dining, outdoor_dining, museum, shopping, driving, train, ferry, cycling, airport_transfer, event, sightseeing, free_time.

    Request

    curl -s -X POST "https://api.travelmode.ai/v1/weather/timeline" \
      -H "Authorization: Bearer tm_weather_..." \
      -H "Content-Type: application/json" \
      -d '{
        "units": "metric",
        "language": "en",
        "items": [
          {
            "id": "morning_walk",
            "start": "2026-05-15T08:00:00.000Z",
            "end":   "2026-05-15T09:30:00.000Z",
            "lat": 48.8566, "lng": 2.3522,
            "activity_type": "walking_tour",
            "timezone": "Europe/Paris"
          },
          {
            "id": "louvre_visit",
            "start": "2026-05-15T10:00:00.000Z",
            "end":   "2026-05-15T13:00:00.000Z",
            "lat": 48.8606, "lng": 2.3376,
            "activity_type": "museum",
            "timezone": "Europe/Paris"
          }
        ]
      }'
    

    Response (200 OK)

    {
      "data": {
        "items": [
          {
            "id": "morning_walk",
            "activity_type": "walking_tour",
            "outdoor": true,
            "start": "2026-05-15T08:00:00.000Z",
            "weather": {
              "observed_at": "2026-05-15T08:00:00.000Z",
              "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
              "cache_status": "HIT",
              "temperature_c": 12.4, "feels_like_c": 11.2,
              "condition": "light rain",
              "precipitation_probability": 65,
              "precipitation_intensity_mm_h": 1.2,
              "wind_speed_kph": 14.4, "wind_gust_kph": 22.0,
              "uv_index": 2
            },
            "risk": {
              "level": "watch",
              "reasons": [
                { "code": "rain_likely", "level": "watch", "message": "Light rain likely (65% chance)" }
              ],
              "recommendation": "Bring a rain jacket; light rain expected during your walking tour."
            }
          },
          {
            "id": "louvre_visit",
            "activity_type": "museum",
            "outdoor": false,
            "start": "2026-05-15T10:00:00.000Z",
            "weather": {
              "observed_at": "2026-05-15T10:00:00.000Z",
              "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
              "cache_status": "HIT",
              "temperature_c": 13.0, "feels_like_c": 12.0,
              "condition": "light rain",
              "precipitation_probability": 60,
              "precipitation_intensity_mm_h": 0.8,
              "wind_speed_kph": 12.6, "wind_gust_kph": 20.5,
              "uv_index": 2
            },
            "risk": { "level": "low", "reasons": [] }
          }
        ],
        "summary": {
          "overall_risk": "watch",
          "main_issue": "Light rain likely (65% chance) for walking tour at 10:00 AM",
          "best_outdoor_window": {
            "start": "2026-05-15T13:00:00.000Z",
            "end":   "2026-05-15T17:00:00.000Z",
            "level": "low"
          }
        }
      },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-04-25T18:01:13.500Z",
        "environment": "production",
        "cache_status": "HIT",
        "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
        "billing_units": 4,
        "items_analyzed": 2,
        "units": "metric",
        "language": "en"
      }
    }
    

    Validation errors

    CodeWhen
    bad_requestTop-level body failed schema (missing items, etc).
    timeline_item_invalidIndividual item failed validation. details carries index, field, and issues.

    Route

    POST /v1/weather/route  ·  Scope: weather:route  ·  Bills: 3 units × segments_analyzed

    Samples points along a route and returns weather + risk per segment, plus an overall_risk summary.

    transport_mode is one of car, bus, train, ferry, walking, cycling, shuttle, transfer. The optional polyline field accepts an encoded Google polyline string, an array of [lat, lng] tuples, or an array of { lat, lng } objects. When omitted, the analyzer samples a great-circle line between origin and destination.

    Request

    curl -s -X POST "https://api.travelmode.ai/v1/weather/route" \
      -H "Authorization: Bearer tm_weather_..." \
      -H "Content-Type: application/json" \
      -d '{
        "origin":      { "lat": 48.8566, "lng": 2.3522 },
        "destination": { "lat": 49.2583, "lng": 4.0317 },
        "transport_mode": "car",
        "start_time": "2026-05-15T12:00:00.000Z",
        "units": "metric",
        "language": "en"
      }'
    

    Response (200 OK)

    {
      "data": {
        "origin":      { "lat": 48.8566, "lng": 2.3522 },
        "destination": { "lat": 49.2583, "lng": 4.0317 },
        "transport_mode": "car",
        "segments": [
          {
            "index": 0,
            "start_point": { "lat": 48.8566, "lng": 2.3522 },
            "end_point":   { "lat": 49.0571, "lng": 3.1920 },
            "start_time":  "2026-05-15T12:00:00.000Z",
            "end_time":    "2026-05-15T13:00:00.000Z",
            "distance_m": 67000, "duration_minutes": 60,
            "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
            "cache_status": "HIT",
            "condition": {
              "label": "clear", "temperature_c": 17.2,
              "wind_speed_kph": 16.0, "wind_gust_kph": 24.0,
              "precipitation_mm": 0.0, "visibility_km": 10.0
            },
            "risk": { "level": "low", "reasons": [], "recommendation": null }
          },
          {
            "index": 1,
            "start_point": { "lat": 49.0571, "lng": 3.1920 },
            "end_point":   { "lat": 49.2583, "lng": 4.0317 },
            "start_time":  "2026-05-15T13:00:00.000Z",
            "end_time":    "2026-05-15T14:00:00.000Z",
            "distance_m": 76000, "duration_minutes": 60,
            "snapshot_id": "8a8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e7a",
            "cache_status": "MISS",
            "condition": {
              "label": "heavy rain", "temperature_c": 14.8,
              "wind_speed_kph": 38.0, "wind_gust_kph": 60.0,
              "precipitation_mm": 4.5, "visibility_km": 4.0
            },
            "risk": {
              "level": "warning",
              "reasons": [
                { "code": "heavy_rain", "level": "warning", "message": "Heavy rain reduces visibility" }
              ],
              "recommendation": "Slow down and consider stopping if visibility drops further."
            }
          }
        ],
        "overall_risk": {
          "level": "warning",
          "reasons": [
            { "code": "heavy_rain", "level": "warning", "message": "Heavy rain reduces visibility" }
          ],
          "recommendation": "Slow down and consider stopping if visibility drops further.",
          "main_issue": "Heavy rain on the second leg of the drive"
        }
      },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-04-25T12:00:13.500Z",
        "environment": "production",
        "cache_status": "MIXED",
        "snapshot_id": "8a8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e7a",
        "billing_units": 6,
        "segments_analyzed": 2,
        "units": "metric",
        "language": "en"
      }
    }
    

    Validation errors

    CodeWhen
    route_invalidBody failed schema (bad coords, malformed polyline, unknown transport).

    Watches

    All three watch endpoints require the weather:watch scope.

    Create a watch

    POST /v1/weather/watch  ·  Bills: 1 unit + 1/day per active watch

    A watch monitors a place / timeline item / route window / trip. Whenever the upstream snapshot moves enough to cross one of the watch's change_rules, a weather.change_detected event is recorded and dispatched to the configured webhook URL. change_rules is optional — defaults from PRD §18.2 are merged in for any field you don't supply.

    The webhook_url you set here is POSTed directly with a signed JSON envelope (no /v1/webhooks registration needed). See watch-webhooks.md for the headers, the HMAC-SHA256 signature formula, the payload shape, and the retry/backoff behaviour you need to verify and trust those calls.

    Request

    curl -s -X POST "https://api.travelmode.ai/v1/weather/watch" \
      -H "Authorization: Bearer tm_weather_..." \
      -H "Content-Type: application/json" \
      -d '{
        "target_type": "place",
        "target_ref": { "place_id": "city:paris" },
        "latitude":  48.8566,
        "longitude": 2.3522,
        "place_type": "city",
        "activity_type": "walking_tour",
        "outdoor": true,
        "starts_at": "2026-05-15T00:00:00.000Z",
        "ends_at":   "2026-05-22T00:00:00.000Z",
        "webhook_url": "https://example.com/hooks/weather"
      }'
    

    Response (201 Created)

    {
      "data": {
        "watch_id": "1f8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6a",
        "status": "active",
        "target_type": "place",
        "target_ref": { "place_id": "city:paris" },
        "starts_at": "2026-05-15T00:00:00.000Z",
        "ends_at":   "2026-05-22T00:00:00.000Z",
        "change_rules": {
          "precipitation_probability_delta": 30,
          "temperature_c_delta": 5,
          "wind_kph_delta": 20,
          "uv_index_delta": 3,
          "detect_severe_alerts": true,
          "detect_risk_level_change": true
        },
        "activity_type": "walking_tour",
        "transport_mode": null,
        "outdoor": true,
        "webhook_url": "https://example.com/hooks/weather",
        "next_check_at": "2026-05-15T00:00:00.000Z",
        "created_at": "2026-04-25T18:01:13.500Z"
      },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-04-25T18:01:13.500Z",
        "environment": "production",
        "billing_units": 1
      }
    }
    

    Get a watch

    GET /v1/weather/watch/{watch_id}  ·  Bills: 1 unit

    Returns the watch hydrated with its latest snapshot, latest risk assessment, and the most recent change events. Returns 404 if the watch isn't owned by the calling developer account.

    Request

    curl -s "https://api.travelmode.ai/v1/weather/watch/1f8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6a" \
      -H "Authorization: Bearer tm_weather_..."
    

    Response (200 OK)

    {
      "data": {
        "watch_id": "1f8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6a",
        "status": "active",
        "target_type": "place",
        "target_ref": { "place_id": "city:paris" },
        "latitude": 48.8566,
        "longitude": 2.3522,
        "starts_at": "2026-05-15T00:00:00.000Z",
        "ends_at":   "2026-05-22T00:00:00.000Z",
        "change_rules": {
          "precipitation_probability_delta": 30,
          "temperature_c_delta": 5,
          "wind_kph_delta": 20,
          "uv_index_delta": 3,
          "detect_severe_alerts": true,
          "detect_risk_level_change": true
        },
        "activity_type": "walking_tour",
        "transport_mode": null,
        "outdoor": true,
        "webhook_url": "https://example.com/hooks/weather",
        "next_check_at": "2026-05-15T00:30:00.000Z",
        "last_checked_at": "2026-05-15T00:15:00.000Z",
        "last_risk_level": "low",
        "failure_count": 0,
        "created_at": "2026-04-25T18:01:13.500Z",
        "updated_at": "2026-05-15T00:15:00.000Z",
        "expired_at": null,
        "latest_snapshot": {
          "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
          "forecast_type": "current",
          "valid_from": "2026-05-15T00:00:00.000Z",
          "valid_to":   "2026-05-15T01:00:00.000Z",
          "fetched_at": "2026-05-15T00:15:00.000Z",
          "freshness_band": "current",
          "metrics": {
            "temperature_c": 14.2,
            "precipitation_probability": 25,
            "wind_speed_kph": 18.0
          },
          "alerts": []
        },
        "latest_risk": {
          "risk_assessment_id": "5e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
          "level": "low",
          "recommendation": null,
          "reasons": []
        },
        "recent_change_events": []
      },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-05-15T00:15:01.500Z",
        "environment": "production",
        "snapshot_id": "4e8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6f",
        "billing_units": 1
      }
    }
    

    Cancel a watch

    DELETE /v1/weather/watch/{watch_id}  ·  Bills: 1 unit

    Soft-cancels the watch (status='cancelled', expired_at=now). The refresh worker stops picking it up. Returns 404 if the watch isn't owned by the calling developer account.

    Request

    curl -s -X DELETE "https://api.travelmode.ai/v1/weather/watch/1f8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6a" \
      -H "Authorization: Bearer tm_weather_..."
    

    Response (200 OK)

    {
      "data": {
        "watch_id": "1f8df5f0-8d9f-4a37-9c1a-9b2b3c4d5e6a",
        "status": "cancelled",
        "expired_at": "2026-05-15T01:00:00.000Z"
      },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-05-15T01:00:00.500Z",
        "environment": "production",
        "billing_units": 1
      }
    }
    

    Health

    GET /v1/weather/health  ·  Scope: weather:read  ·  Bills: 0 units

    Tiny ping that proves the API surface is reachable and the caller's key + scope check passed. Doesn't depend on the upstream weather provider being warm — safe to call on any frequency.

    Request

    curl -s "https://api.travelmode.ai/v1/weather/health" \
      -H "Authorization: Bearer tm_weather_..."
    

    Response (200 OK)

    {
      "data": { "status": "ok", "environment": "production" },
      "meta": {
        "request_id": "7c0f3c2c-9e4a-4d29-b4a2-9c2b4e9f5c11",
        "generated_at": "2026-04-25T18:01:13.500Z",
        "environment": "production",
        "billing_units": 0
      }
    }
    
    Previous
    ← Rate Limits
    Next
    Errors →