Developer docs · REST API v1
Dermal Vectors Forecast API
Daily Dry Skin Index (DSI) forecasts for U.S. metro areas, ready for your own code, dashboards, automation tools and AI agents. Ask for a place by city location, state or metro code and get back a 7-day forecast in JSON or CSV. New to this? Start with the step-by-step guide.
- Base URL
https://YOUR-DERMAL-VECTORS-SITE- Authentication
- An organization API key in a header:
Authorization: Bearer YOUR_KEY. A brand owner creates it on the Integrations page. The market list needs no key. - Formats
- JSON (default) or CSV (
format=csv) - Updates
- A new forecast every day, normally ready by about 12:35 UTC
- Coverage
- 371 U.S. metro areas in 50 states and DC, 7 days ahead
- Limits
- Monthly allowance per brand, plus a per-minute limit. No overage charges. Details
- Spec
- OpenAPI 3.1 (YAML)
Quick start
No codes needed. Ask for the metro nearest a location, like a weather API. Here is this week's Dry Skin Index for Boston (latitude 42.36, longitude −71.06):
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?near=42.36,-71.06"Keep your key in an environment variable, for example export DV_API_KEY="…", never in shared code. Each forecast call uses one read from your monthly allowance.
Products
| Product | Product ID | Status | How to call it |
|---|---|---|---|
| Daily Metro DSI Forecast | daily_metro_dsi_forecast | Available | GET /api/v1/products/daily_metro_dsi_forecast/latest · details |
| Dry-Skin Search Outlook | dry_skin_search_outlook | Coming | Same pattern once released; returns 503 until then |
| Humidifier Search Outlook | humidifier_search_outlook | Coming | Same pattern once released; returns 503 until then |
To check in code which products your brand can use right now, call GET /api/v1/products (one lookup, not a forecast read).
Daily Metro DSI Forecast
- What it measures
- Indoor drying stress on skin, on a 0–10 scale (higher = drier), from NOAA GFS temperature and humidity forecasts
- Places
- 371 U.S. Census metro areas (CBSAs), not DMAs
- Time
- 7 daily values per metro, starting on the issue date
- Updated
- Daily, about 12:35 UTC. Each day's forecast is an “issue” (like an edition) with a permanent ID, and is current for about 24 hours
- Formats
- JSON or CSV
Endpoints
| Call | What it returns | Counts as |
|---|---|---|
GET /api/v1/products/daily_metro_dsi_forecast/latest | Today's 7-day forecast for the places you choose (the newest “issue”) | 1 forecast read |
GET /api/v1/products/daily_metro_dsi_forecast/issues/{issueId} | A specific past forecast again, unchanged, using its ID (so a report can be re-checked with the same numbers) | 1 forecast read |
GET /api/v1/markets | Supported metros: find codes by name, state or location | Free, no key |
Choosing places
Use one of these per request. The response always lists the exact metro codes it used in markets.requested.
| Parameter | Example | Which metros you get |
|---|---|---|
near | near=42.36,-71.06 | The single nearest supported metro to that latitude,longitude (like a weather API) |
state | state=CT | Every supported metro in that state (metros that cross state lines count for each state) |
markets | markets=14460,35620 | Exactly these CBSA codes, up to 100. Find codes |
| (none) | /latest | All 371 metros |
Examples
Every Connecticut metro, as JSON:
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?state=CT"Four Northeast metros by code:
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?markets=14460,35620,37980,25540"Other parameters
| Parameter | Values | Meaning |
|---|---|---|
format | json | csv | JSON (default) or a CSV file download |
view | daily | summary | both | 7 daily rows per metro (default), one summary line per metro, or both |
sort | mean7 | excess | exposure65 | trend | With view=summary or both: highest first (trend: fastest rising first) |
top | 1–400 | With view=summary or both: keep only the first N |
issueId | in the path | Only for /issues/{issueId}; copy it from product.issueId |
What you get back
The response has two parts: information about the issue (which forecast this is, when it was made, where it came from) and rows: one row per metro per day. The arrows mark each part. This example is for near=42.36,-71.06 (Boston), shortened:
{
"schemaVersion": "dv-product-response-v1",
"product": { ← which forecast issue this is
"productId": "daily_metro_dsi_forecast",
"issueId": "dsi-20261006T140100Z-3824fb7ca0b601ee",
"issuedAt": "2026-10-06T14:01:00.000Z",
"validFrom": "2026-10-06T00:00:00Z",
"validUntil": "2026-10-07T14:01:00.000Z",
"geography": "us_census_cbsa_metro",
"coverage": { "expected": 371, "completed": 371 },
"modelVersion": "residential-dsi-hierarchy-v1",
"recipeVersion": null,
"formats": ["json", "csv"]
},
"freshness": "current",
"access": "full",
"release": "customer_released",
"geography": { "type": "us_census_cbsa_metro", "code": "5-digit CBSA",
"note": "U.S. Census metro areas, not DMAs." },
"provenance": { ← where the numbers came from
"runId": "signal-20261006T1401Z",
"noaaCycle": "2026-10-06T00:00:00+00:00",
"noaaModel": "gfs",
"targetDates": ["2026-10-06", "2026-10-07", "…", "2026-10-12"],
"catalogMetros": 384, "modeledMetros": 371,
"manifestSha256": "3824fb7c…", "artifactSha256": "be261f7c…",
"excludedCbsas": ["14100", "…"], "validationStatus": "shadow_verified"
},
"markets": { "requested": ["14460"], "returned": 1 }, ← the metros used
"units": { "dsi": "Dry Skin Index (dimensionless, 0-10)", "leadDay": "1 = issue date",
"forecastConfidence": "reduced from lead day 6", "coveredPopulation": "people" },
"rows": [ ← the forecast: one row per metro per day
{ "cbsa": "14460", "metroName": "Boston-Cambridge-Newton, MA-NH", "date": "2026-10-06",
"leadDay": 1, "forecastConfidence": "standard",
"dsi": 5.915614, "dsiLow": 4.881779, "dsiHigh": 7.168575, "coveredPopulation": 4917438.333 },
{ "cbsa": "14460", "metroName": "Boston-Cambridge-Newton, MA-NH", "date": "2026-10-07",
"leadDay": 2, "forecastConfidence": "standard",
"dsi": 5.408925, "dsiLow": 4.482004, "dsiHigh": 6.527612, "coveredPopulation": 4917438.333 }
… 5 more rows, one per day to 2026-10-12
]
}Headers: X-DV-Issue-Id (same as product.issueId) and Cache-Control: private, no-store.
Full data dictionary, CSV headings and downloadable definitions
Data dictionary: rows
| Field | Meaning | Unit / values | Example |
|---|---|---|---|
cbsa | U.S. Census metro code. | 5-digit text | 14460 |
metroName | Official metro name. | text | Boston-Cambridge-Newton, MA-NH |
date | Forecast date. | YYYY-MM-DD | 2026-10-07 |
leadDay | Forecast day; 1 is the issue date. | 1–7 | 1 |
forecastConfidence | Confidence label; reduced from day 6. | standard / reduced | standard |
dsi | Modeled indoor drying stress on skin; higher means drier. | index, 0–10 | 5.92 |
dsiLow | Lower end of the forecast range. | index, 0–10 | 4.88 |
dsiHigh | Upper end of the forecast range. | index, 0–10 | 7.17 |
coveredPopulation | Population covered by the metro forecast. | people | 4917438 |
Data dictionary: issue information
| Field | Meaning | Unit / values | Example |
|---|---|---|---|
product.issueId | Permanent ID of this forecast; the same ID always returns the same numbers. Cite it. | text | dsi-20261006T… |
product.issuedAt | When the issue was published | UTC time | 2026-10-06T14:01Z |
product.validFrom / validUntil | When this issue counts as the current forecast | UTC time | about 24 hours |
freshness | current, or expired for an earlier issue you asked for by ID | current | expired | current |
markets.requested / returned | Metro codes used, and how many came back | codes / count | ["14460"] / 1 |
provenance.targetDates | The 7 forecast dates | dates | 2026-10-06 … 2026-10-12 |
provenance.noaaCycle / noaaModel | The NOAA weather run used | time / name | gfs |
provenance.runId, …Sha256 | IDs for audits and reproducibility | text | — |
units | Plain-language units for the row fields | object | — |
CSV
With format=csv you get a file with one line per metro per day. Columns match the row fields in snake_case:
cbsa,metro_name,date,lead_day,forecast_confidence,dsi,dsi_low,dsi_high,covered_population 14460,"Boston-Cambridge-Newton, MA-NH",2026-10-06,1,standard,5.915614,4.881779,7.168575,4917438.333 14460,"Boston-Cambridge-Newton, MA-NH",2026-10-07,2,standard,5.408925,4.482004,6.527612,4917438.333 …
Summary measures (7-day)
Add view=summary to get one line per metro with the 7-day measures below, computed on our side from the same issue, instead of 7 daily rows you would have to add up yourself. It is smaller and faster to read for code and AI agents. Combine with sort and top to rank metros, for example the 10 driest in the country, in one read.
| Measure | Definition | Unit |
|---|---|---|
mean7 | Average of the daily DSI values | DSI, 0–10 |
peak | Highest daily DSI and its date (earliest if tied) | DSI and date |
excessAbove4 | Sum over the days of (DSI − 4), counting only days above 4 (recipe cumulative-excess-v1) | index-days above 4 |
exposure65plus | excessAbove4 × the metro's population aged 65+ (metro-wide, 2023 ACS 5-year, table B01001): how much above-4 dryness older adults are exposed to over the week | 65+ person-index-days |
trend | Least-squares change in DSI per day over the week: rising (≥ +0.15/day, about +1 point a week), falling (≤ −0.15/day), otherwise steady | DSI per day + label |
Examples
This week's summary for Boston:
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?near=42.36,-71.06&view=summary"The 10 driest metros in the country this week:
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?view=summary&sort=mean7&top=10"Texas metros with the highest 65+ exposure, as a spreadsheet:
curl -H "Authorization: Bearer $DV_API_KEY" -o texas-65plus-exposure.csv \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?state=TX&view=summary&sort=exposure65&top=5&format=csv"Example response 200 OK real values, Sept 29 issue; shortened
{
"schemaVersion": "dv-product-response-v1",
"view": "summary",
"summaryVersion": "dsi-summary-v1",
"product": { "issueId": "dsi-20260929T191051Z-9d3005985574912e", "issuedAt": "2026-09-29T19:10:51Z", … },
"freshness": "current",
"markets": { "requested": ["14460"], "returned": 1 },
"provenance": { "runId": "signal-delivery-20260929-1200", "targetDates": ["2026-09-29", "…", "2026-10-05"] },
"units": { "mean7": "mean daily DSI, 0-10", "excessAbove4": "sum of max(DSI-4,0), index-days", … },
"summaries": [
{ "cbsa": "14460", "metroName": "Boston-Cambridge-Newton, MA-NH", "days": 7,
"firstDate": "2026-09-29", "lastDate": "2026-10-05",
"mean7": 4.205,
"peak": { "dsi": 4.595, "date": "2026-10-05" },
"excessAbove4": 1.705,
"population65plus": 818502,
"exposure65plus": 1395836,
"trend": { "slopePerDay": 0.107, "label": "steady" } }
]
}With sort, each summary also has a rank. The summary CSV has one row per metro: rank,cbsa,metro_name,first_date,last_date,days,mean7,peak_dsi,peak_date,excess_above_4,population_65plus,exposure_65plus,trend_slope_per_day,trend. Full provenance (hashes, excluded metros) is in view=daily or view=both.
These are weather-derived summaries of the Dry Skin Index, not medical, sales or audience measures.
Find a market
Look up any supported metro and copy its code, or download the full list. No key is needed for either.
GET /api/v1/markets
The same list for your code. Public, cacheable, and not counted against your allowance.
| Parameter | Example | Meaning |
|---|---|---|
q | q=dallas | Part of a metro name, or a code |
state | state=TX | Metros in a state (can be combined with q) |
near | near=42.36,-71.06 | Nearest metros first, with distanceKm (use on its own) |
limit | limit=3 | Up to 400; default 5 with near, otherwise all |
format | format=csv | JSON (default) or CSV |
curl \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/markets?near=42.36,-71.06&limit=2"{
"schemaVersion": "dv-markets-v1",
"productId": "daily_metro_dsi_forecast",
"geography": "us_census_cbsa_metro",
"totalSupported": 371,
"count": 2,
"markets": [
{ "cbsa": "14460", "name": "Boston-Cambridge-Newton, MA-NH", "states": ["MA", "NH"],
"latitude": 42.3739, "longitude": -71.141, "population": 4917661, "distanceKm": 7 },
{ "cbsa": "49340", "name": "Worcester, MA-CT", "states": ["MA", "CT"],
"latitude": 42.2784, "longitude": -71.7038, "population": 861664, "distanceKm": 54 }
]
}Recipes
This week for one city
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?near=32.78,-96.80"Which of several metros is driest this week
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?markets=14460,35620,37980,25540&view=summary&sort=mean7"The driest metros in the whole country (one read)
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?view=summary&sort=mean7&top=10"Where dryness is rising fastest
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?view=summary&sort=trend&top=10"Every metro in a state, as a spreadsheet
curl -H "Authorization: Bearer $DV_API_KEY" -o texas-dsi.csv \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?state=TX&format=csv"Everything, as a spreadsheet
curl -H "Authorization: Bearer $DV_API_KEY" -o all-metros-dsi.csv \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/latest?format=csv"The same numbers again later
Each day's forecast is published as an issue, like a newspaper edition, with a permanent ID in product.issueId. /latest always returns the newest one. To get a specific past forecast again, unchanged (for example to re-check last week's report), put its ID in the address:
curl -H "Authorization: Bearer $DV_API_KEY" \
"https://YOUR-DERMAL-VECTORS-SITE/api/v1/products/daily_metro_dsi_forecast/issues/dsi-20261006T140100Z-3824fb7ca0b601ee?markets=14460"Errors
Errors use standard HTTP status codes and a JSON body with a stable code and a plain-language message that says when retrying won't help.
HTTP/1.1 422 Unprocessable Entity
{
"error": {
"code": "unsupported_market",
"message": "Some requested markets are not supported CBSA metros in this issue.",
"unsupportedMarkets": ["99999"]
}
}| Status | Code | Meaning and what to do |
|---|---|---|
| 400 | invalid_request | A parameter is malformed, more than one way of choosing places was used, or a key was sent in a URL or cookie. Fix the request. |
| 400 | ambiguous_credentials | Both a website session and a key were sent. Send only the key. |
| 401 | invalid_api_key | Missing, unknown, revoked or expired key. Create a new key and update your code; retrying won't help. |
| 403 | entitlement_required | No active trial or subscription. A brand owner subscribes in Billing. |
| 403 | agent_access_not_enabled | API access isn't enabled for this brand. Contact Dermal Vectors. |
| 403 | read_only_latest_denied, issue_not_received | After a subscription ends, only issues the brand already received can be read. |
| 404 | unsupported_product, issue_not_found | Unknown product or issue ID. |
| 409 | stale_issue | Today's issue isn't published yet and the previous one has expired. Try again later. |
| 422 | unsupported_market | Some codes aren't covered (see unsupportedMarkets), or a state has no supported metros. |
| 429 | rate_limited | Per-minute limit. Wait Retry-After seconds (60 or less). |
| 429 | allowance_exhausted | Monthly allowance used up. Retry-After points to the 1st of next month (UTC); retrying sooner won't succeed. |
| 429 | too_many_failed_attempts | Too many failed keys from your address. Fix the key, then wait. |
| 502 | artifact_invalid | A forecast file failed its integrity check and was not served. |
| 503 | product_unavailable, release_pending, source_unavailable, meter_unavailable, auth_unavailable | Temporarily unavailable, or not yet released. Retry later. |
Limits
- Monthly allowance per brand, shared by every API key and AI app: forecast reads, lookups and data returned. Current usage is on the Integrations page. It resets on the 1st of each month (UTC). There are no overage charges; requests are refused until the reset.
- Per-minute limit per brand. Wait for
Retry-After. - Up to 100 metros per request (10 per AI-agent tool call). Leave places out to get all metros in one read.
- The market list (
/api/v1/markets) is free and needs no key.
Tip: one call without places returns every metro for one read. Fetch once a day after about 12:35 UTC and reuse your copy.
Use of forecasts, allowances and limits: Terms of Service and API and Data-use Terms.
For AI agents (MCP)
AI apps connected to https://YOUR-DERMAL-VECTORS-SITE/mcp see read-only tools with the same data and allowance, and receive a short briefing on what DSI means, citing the issue ID and saving allowance. Setup is in the guide.
| Tool | Input | Returns |
|---|---|---|
get_product_dictionary | Optional product; defaults to all | Field definitions, CSV/API mappings, units and examples; no forecast reads charged |
list_forecast_products | none | Products your brand can use |
get_product_coverage | optional query, state, near, limit | Supported metros (filtered), with codes |
get_dsi_forecast | one of markets (1–10 codes), state, near; optional issue, view | 7-day summaries by default (daily rows with view=daily); issue ID; resolvedPlace for state/near |
rank_metros | optional by (mean7, excess, exposure65, trend), state, top (≤ 25) | Top N metros nationwide or in a state, with their 7-day summaries |
get_pilot_market_comparison | none | The brand owner's ten pinned pilot metros (five higher/lower DSI pairs) against the latest issue |
get_search_outlook | category; optional regions, query, sort, top | Weekly search-interest outlook. Internal review only; listed by list_forecast_products only when available to your brand |
Changes
- 2026-10-06: 7-day summary measures (
view=summary,sort,top): mean7, peak, excessAbove4, exposure65plus, trend; MCP returns summaries by default and adds rank_metros. - 2026-10-06: choose places by
nearorstate; new public/api/v1/markets; separateallowance_exhaustedandrate_limitedcodes; MCP tools accept places and send a briefing.