One endpoint. No key, no signup, no rate-limit fluff. Returns the same numbers the calculator shows you, as JSON.

Endpoint

GET https://dfetcher.com/api/calculate

CORS-open. Cached at the edge for 60 seconds. Returns application/json.

Quick example

curl 'https://dfetcher.com/api/calculate?lat=41.24&lon=-81.84&skin=3&target=1000'

Query parameters

Name Type Default Notes
lat number Required. -90 to 90.
lon number Required. -180 to 180.
skin integer 1–6 3 Fitzpatrick skin type.
area number 0–1 0.25 Exposed body fraction. 0.10 face+hands, 0.25 arms+face, 0.85 near-full body.
scalp enum hair hair | bald. Bald adds ~3.5% BSA.
age integer 45 Used for the age factor (linear decline 1.0 @ 20 → 0.4 @ 70+).
target integer IU 1000 Daily target dose.
date ISO 8601 or ms now Override the moment of calculation.
day boolean true Include day[] (15-min samples through the local day).
year boolean true Include year[] (monthly solar-noon samples with cloud climatology).
dayStep integer 5–60 15 Day-curve resolution in minutes.

Response

{
  "input": { "lat", "lon", "date" (ISO), "skinType", "areaFraction", "age", "targetIU" },
  "sun":   { "elevation", "zenith", "declination" }                          // degrees
  "uvi":   { "value", "clearSky", "source": "live" | "clear-sky", "deltaMin" },
  "synthesis": {
    "iuPerMin",
    "minutesToTarget",   // null if synthesis is closed
    "medMinutes",        // minutes to 1 MED (sunburn threshold)
    "elevationGate",     // 0..1, low-sun penalty
    "ageFactor",         // 0.4..1.0
    "viable"             // boolean
  },
  "peak":   { "solarNoon" (ISO), "minutesToTargetAtNoon", "medMinutesAtNoon" },
  "window": { "start" (ISO|null), "end" (ISO|null) },
  "day":    [ { "hour", "time", "elev", "uvi", "uviSource",
                "iuPerMin", "minutesToTarget" }, ... ],
  "year":   [ { "month" (1..12), "solarNoon", "elev", "uviClear",
                "cloudPct", "minutesClear", "minutesCloudy" }, ... ]
}

Times in window and peak.solarNoon are ISO UTC. day[].time is also ISO UTC; the hour field is a local-day fraction (0–24).

Errors

Status When
400 Missing or invalid lat/lon, malformed date, or out-of-range values.
500 Internal failure. Body includes a detail string for debugging.

Error bodies are JSON: { "error": "...", "detail"?: "..." }. When the upstream UV index feed is unreachable, the response still succeeds with uvi.source = "clear-sky" — no error is raised, but expect lower accuracy under heavy cloud cover.

Caching

  • Responses set cache-control: public, max-age=60, s-maxage=60.
  • CORS: access-control-allow-origin: *. Safe to call from the browser.

MCP server

For Claude Desktop, Claude Code, and other MCP clients, D Fetcher also speaks the Model Context Protocol over Streamable HTTP.

https://dfetcher.com/mcp

Exposes three tools — calculate, geocode, and describe_skin_types. Example Claude Desktop config:

{
  "mcpServers": {
    "dfetcher": { "type": "http", "url": "https://dfetcher.com/mcp" }
  }
}