Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Smarterweather Com Agriculture API
version: 1.0.0
contact:
name: Smarter Weather Developer Platform
url: https://github.com/smarterweather/developer
license:
name: Creative Commons Attribution 4.0 International
identifier: CC-BY-4.0
termsOfService: https://developers.smarterweather.com/legal/terms
description: 'Operations tagged Agriculture across 2 of this provider''s published API definitions: developers-smarterweather-com-openapi.yaml, smarterweather-com-openapi.yaml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://api.smarterweather.com
description: Production
security:
- bearerAuth: []
tags:
- name: Agriculture
description: 'Agriculture-derived indices (Growing Degree Units / GDD) computed on
read from stored daily temperature extremes.'
paths:
/v1/agriculture/growing-degree-days:
get:
operationId: getGrowingDegreeDays
summary: Growing Degree Units (GDU / GDD) for a point
description: 'Returns Growing Degree Units (also called Growing Degree Days) for a
US point (CONUS, Alaska, Hawaii), computed on read from stored daily
maximum/minimum temperatures. No GDU grids are stored; the values are
derived per request from the temperature bundles, so a crop''s
base/upper thresholds and the simple/modified method can be selected
freely without re-running the pipeline.
**Two modes:**
- **Forecast (default).** Without `season_start`, the response carries
a per-day GDU series across the NBM forecast horizon (`days`).
- **Season cumulative.** With `season_start` (a `YYYY-MM-DD` local
date within the ~180-day observed window), the response stitches
RTMA observed daily history + today''s partial (hourly on-read
rollup) + NBM forecast, returns a `cumulative_total`, and adds a
per-day `cumulative_gdu` running sum. This is the number a grower
tracks against crop growth-stage milestones. If part of the season
window has no observed data, the per-day series still comes back
`200` but `cumulative_total` is omitted and `meta.gaps` carries an
`unfilled` span — a partial sum is not a season total.
**Crops.** Pass a catalog `crop` id (e.g. `corn`, `soybean`,
`wheat_winter`, `cotton`, `alfalfa`) to use calibrated thresholds, or
`crop=custom` with `base_temp_c` (and optionally `upper_temp_c` /
`method`) to supply your own.
Every response echoes the resolved `method`, `thresholds` (always in
°C), and a `meta` provenance block (`day_definition`,
`computation_path`, `source`, `unit`, any `gaps`) so nothing is
silently assumed.
Pass one location: `lat` and `lon`, `zip`, or `location`. A request
without one returns `400`; a ZIP or name that does not resolve
returns `404`; while location lookup is unavailable, a `zip` or
`location` request returns `503` with `Retry-After`.
The resolved place is echoed as `location`, present when the place
was resolved.
A point outside the 50 US states and DC returns `404`
`outside-coverage` with `next_steps`.'
tags:
- Agriculture
security:
- bearerAuth: []
parameters:
- $ref: '#/components/parameters/LatQuery'
- $ref: '#/components/parameters/LonQuery'
- $ref: '#/components/parameters/ZipQuery'
- $ref: '#/components/parameters/LocationQuery'
- name: crop
in: query
required: true
description: 'Crop catalog id (e.g. `corn`, `soybean`, `wheat_winter`,
`cotton`, `alfalfa`) or `custom` to supply thresholds directly.
'
schema:
type: string
example: corn
- name: season_start
in: query
required: false
description: 'Season/planting start as a `YYYY-MM-DD` local date. Presence
switches the response into cumulative season-to-date mode. Must be
within the ~180-day observed-history window.
'
schema:
type: string
format: date
example: '2026-05-01'
- name: days
in: query
required: false
description: Forecast horizon in days (default 10).
schema:
type: integer
minimum: 1
maximum: 30
default: 10
- name: day_definition
in: query
required: false
description: 'Daily boundary: `nws` (default; native NBM MaxT/MinT period
extremes) or `local_calendar` (midnight-to-midnight local day).
'
schema:
type: string
enum:
- nws
- local_calendar
default: nws
- name: unit
in: query
required: false
description: 'Unit system for GDU + temperatures. `imperial` (default) uses
°F-days; `metric` uses °C-days. Thresholds are always echoed in
°C regardless.
'
schema:
type: string
enum:
- imperial
- metric
default: imperial
- name: base_temp_c
in: query
required: false
description: Custom base threshold in °C. Required when `crop=custom`.
schema:
type: number
format: double
- name: upper_temp_c
in: query
required: false
description: 'Custom upper cutoff in °C (enables the modified method). Optional.
'
schema:
type: number
format: double
- name: method
in: query
required: false
description: 'GDU method for custom crops. Defaults based on whether
`upper_temp_c` is supplied.
'
schema:
type: string
enum:
- simple
- modified
- name: include_milestones
in: query
required: false
description: Include the crop's growth-stage GDU milestones.
schema:
type: boolean
default: false
responses:
'200':
description: Growing Degree Units for the requested point.
headers:
RateLimit-Limit:
$ref: '#/components/headers/RateLimitLimit'
RateLimit-Remaining:
$ref: '#/components/headers/RateLimitRemaining'
RateLimit-Reset:
$ref: '#/components/headers/RateLimitReset'
RateLimit-Policy:
$ref: '#/components/headers/RateLimitPolicy'
RateLimit-Daily-Limit:
$ref: '#/components/headers/RateLimitDailyLimit'
RateLimit-Daily-Remaining:
$ref: '#/components/headers/RateLimitDailyRemaining'
RateLimit-Daily-Reset:
$ref: '#/components/headers/RateLimitDailyReset'
content:
application/json:
schema:
$ref: '#/components/schemas/GrowingDegreeDays'
'400':
$ref: '#/components/responses/Problem400'
'404':
$ref: '#/components/responses/Problem404'
'502':
$ref: '#/components/responses/Problem502'
'503':
$ref: '#/components/responses/Problem503'
'504':
$ref: '#/components/responses/Problem504'
servers:
- url: https://api.smarterweather.com
description: Production
components:
headers:
RateLimitDailyLimit:
description: 'Daily request quota for this API key. Omitted for keys with no
daily cap.
'
schema:
type: integer
minimum: 0
RateLimitReset:
description: Seconds until the bucket is full again (0 when full).
schema:
type: integer
minimum: 0
RateLimitLimit:
description: 'Burst capacity of this API key''s token bucket: the most requests it
can make at once. `RateLimit-Policy: <limit>;w=<seconds>` gives the
time a full bucket takes to refill, so the sustained rate in requests
per minute is `Limit × 60 / w`.
'
schema:
type: integer
minimum: 0
RateLimitPolicy:
description: 'Token-bucket policy as `<burst>;w=<seconds>`: the burst capacity
(`RateLimit-Limit`) and the seconds a full bucket takes to refill.
The sustained rate in requests per minute is `burst × 60 / w`.
'
schema:
type: string
example: 30;w=30
RateLimitDailyReset:
description: 'Seconds until the daily quota resets (at 00:00 UTC). Omitted for
keys with no daily cap.
'
schema:
type: integer
minimum: 0
RateLimitDailyRemaining:
description: 'Requests left in today''s quota. Omitted for keys with no daily cap.
'
schema:
type: integer
minimum: 0
RateLimitRemaining:
description: Requests available now (tokens left in the bucket).
schema:
type: integer
minimum: 0
responses:
Problem504:
description: 'Gateway timeout. An upstream data source did not respond within
the service''s budget.
'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
Problem400:
description: Bad request.
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
Problem404:
description: 'Resource not found: a location that cannot be resolved (unknown
ZIP, unrecognised free-text location), no upstream data for the
location, or a missing resource. On a route that checks coverage
(its description says so), a location outside the 50 US states and
DC returns type `https://smarterweather.com/errors/outside-coverage`;
that and the location-not-found problem carry `next_steps`
(`recommended = coverage`).
'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
Problem502:
description: 'Bad gateway. The service received an invalid response from an
upstream data source. Transient; clients should retry with backoff.
'
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
Problem503:
description: 'Service unavailable. An upstream dependency is unavailable or
shedding load (type `service-unavailable`). Transient; retry with
backoff and honor any `Retry-After` header.
'
headers:
Retry-After:
description: Seconds to wait before retrying, when present.
schema:
type: integer
minimum: 0
content:
application/problem+json:
schema:
$ref: '#/components/schemas/Problem'
parameters:
ZipQuery:
name: zip
in: query
description: '5-digit US ZIP code. Mutually exclusive with `lat`/`lon` and
`location`.
'
required: false
schema:
type: string
pattern: ^\d{5}$
example: 02108
LonQuery:
name: lon
in: query
description: 'Longitude (WGS84 decimal degrees). Give it with `lat`. On a route
that also takes `zip` or `location`, give only one location form.
'
required: false
schema:
type: number
format: double
minimum: -180
maximum: 180
example: -71.0589
LocationQuery:
name: location
in: query
description: 'Free-text location name. Examples: `"Boston, MA"`, `"94043"`,
`"Denver"`. Resolved by the Smarter Weather geocoder. Mutually exclusive with
`lat`/`lon` and `zip`.
'
required: false
schema:
type: string
minLength: 1
maxLength: 128
example: Boston, MA
LatQuery:
name: lat
in: query
description: 'Latitude (WGS84 decimal degrees). Give it with `lon`. On a route
that also takes `zip` or `location`, give only one location form.
'
required: false
schema:
type: number
format: double
minimum: -90
maximum: 90
example: 42.3601
schemas:
ProblemNextStepLink:
type: object
description: 'One destination in `next_steps`. `href` and `description` are
always present. Optional `command` names a one-liner that sinks
the key to `.env` (preferred over raw endpoints). The
`device_flow` relation also carries the public Clerk device-grant
recipe fields; `trial` carries `challenge_endpoint` /
`mint_endpoint` (raw HTTP mints that return the bearer in the
body — labeled as such in `description`).
'
required:
- href
- description
properties:
href:
type: string
format: uri
description: 'Absolute URL. Carries `utm_source=api&utm_medium=problem-json&utm_campaign=<status>`
so the portal can attribute visits that started from an API error.
'
description:
type: string
description: One sentence a human or agent can act on.
command:
type: string
description: 'Preferred one-liner (e.g. `npx -y @smarterweather/mcp-onboarding@latest login`).
No UTM. Writes the key to `.env` and prints only a prefix.
'
client_id:
type: string
description: Public OAuth client id (device_flow only).
device_authorization_endpoint:
type: string
format: uri
description: Clerk device-authorization URL (device_flow only). No UTM.
token_endpoint:
type: string
format: uri
description: Clerk token URL (device_flow only). No UTM.
api_keys_endpoint:
type: string
format: uri
description: 'Key CRUD URL to call with the device-grant access token
(device_flow only). No UTM.
'
challenge_endpoint:
type: string
format: uri
description: Trial PoW challenge URL (trial only). No UTM. Returns challenge material, not a key.
mint_endpoint:
type: string
format: uri
description: 'Trial mint URL (trial only). No UTM. Returns the bearer in the
response body''s `api_key` field — write only that field to
`.env` as `SMARTERWEATHER_API_KEY=`; never print it.
'
endpoint:
type: string
format: uri
description: 'onboarding_mcp only; Streamable HTTP MCP URL, POST-only (its
`href` is the setup guide). No UTM.
'
GddGap:
type: object
description: A run of missing observed days affecting a cumulative total.
required:
- start
- end
- days
- filled
properties:
start:
type: string
format: date
description: First missing day (inclusive).
end:
type: string
format: date
description: Last missing day (inclusive).
days:
type: integer
description: Number of missing days in the run.
filled:
type: string
description: 'How the gap was handled, e.g. `interpolated` (short gap filled
from adjacent days) or `unfilled` (long gap surfaced, not
silently under-counted).
'
GddMilestone:
type: object
description: 'A crop growth-stage GDU hint from the catalog. Interpretation aid for
clients; not a server-computed threshold.
'
required:
- stage
- gdu
properties:
stage:
type: string
description: Growth-stage label (e.g. `emergence`, `silking`).
gdu:
type: number
format: double
description: Cumulative GDU (requested unit) at which the stage is reached.
ProblemNextSteps:
type: object
description: 'Extension member on `401`, `402`, `403`, and `429` problems, and
on `404` `outside-coverage` and US location-not-found problems:
where to go next, as a map of link relations. `recommended` names the
relation a client should take first; when present,
`if_no_human_present` names the relation an autonomous agent
should take when nobody can act on the recommended one right
now. Every other key is a link relation (`device_flow`,
`get_key`, `quickstart`, `agents`, `onboarding_mcp`,
`keyless_x402`, `key_handling`, `errors`, `upgrade`, `pricing`,
`usage`, `claim`, `coverage`) whose value is a `ProblemNextStepLink`. New
relations may be added over time; unknown relations MUST be
ignored.
'
required:
- recommended
properties:
recommended:
type: string
description: The link relation to take first.
example: device_flow
if_no_human_present:
type: string
description: 'The link relation for an autonomous agent when no human can act
on `recommended` right now. Absent when there is no such
alternative.
'
additionalProperties:
$ref: '#/components/schemas/ProblemNextStepLink'
example:
recommended: device_flow
agents:
href: https://developers.smarterweather.com/llms.txt?utm_campaign=401&utm_medium=problem-json&utm_source=api
description: 'Agents: start here. The full agent path, key handling, and the machine-readable contracts.'
device_flow:
href: https://developers.smarterweather.com/quickstart?utm_campaign=401&utm_medium=problem-json&utm_source=api#device-flow
description: 'Human present: run the `command` below. It shows the human a verification URL and code, writes SMARTERWEATHER_API_KEY to ./.env (0600, gitignored), and prints only a key prefix. Without Node: device grant at the endpoints below, then POST api_keys_endpoint and write only the response''s key field to .env as a SMARTERWEATHER_API_KEY= line (e.g. pipe through jq -r .key). Never print the key or access token.'
command: npx -y @smarterweather/mcp-onboarding@latest login
client_id: k2h05BUoTP393zcD
device_authorization_endpoint: https://clerk.smarterweather.com/oauth/device_authorization
token_endpoint: https://clerk.smarterweather.com/oauth/token
api_keys_endpoint: https://api.smarterweather.com/developer/keys
errors:
href: https://developers.smarterweather.com/errors?utm_campaign=401&utm_medium=problem-json&utm_source=api
description: What every problem type means and what to do next.
get_key:
href: https://developers.smarterweather.com/dashboard/api-keys?utm_campaign=401&utm_medium=problem-json&utm_source=api
description: 'Sign in (free, no card) and mint an API key. Pass it as ''Authorization: Bearer sw_live_*''.'
key_handling:
href: https://developers.smarterweather.com/agents?utm_campaign=401&utm_medium=problem-json&utm_source=api#key-handling
description: Write the key to .env, add .env to .gitignore, read SMARTERWEATHER_API_KEY in code, never echo the key in chat or commit it.
keyless_x402:
href: https://developers.smarterweather.com/agents?utm_campaign=401&utm_medium=problem-json&utm_source=api#x402
description: Agents with a wallet can pay per call (USDC on Base via x402) on the weather MCP with no account.
onboarding_mcp:
href: https://developers.smarterweather.com/agents?utm_campaign=401&utm_medium=problem-json&utm_source=api
description: Anonymous Streamable HTTP MCP that can sign you up, mint a key, and configure the weather MCP in your client. Connect your MCP client to endpoint (POST-only); href is the setup guide.
endpoint: https://mcp.developers.smarterweather.com
quickstart:
href: https://developers.smarterweather.com/quickstart?utm_campaign=401&utm_medium=problem-json&utm_source=api
description: Three requests from zero to a live forecast call; the no-install path for agents and humans.
GddThresholds:
type: object
description: Resolved GDU thresholds, always expressed in °C.
required:
- base_temp_c
properties:
base_temp_c:
type: number
format: double
description: Base (lower) temperature threshold in °C.
upper_temp_c:
type: number
format: double
description: Upper cutoff in °C (present only for the modified method).
GddDay:
type: object
description: One day of GDU output.
required:
- date
- gdu
properties:
date:
type: string
format: date
description: Local calendar date for this day.
gdu:
type: number
format: double
description: GDU accrued on this day, in the requested unit.
tmax_c:
type: number
format: double
description: Daily maximum temperature in °C (metric responses).
tmin_c:
type: number
format: double
description: Daily minimum temperature in °C (metric responses).
tmax_f:
type: number
format: double
description: Daily maximum temperature in °F (imperial responses).
tmin_f:
type: number
format: double
description: Daily minimum temperature in °F (imperial responses).
cumulative_gdu:
type: number
format: double
description: 'Running season-to-date total through this day. Present only in
cumulative mode (when `season_start` was supplied).
'
missing:
type: boolean
description: True when the underlying day had no temperature data.
interpolated:
type: boolean
description: True when this day's value was interpolated across a gap.
Problem:
type: object
description: 'RFC 9457 problem-details object served as `application/problem+json`
on every `4xx` and `5xx` response. RFC 9457 obsoletes RFC 7807 with
an identical wire format; parsers written for either work.
Beyond the five standard members the object may carry extension
members (RFC 9457 §3.2). Today `401`, `402`, `403`, and `429`
carry `next_steps`, as do `404` `outside-coverage` and the `404`
for a place that matches no US location. Clients MUST ignore
extension members they do not understand.
'
required:
- type
- title
- status
additionalProperties: true
properties:
type:
type: string
format: uri
description: 'A URI reference identifying the problem type. Stable; switch on
it as an opaque string. Every value under
`https://smarterweather.com/errors/` redirects to the matching
section of
[developers.smarterweather.com/errors](https://developers.smarterweather.com/errors).
'
example: https://smarterweather.com/errors/unauthorized
title:
type: string
description: Short, human-readable summary of the problem type.
status:
type: integer
description: HTTP status code.
detail:
type: string
description: Human-readable explanation specific to this occurrence.
instance:
type: string
format: uri
description: A URI reference identifying the specific occurrence.
next_steps:
$ref: '#/components/schemas/ProblemNextSteps'
GrowingDegreeDays:
type: object
description: Growing Degree Units for a point, forecast or season-cumulative.
required:
- crop
- catalog_version
- method
- thresholds
- meta
- days
properties:
crop:
type: string
description: Echoed crop id (`corn`, ..., or `custom`).
catalog_version:
type: integer
description: Version of the crop catalog used to resolve thresholds.
method:
type: string
enum:
- simple
- modified
description: GDU method applied.
thresholds:
$ref: '#/components/schemas/GddThresholds'
meta:
$ref: '#/components/schemas/GddMeta'
days:
type: array
description: Per-day GDU series (chronological).
items:
$ref: '#/components/schemas/GddDay'
cumulative_total:
type: number
format: double
description: 'Season-to-date GDU total in the requested unit. Present only in
cumulative mode (when `season_start` was supplied), and omitted
even then when `meta.gaps` contains an `unfilled` span: those days
have no observed data, so the sum would under-count the season.
Treat an absent total on a `season_start` request as "season total
unavailable" and fall back to the per-day series, which is still
good for the days it covers. `meta.gaps` names the window that was
lost.
'
milestones:
type: array
description: 'Crop growth-stage GDU hints, present when `include_milestones=true`
and the crop has catalog milestones.
'
items:
$ref: '#/components/schemas/GddMilestone'
location:
$ref: '#/components/schemas/Location'
description: 'Resolved location, as `/v1/weather` returns it. Present when the
place was resolved: always for a `zip` or `location` request, and
for `lat`/`lon` when the coverage check''s lookup answered in time
(omitted when that check fails open).
'
Location:
type: object
description: Resolved location.
required:
- lat
- lon
- name
- timezone
properties:
lat:
type: number
format: double
minimum: -90
maximum: 90
lon:
type: number
format: double
minimum: -180
maximum: 180
name:
type: string
description: 'Human-readable place name, usually without the state; see
`region`. The resolved place name, else the city, else the
nearest city. Empty when none is known.
'
example: Boston
region:
type: string
description: State or region abbreviation.
example: MA
country:
type: string
description: ISO 3166-1 alpha-2 country code.
example: US
timezone:
type: string
description: IANA timezone identifier.
example: America/New_York
county:
type: string
description: County name (US only).
example: Suffolk
zip:
type: string
description: ZIP code (US only).
example: 02108
GddMeta:
type: object
description: Provenance for a GDU response. Nothing is silently assumed.
required:
- day_definition
- computation_path
- source
- unit
properties:
day_definition:
type: string
enum:
- nws
- local_calendar
description: The daily boundary used.
computation_path:
type: string
description: 'How the series was assembled (e.g. forecast-only vs. stitched
observed + partial + forecast), for grid-vs-point transparency.
'
source:
type: string
description: Backing product mix (NBM / RTMA) used for this answer.
freshness:
type: string
description: Human-readable data-age hint, when available.
unit:
type: string
enum:
- imperial
- metric
description: Unit system applied to numeric GDU + temperature fields.
approximate:
type: boolean
description: True when gaps were interpolated or coverage was partial.
gaps:
type: array
description: Missing-day runs affecting a cumulative total.
items:
$ref: '#/components/schemas/GddGap'
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: sw_live_*|sw_test_*
description: "API key passed as an HTTP Bearer token (RFC 6750):\n\n```\nAuthorization: Bearer sw_live_xxxx...\n```\n\nKeys are issued in two flavors:\n\n- `sw_live_*` -- production keys; requests are billed and counted\n against rate limits.\n- `sw_test_*` -- test-mode keys; requests return live data but are\n excluded from billing meter events. Useful for CI and local\n development.\n\nGet a key from the developer dashboard at\n[developers.smarterweather.com/dashboard/api-keys](https://developers.smarterweather.com/dashboard/api-keys).\n"
x-refined-from:
- developers-smarterweather-com-openapi.yaml
- smarterweather-com-openapi.yaml