lat float required Geodetic (WGS 84) latitude in decimal degrees, positive north. ±90 is accepted: the East component's polar singularity is handled by the model's limiting series, so the poles answer a real value instead of NaN.
Magnetic declination, inclination and field strength anywhere on Earth from the official WMM2025 coefficients, plus compass-to-true heading conversion.
Authoritative reference data or standards computation
Evaluates WMM2025 at one geodetic coordinate, height and date. date defaults to today in UTC and must resolve inside 2025-01-01…2029-12-31 — outside it the answer is a 400, never an extrapolation.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
lat
required
| float | allowed: -90 – 90 example: 55.6761 | Geodetic (WGS 84) latitude in decimal degrees, positive north. ±90 is accepted: the East component's polar singularity is handled by the model's limiting series, so the poles answer a real value instead of NaN. |
lng
required
| float | allowed: -180 – 180 example: 12.5683 | Geodetic (WGS 84) longitude in decimal degrees, positive east. The antimeridian is not special — the expansion only ever uses cos/sin of multiples of the longitude. |
date | date | example: 2026-07-01 | Calendar date the field is evaluated for (YYYY-MM-DD), which **defaults to today in UTC** — the resolved value comes back in the `date` field and in `meta.params.date`. Must land inside 2025-01-01…2029-12-31; anything else is a 400 rather than an extrapolation. Internally the date becomes the model's decimal year, `year + (dayOfYear − 1) / (365 or 366)`. |
altitudeKm | float | default: 0 allowed: -1 – 850 example: 100 | Height above the WGS 84 ellipsoid in kilometres. WMM2025's documented envelope is −1 km to 850 km and both ends are inclusive; sea level (0) is the default. |
lat float required Geodetic (WGS 84) latitude in decimal degrees, positive north. ±90 is accepted: the East component's polar singularity is handled by the model's limiting series, so the poles answer a real value instead of NaN.
lng float required Geodetic (WGS 84) longitude in decimal degrees, positive east. The antimeridian is not special — the expansion only ever uses cos/sin of multiples of the longitude.
date date Calendar date the field is evaluated for (YYYY-MM-DD), which **defaults to today in UTC** — the resolved value comes back in the `date` field and in `meta.params.date`. Must land inside 2025-01-01…2029-12-31; anything else is a 400 rather than an extrapolation. Internally the date becomes the model's decimal year, `year + (dayOfYear − 1) / (365 or 366)`.
altitudeKm float Height above the WGS 84 ellipsoid in kilometres. WMM2025's documented envelope is −1 km to 850 km and both ends are inclusive; sea level (0) is the default.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
fields | list | example: date,decimalYear | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: model | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
date | string (YYYY-MM-DD) | The resolved evaluation date — the supplied `date`, or today in UTC when it was omitted. | 2026-07-01 |
decimalYear | float | The model's time argument, `year + (dayOfYear − 1) / (365 or 366)`, rounded to 6 dp. 2025-01-01 is exactly 2025 and 2029-12-31 is 2029.997260. | 2026.49589 |
latitude | float | Geodetic latitude, echoed as supplied. | 55.6761 |
longitude | float | Geodetic longitude, echoed as supplied. | 12.5683 |
altitudeKm | float | Height above the WGS 84 ellipsoid, echoed as supplied. | 0 |
declinationDegrees | float (-180 to 180) | Angle from true north to magnetic north, **positive east**. This is the number you add to a magnetic bearing to get a true bearing. Reported at 2 dp — NOAA's own precision, and already about ten times finer than the model's stated uncertainty. | 5.23 |
inclinationDegrees | float (-90 to 90) | Dip angle of the field relative to horizontal, positive downward. | 70.31 |
horizontalIntensityNt | float | H — horizontal field strength in nanotesla, the component a compass needle aligns to. | 17107.9 |
totalIntensityNt | float | F — total field strength in nanotesla. | 50765.6 |
northComponentNt | float | X — the geodetic-north component in nanotesla. | 17036.7 |
eastComponentNt | float | Y — the geodetic-east component in nanotesla. | 1559 |
verticalComponentNt | float | Z — the downward component in nanotesla. | 47796.1 |
gridVariationDegrees nullable | float (-180 to 180) | Declination referred to the polar-stereographic grid instead of true north: `declination − longitude` from 55°N poleward, `declination + longitude` from 55°S poleward, wrapped into [−180, 180] by NOAA's own ±360 correction (which leaves an exact ±180 in place, and 2 dp rounding can land on −180). **`null` for |latitude| < 55**, the band where NOAA's own software leaves it undefined and prints `NaN` in its published test values — this API returns `null` rather than inventing a value. | -7.34 |
annualChange | object | Secular variation — the same seven keys as per-year rates (`declinationDegrees`, `inclinationDegrees`, `horizontalIntensityNt`, `totalIntensityNt`, `northComponentNt`, `eastComponentNt`, `verticalComponentNt`). The X/Y/Z rates are constant across the whole validity window because the model is linear in time; the declination, inclination, H and F rates are derived from the moving components, so they drift slightly across the five years. | {"declinationDegrees":0.16,"inclinationDegrees":0.02,"horizontalIntensityNt":-0.2,"totalIntensityNt":46.4,"northComponentNt":-4.5,"eastComponentNt":46.5,"verticalComponentNt":49.3} |
uncertainty | object | NOAA's published error model — one standard deviation between a hypothetical measurement and the model — with the same seven keys. Six values are fixed (137/89/141 nT on X/Y/Z, 133 nT on H, 138 nT on F, 0.20° on inclination); the declination uncertainty is √(0.26² + (5417/H)²) degrees and therefore grows where the horizontal field is weak. | {"declinationDegrees":0.41,"inclinationDegrees":0.2,"horizontalIntensityNt":133,"totalIntensityNt":138,"northComponentNt":137,"eastComponentNt":89,"verticalComponentNt":141} |
compassZone | string | `blackout` where H < 2000 nT (NOAA's Blackout Zone, where a magnetic compass should not be relied on for navigation), `caution` where 2000 nT ≤ H < 6000 nT (NOAA's Caution Zone), `normal` above that. Both thresholds are NOAA's; `normal` is this API's label for "outside both of NOAA's named zones" and not a NOAA term. A non-normal zone also raises a `meta.warnings` entry naming the measured H. | normal |
model | string | The model identifier that produced these numbers. Present so a stored response stays interpretable after the next model release. | WMM2025 |
date string (YYYY-MM-DD) The resolved evaluation date — the supplied `date`, or today in UTC when it was omitted.
example: 2026-07-01
decimalYear float The model's time argument, `year + (dayOfYear − 1) / (365 or 366)`, rounded to 6 dp. 2025-01-01 is exactly 2025 and 2029-12-31 is 2029.997260.
example: 2026.49589
latitude float Geodetic latitude, echoed as supplied.
example: 55.6761
longitude float Geodetic longitude, echoed as supplied.
example: 12.5683
altitudeKm float Height above the WGS 84 ellipsoid, echoed as supplied.
example: 0
declinationDegrees float (-180 to 180) Angle from true north to magnetic north, **positive east**. This is the number you add to a magnetic bearing to get a true bearing. Reported at 2 dp — NOAA's own precision, and already about ten times finer than the model's stated uncertainty.
example: 5.23
inclinationDegrees float (-90 to 90) Dip angle of the field relative to horizontal, positive downward.
example: 70.31
horizontalIntensityNt float H — horizontal field strength in nanotesla, the component a compass needle aligns to.
example: 17107.9
totalIntensityNt float F — total field strength in nanotesla.
example: 50765.6
northComponentNt float X — the geodetic-north component in nanotesla.
example: 17036.7
eastComponentNt float Y — the geodetic-east component in nanotesla.
example: 1559
verticalComponentNt float Z — the downward component in nanotesla.
example: 47796.1
gridVariationDegrees float (-180 to 180) nullable Declination referred to the polar-stereographic grid instead of true north: `declination − longitude` from 55°N poleward, `declination + longitude` from 55°S poleward, wrapped into [−180, 180] by NOAA's own ±360 correction (which leaves an exact ±180 in place, and 2 dp rounding can land on −180). **`null` for |latitude| < 55**, the band where NOAA's own software leaves it undefined and prints `NaN` in its published test values — this API returns `null` rather than inventing a value.
example: -7.34
annualChange object Secular variation — the same seven keys as per-year rates (`declinationDegrees`, `inclinationDegrees`, `horizontalIntensityNt`, `totalIntensityNt`, `northComponentNt`, `eastComponentNt`, `verticalComponentNt`). The X/Y/Z rates are constant across the whole validity window because the model is linear in time; the declination, inclination, H and F rates are derived from the moving components, so they drift slightly across the five years.
example: {"declinationDegrees":0.16,"inclinationDegrees":0.02,"horizontalIntensityNt":-0.2,"totalIntensityNt":46.4,"northComponentNt":-4.5,"eastComponentNt":46.5,"verticalComponentNt":49.3}
uncertainty object NOAA's published error model — one standard deviation between a hypothetical measurement and the model — with the same seven keys. Six values are fixed (137/89/141 nT on X/Y/Z, 133 nT on H, 138 nT on F, 0.20° on inclination); the declination uncertainty is √(0.26² + (5417/H)²) degrees and therefore grows where the horizontal field is weak.
example: {"declinationDegrees":0.41,"inclinationDegrees":0.2,"horizontalIntensityNt":133,"totalIntensityNt":138,"northComponentNt":137,"eastComponentNt":89,"verticalComponentNt":141}
compassZone string `blackout` where H < 2000 nT (NOAA's Blackout Zone, where a magnetic compass should not be relied on for navigation), `caution` where 2000 nT ≤ H < 6000 nT (NOAA's Caution Zone), `normal` above that. Both thresholds are NOAA's; `normal` is this API's label for "outside both of NOAA's named zones" and not a NOAA term. A non-normal zone also raises a `meta.warnings` entry naming the measured H.
example: normal
model string The model identifier that produced these numbers. Present so a stored response stays interpretable after the next model release.
example: WMM2025
/api/magnetic-declination?lat=55.6761&lng=12.5683&date=2026-07-01 {
"data": {
"date": "2026-07-01",
"decimalYear": 2026.49589,
"latitude": 55.6761,
"longitude": 12.5683,
"altitudeKm": 0,
"declinationDegrees": 5.23,
"inclinationDegrees": 70.31,
"horizontalIntensityNt": 17107.9,
"totalIntensityNt": 50765.6,
"northComponentNt": 17036.7,
"eastComponentNt": 1559,
"verticalComponentNt": 47796.1,
"gridVariationDegrees": -7.34,
"annualChange": {
"declinationDegrees": 0.16,
"inclinationDegrees": 0.02,
"horizontalIntensityNt": -0.2,
"totalIntensityNt": 46.4,
"northComponentNt": -4.5,
"eastComponentNt": 46.5,
"verticalComponentNt": 49.3
},
"uncertainty": {
"declinationDegrees": 0.41,
"inclinationDegrees": 0.2,
"horizontalIntensityNt": 133,
"totalIntensityNt": 138,
"northComponentNt": 137,
"eastComponentNt": 89,
"verticalComponentNt": 141
},
"compassZone": "normal",
"model": "WMM2025"
},
"meta": {
"endpoint": "magnetic-declination",
"params": {
"lat": 55.6761,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination?lat=40.7128&lng=-74.0060&date=2026-07-01 {
"data": {
"date": "2026-07-01",
"decimalYear": 2026.49589,
"latitude": 40.7128,
"longitude": -74.006,
"altitudeKm": 0,
"declinationDegrees": -12.47,
"inclinationDegrees": 65.55,
"horizontalIntensityNt": 21018.8,
"totalIntensityNt": 50785,
"northComponentNt": 20522.6,
"eastComponentNt": -4540.2,
"verticalComponentNt": 46231.2,
"gridVariationDegrees": null,
"annualChange": {
"declinationDegrees": 0.04,
"inclinationDegrees": -0.1,
"horizontalIntensityNt": 39.1,
"totalIntensityNt": -109.5,
"northComponentNt": 41.3,
"eastComponentNt": 5.8,
"verticalComponentNt": -138.1
},
"uncertainty": {
"declinationDegrees": 0.37,
"inclinationDegrees": 0.2,
"horizontalIntensityNt": 133,
"totalIntensityNt": 138,
"northComponentNt": 137,
"eastComponentNt": 89,
"verticalComponentNt": 141
},
"compassZone": "normal",
"model": "WMM2025"
},
"meta": {
"endpoint": "magnetic-declination",
"params": {
"lat": 40.7128,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination?lat=46.5&lng=8.0&date=2027-03-15&altitudeKm=11 {
"data": {
"date": "2027-03-15",
"decimalYear": 2027.2,
"latitude": 46.5,
"longitude": 8,
"altitudeKm": 11,
"declinationDegrees": 3.52,
"inclinationDegrees": 62.65,
"horizontalIntensityNt": 21994.9,
"totalIntensityNt": 47869.7,
"northComponentNt": 21953.5,
"eastComponentNt": 1349,
"verticalComponentNt": 42517.4,
"gridVariationDegrees": null,
"annualChange": {
"declinationDegrees": 0.12,
"inclinationDegrees": 0.02,
"horizontalIntensityNt": 7.1,
"totalIntensityNt": 44.6,
"northComponentNt": 4.2,
"eastComponentNt": 47.4,
"verticalComponentNt": 46.5
},
"uncertainty": {
"declinationDegrees": 0.36,
"inclinationDegrees": 0.2,
"horizontalIntensityNt": 133,
"totalIntensityNt": 138,
"northComponentNt": 137,
"eastComponentNt": 89,
"verticalComponentNt": 141
},
"compassZone": "normal",
"model": "WMM2025"
},
"meta": {
"endpoint": "magnetic-declination",
"params": {
"lat": 46.5,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination?lat=-62&lng=130&date=2026-07-01 {
"data": {
"date": "2026-07-01",
"decimalYear": 2026.49589,
"latitude": -62,
"longitude": 130,
"altitudeKm": 0,
"declinationDegrees": -47.21,
"inclinationDegrees": -88.56,
"horizontalIntensityNt": 1681.9,
"totalIntensityNt": 66738.3,
"northComponentNt": 1142.6,
"eastComponentNt": -1234.2,
"verticalComponentNt": -66717.1,
"gridVariationDegrees": 82.79,
"annualChange": {
"declinationDegrees": 0.45,
"inclinationDegrees": -0.04,
"horizontalIntensityNt": -44.5,
"totalIntensityNt": -10.4,
"northComponentNt": -20.6,
"eastComponentNt": 41.6,
"verticalComponentNt": 9.3
},
"uncertainty": {
"declinationDegrees": 3.23,
"inclinationDegrees": 0.2,
"horizontalIntensityNt": 133,
"totalIntensityNt": 138,
"northComponentNt": 137,
"eastComponentNt": 89,
"verticalComponentNt": 141
},
"compassZone": "blackout",
"model": "WMM2025"
},
"meta": {
"endpoint": "magnetic-declination",
"params": {
"lat": -62,
…
]
}
} /api/magnetic-declination?lat=55.6761&lng=12.5683&date=2029-12-31 {
"data": {
"date": "2029-12-31",
"decimalYear": 2029.99726,
"latitude": 55.6761,
"longitude": 12.5683,
"altitudeKm": 0,
"declinationDegrees": 5.78,
"inclinationDegrees": 70.37,
"horizontalIntensityNt": 17107.9,
"totalIntensityNt": 50928.3,
"northComponentNt": 17021,
"eastComponentNt": 1721.7,
"verticalComponentNt": 47968.9,
"gridVariationDegrees": -6.79,
"annualChange": {
"declinationDegrees": 0.16,
"inclinationDegrees": 0.02,
"horizontalIntensityNt": 0.2,
"totalIntensityNt": 46.5,
"northComponentNt": -4.5,
"eastComponentNt": 46.5,
"verticalComponentNt": 49.3
},
"uncertainty": {
"declinationDegrees": 0.41,
"inclinationDegrees": 0.2,
"horizontalIntensityNt": 133,
"totalIntensityNt": 138,
"northComponentNt": 137,
"eastComponentNt": 89,
"verticalComponentNt": 141
},
"compassZone": "normal",
"model": "WMM2025"
},
"meta": {
"endpoint": "magnetic-declination",
"params": {
"lat": 55.6761,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} Supply exactly one of magneticHeading or trueHeading; supplying both is a 400 because the other one is the answer, not an input. Both headings come back normalised into [0, 360), so a heading that wraps past north does not print as 362°.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
lat
required
| float | allowed: -90 – 90 example: 55.6761 | Geodetic (WGS 84) latitude in decimal degrees, positive north. ±90 is accepted: the East component's polar singularity is handled by the model's limiting series, so the poles answer a real value instead of NaN. |
lng
required
| float | allowed: -180 – 180 example: 12.5683 | Geodetic (WGS 84) longitude in decimal degrees, positive east. The antimeridian is not special — the expansion only ever uses cos/sin of multiples of the longitude. |
date | date | example: 2026-07-01 | Calendar date the field is evaluated for (YYYY-MM-DD), which **defaults to today in UTC** — the resolved value comes back in the `date` field and in `meta.params.date`. Must land inside 2025-01-01…2029-12-31; anything else is a 400 rather than an extrapolation. Internally the date becomes the model's decimal year, `year + (dayOfYear − 1) / (365 or 366)`. |
altitudeKm | float | default: 0 allowed: -1 – 850 example: 100 | Height above the WGS 84 ellipsoid in kilometres. WMM2025's documented envelope is −1 km to 850 km and both ends are inclusive; sea level (0) is the default. |
magneticHeading | float | allowed: 0 – 360 example: 45 | Compass (magnetic) heading in degrees. Supply exactly one of `magneticHeading` or `trueHeading`. 360 is accepted and normalises to 0. |
trueHeading | float | allowed: 0 – 360 example: 90 | True (geographic) heading in degrees, for the inverse conversion. Supply exactly one of `magneticHeading` or `trueHeading`. |
lat float required Geodetic (WGS 84) latitude in decimal degrees, positive north. ±90 is accepted: the East component's polar singularity is handled by the model's limiting series, so the poles answer a real value instead of NaN.
lng float required Geodetic (WGS 84) longitude in decimal degrees, positive east. The antimeridian is not special — the expansion only ever uses cos/sin of multiples of the longitude.
date date Calendar date the field is evaluated for (YYYY-MM-DD), which **defaults to today in UTC** — the resolved value comes back in the `date` field and in `meta.params.date`. Must land inside 2025-01-01…2029-12-31; anything else is a 400 rather than an extrapolation. Internally the date becomes the model's decimal year, `year + (dayOfYear − 1) / (365 or 366)`.
altitudeKm float Height above the WGS 84 ellipsoid in kilometres. WMM2025's documented envelope is −1 km to 850 km and both ends are inclusive; sea level (0) is the default.
magneticHeading float Compass (magnetic) heading in degrees. Supply exactly one of `magneticHeading` or `trueHeading`. 360 is accepted and normalises to 0.
trueHeading float True (geographic) heading in degrees, for the inverse conversion. Supply exactly one of `magneticHeading` or `trueHeading`.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
fields | list | example: date,decimalYear | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: declinationUncertaintyDegrees | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
date | string (YYYY-MM-DD) | The resolved evaluation date — the supplied `date`, or today in UTC when it was omitted. | 2026-07-01 |
decimalYear | float | The model's time argument, `year + (dayOfYear − 1) / (365 or 366)`, rounded to 6 dp. 2025-01-01 is exactly 2025 and 2029-12-31 is 2029.997260. | 2026.49589 |
latitude | float | Geodetic latitude, echoed as supplied. | 55.6761 |
longitude | float | Geodetic longitude, echoed as supplied. | 12.5683 |
altitudeKm | float | Height above the WGS 84 ellipsoid, echoed as supplied. | 0 |
providedHeading | string | Which input was supplied: `magnetic` or `true`. | magnetic |
magneticHeading | float (0 to 360) | The magnetic heading — supplied or derived — normalised into [0, 360). | 45 |
trueHeading | float (0 to 360) | The true heading — supplied or derived — normalised into [0, 360). | 50.23 |
declinationDegrees | float (-180 to 180) | The declination applied at this point, date and height, positive east. | 5.23 |
rule | string | The convention spelled out, so the sign never has to be guessed. | true = magnetic + declination (east declination positive); magnetic = true − declination |
horizontalIntensityNt | float | H at the point — the field strength the compass has to work with. | 17107.9 |
compassZone | string | `blackout` where H < 2000 nT (NOAA's Blackout Zone, where a magnetic compass should not be relied on for navigation), `caution` where 2000 nT ≤ H < 6000 nT (NOAA's Caution Zone), `normal` above that. Both thresholds are NOAA's; `normal` is this API's label for "outside both of NOAA's named zones" and not a NOAA term. A non-normal zone also raises a `meta.warnings` entry naming the measured H. | normal |
declinationUncertaintyDegrees | float | NOAA's one-standard-deviation uncertainty on the declination that was applied, √(0.26² + (5417/H)²), so the converted heading carries its own error bar. | 0.41 |
date string (YYYY-MM-DD) The resolved evaluation date — the supplied `date`, or today in UTC when it was omitted.
example: 2026-07-01
decimalYear float The model's time argument, `year + (dayOfYear − 1) / (365 or 366)`, rounded to 6 dp. 2025-01-01 is exactly 2025 and 2029-12-31 is 2029.997260.
example: 2026.49589
latitude float Geodetic latitude, echoed as supplied.
example: 55.6761
longitude float Geodetic longitude, echoed as supplied.
example: 12.5683
altitudeKm float Height above the WGS 84 ellipsoid, echoed as supplied.
example: 0
providedHeading string Which input was supplied: `magnetic` or `true`.
example: magnetic
magneticHeading float (0 to 360) The magnetic heading — supplied or derived — normalised into [0, 360).
example: 45
trueHeading float (0 to 360) The true heading — supplied or derived — normalised into [0, 360).
example: 50.23
declinationDegrees float (-180 to 180) The declination applied at this point, date and height, positive east.
example: 5.23
rule string The convention spelled out, so the sign never has to be guessed.
example: true = magnetic + declination (east declination positive); magnetic = true − declination
horizontalIntensityNt float H at the point — the field strength the compass has to work with.
example: 17107.9
compassZone string `blackout` where H < 2000 nT (NOAA's Blackout Zone, where a magnetic compass should not be relied on for navigation), `caution` where 2000 nT ≤ H < 6000 nT (NOAA's Caution Zone), `normal` above that. Both thresholds are NOAA's; `normal` is this API's label for "outside both of NOAA's named zones" and not a NOAA term. A non-normal zone also raises a `meta.warnings` entry naming the measured H.
example: normal
declinationUncertaintyDegrees float NOAA's one-standard-deviation uncertainty on the declination that was applied, √(0.26² + (5417/H)²), so the converted heading carries its own error bar.
example: 0.41
/api/magnetic-declination/true-heading?lat=55.6761&lng=12.5683&magneticHeading=45&date=2026-07-01 {
"data": {
"date": "2026-07-01",
"decimalYear": 2026.49589,
"latitude": 55.6761,
"longitude": 12.5683,
"altitudeKm": 0,
"providedHeading": "magnetic",
"magneticHeading": 45,
"trueHeading": 50.23,
"declinationDegrees": 5.23,
"rule": "true = magnetic + declination (east declination positive); magnetic = true − declination",
"horizontalIntensityNt": 17107.9,
"compassZone": "normal",
"declinationUncertaintyDegrees": 0.41
},
"meta": {
"endpoint": "magnetic-declination",
"route": "/true-heading",
"params": {
"lat": 55.6761,
"lng": 12.5683,
"date": "2026-07-01",
"altitudeKm": 0,
"magneticHeading": 45
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination/true-heading?lat=40.7128&lng=-74.0060&trueHeading=90&date=2026-07-01 {
"data": {
"date": "2026-07-01",
"decimalYear": 2026.49589,
"latitude": 40.7128,
"longitude": -74.006,
"altitudeKm": 0,
"providedHeading": "true",
"magneticHeading": 102.47,
"trueHeading": 90,
"declinationDegrees": -12.47,
"rule": "true = magnetic + declination (east declination positive); magnetic = true − declination",
"horizontalIntensityNt": 21018.8,
"compassZone": "normal",
"declinationUncertaintyDegrees": 0.37
},
"meta": {
"endpoint": "magnetic-declination",
"route": "/true-heading",
"params": {
"lat": 40.7128,
"lng": -74.006,
"date": "2026-07-01",
"altitudeKm": 0,
"trueHeading": 90
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination/true-heading?lat=55.6761&lng=12.5683&magneticHeading=357&date=2026-07-01 {
"data": {
"date": "2026-07-01",
"decimalYear": 2026.49589,
"latitude": 55.6761,
"longitude": 12.5683,
"altitudeKm": 0,
"providedHeading": "magnetic",
"magneticHeading": 357,
"trueHeading": 2.23,
"declinationDegrees": 5.23,
"rule": "true = magnetic + declination (east declination positive); magnetic = true − declination",
"horizontalIntensityNt": 17107.9,
"compassZone": "normal",
"declinationUncertaintyDegrees": 0.41
},
"meta": {
"endpoint": "magnetic-declination",
"route": "/true-heading",
"params": {
"lat": 55.6761,
"lng": 12.5683,
"date": "2026-07-01",
"altitudeKm": 0,
"magneticHeading": 357
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} The one route that never rejects a date. It exists so the other routes' refusal is discoverable and machine-checkable: ?date=2031-01-01 returns 200 with withinValidity: false and a negative daysUntilExpiry.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
date | date | example: 2030-06-01 | Date to test against the model's validity window; defaults to today in UTC. Unlike the other routes this one never rejects a date — reporting on out-of-window dates is its purpose. |
date date Date to test against the model's validity window; defaults to today in UTC. Unlike the other routes this one never rejects a date — reporting on out-of-window dates is its purpose.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
fields | list | example: model,epoch | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: daysUntilExpiry | Return all fields except these (comma-separated). |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
model | string | Model identifier. | WMM2025 |
epoch | float | The epoch the main-field coefficients are given at, as a decimal year. | 2025 |
validFrom | string (YYYY-MM-DD) | First date the endpoint will evaluate the model for. | 2025-01-01 |
validUntil | string (YYYY-MM-DD) | Last date the endpoint will evaluate the model for, inclusive. | 2029-12-31 |
releaseDate | string (YYYY-MM-DD) | The date NOAA released this model version. | 2024-12-17 |
degree | integer | Maximum spherical-harmonic degree of the main-field expansion. | 12 |
order | integer | Maximum spherical-harmonic order. | 12 |
coefficientRows | integer | Rows in the coefficient file — one per (degree, order) pair, Σ(n+1) for n = 1…12. | 90 |
mainFieldCoefficients | integer | Main-field Gauss coefficients: 90 gₙᵐ plus 78 hₙᵐ (hₙ⁰ does not exist). | 168 |
secularVariationCoefficients | integer | Secular-variation coefficients — the same count again, for 336 in total. | 168 |
geomagneticReferenceRadiusKm | float | The geomagnetic reference sphere the expansion is written on. Not the same number as the WGS 84 semi-major axis (6378.137 km) the caller's latitude and altitude refer to; both are used and they are not interchangeable. | 6371.2 |
ellipsoid | string | The reference ellipsoid `lat`, `lng` and `altitudeKm` are interpreted against. | WGS 84 |
altitudeRangeKm | object | The model's documented altitude envelope above the ellipsoid: `{ min, max }` in kilometres, both inclusive. | {"min":-1,"max":850} |
producedBy | string | Who produces and develops the model. | Produced by the US National Geospatial-Intelligence Agency (NGA) and the UK Defence Geographic Centre (DGC); jointly developed by NOAA NCEI and the British Geological Survey (BGS). |
coefficientFileSha256 | string | SHA-256 of the pinned `WMM2025COF/WMM.COF` these coefficients were transcribed from, so a client can verify it is looking at the same bytes. | dfa8597825af4e0b87ff4198a5b4fb661b3c49f4cd090cd0164e0259b075582f |
date | string (YYYY-MM-DD) | The resolved evaluation date — the supplied `date`, or today in UTC when it was omitted. | 2026-07-01 |
decimalYear | float | The model's time argument, `year + (dayOfYear − 1) / (365 or 366)`, rounded to 6 dp. 2025-01-01 is exactly 2025 and 2029-12-31 is 2029.997260. | 2026.49589 |
withinValidity | boolean | Whether the resolved `date` falls inside the validity window (inclusive at both ends). | true |
daysUntilExpiry | integer | Whole days from the resolved `date` to `validUntil`: 0 on the last valid day and **negative** once the model has expired. | 1279 |
model string Model identifier.
example: WMM2025
epoch float The epoch the main-field coefficients are given at, as a decimal year.
example: 2025
validFrom string (YYYY-MM-DD) First date the endpoint will evaluate the model for.
example: 2025-01-01
validUntil string (YYYY-MM-DD) Last date the endpoint will evaluate the model for, inclusive.
example: 2029-12-31
releaseDate string (YYYY-MM-DD) The date NOAA released this model version.
example: 2024-12-17
degree integer Maximum spherical-harmonic degree of the main-field expansion.
example: 12
order integer Maximum spherical-harmonic order.
example: 12
coefficientRows integer Rows in the coefficient file — one per (degree, order) pair, Σ(n+1) for n = 1…12.
example: 90
mainFieldCoefficients integer Main-field Gauss coefficients: 90 gₙᵐ plus 78 hₙᵐ (hₙ⁰ does not exist).
example: 168
secularVariationCoefficients integer Secular-variation coefficients — the same count again, for 336 in total.
example: 168
geomagneticReferenceRadiusKm float The geomagnetic reference sphere the expansion is written on. Not the same number as the WGS 84 semi-major axis (6378.137 km) the caller's latitude and altitude refer to; both are used and they are not interchangeable.
example: 6371.2
ellipsoid string The reference ellipsoid `lat`, `lng` and `altitudeKm` are interpreted against.
example: WGS 84
altitudeRangeKm object The model's documented altitude envelope above the ellipsoid: `{ min, max }` in kilometres, both inclusive.
example: {"min":-1,"max":850}
producedBy string Who produces and develops the model.
example: Produced by the US National Geospatial-Intelligence Agency (NGA) and the UK Defence Geographic Centre (DGC); jointly developed by NOAA NCEI and the British Geological Survey (BGS).
coefficientFileSha256 string SHA-256 of the pinned `WMM2025COF/WMM.COF` these coefficients were transcribed from, so a client can verify it is looking at the same bytes.
example: dfa8597825af4e0b87ff4198a5b4fb661b3c49f4cd090cd0164e0259b075582f
date string (YYYY-MM-DD) The resolved evaluation date — the supplied `date`, or today in UTC when it was omitted.
example: 2026-07-01
decimalYear float The model's time argument, `year + (dayOfYear − 1) / (365 or 366)`, rounded to 6 dp. 2025-01-01 is exactly 2025 and 2029-12-31 is 2029.997260.
example: 2026.49589
withinValidity boolean Whether the resolved `date` falls inside the validity window (inclusive at both ends).
example: true
daysUntilExpiry integer Whole days from the resolved `date` to `validUntil`: 0 on the last valid day and **negative** once the model has expired.
example: 1279
/api/magnetic-declination/model {
"data": {
"model": "WMM2025",
"epoch": 2025,
"validFrom": "2025-01-01",
"validUntil": "2029-12-31",
"releaseDate": "2024-12-17",
"degree": 12,
"order": 12,
"coefficientRows": 90,
"mainFieldCoefficients": 168,
"secularVariationCoefficients": 168,
"geomagneticReferenceRadiusKm": 6371.2,
"ellipsoid": "WGS 84",
"altitudeRangeKm": {
"min": -1,
"max": 850
},
"producedBy": "Produced by the US National Geospatial-Intelligence Agency (NGA) and the UK Defence Geographic Centre (DGC); jointly developed by NOAA NCEI and the British Geological Survey (BGS).",
"coefficientFileSha256": "dfa8597825af4e0b87ff4198a5b4fb661b3c49f4cd090cd0164e0259b075582f",
"date": "2026-07-30",
"decimalYear": 2026.575342,
"withinValidity": true,
"daysUntilExpiry": 1250
},
"meta": {
"endpoint": "magnetic-declination",
"route": "/model",
"params": {
"date": "2026-07-30"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination/model?date=2030-06-01 {
"data": {
"model": "WMM2025",
"epoch": 2025,
"validFrom": "2025-01-01",
"validUntil": "2029-12-31",
"releaseDate": "2024-12-17",
"degree": 12,
"order": 12,
"coefficientRows": 90,
"mainFieldCoefficients": 168,
"secularVariationCoefficients": 168,
"geomagneticReferenceRadiusKm": 6371.2,
"ellipsoid": "WGS 84",
"altitudeRangeKm": {
"min": -1,
"max": 850
},
"producedBy": "Produced by the US National Geospatial-Intelligence Agency (NGA) and the UK Defence Geographic Centre (DGC); jointly developed by NOAA NCEI and the British Geological Survey (BGS).",
"coefficientFileSha256": "dfa8597825af4e0b87ff4198a5b4fb661b3c49f4cd090cd0164e0259b075582f",
"date": "2030-06-01",
"decimalYear": 2030.413699,
"withinValidity": false,
"daysUntilExpiry": -152
},
"meta": {
"endpoint": "magnetic-declination",
"route": "/model",
"params": {
"date": "2030-06-01"
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} The whole model as JSON, in the coefficient file's own canonical order (degree 1…12, and within each degree, order 0…degree). Filters narrow it; every valid degree/order pair matches at least one row, so an impossible combination is a 400 rather than a silently empty list. This route has no date param and no expiry behaviour.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
degree | int | allowed: 1 – 12 example: 1 | Spherical-harmonic degree n. Omit for all degrees. |
order | int | allowed: 0 – 12 example: 0 | Spherical-harmonic order m. Omit for all orders. Must be ≤ `degree` when both are given. |
degree int Spherical-harmonic degree n. Omit for all degrees.
order int Spherical-harmonic order m. Omit for all orders. Must be ≤ `degree` when both are given.
| Parameter | Type | Default & allowed | Description |
|---|---|---|---|
count | int | default: all matches allowed: 1 – 100 example: 3 | Limit the number of returned records (1–100). Defaults to all matches. |
fields | list | example: degree,order | Return only these fields (comma-separated). Mutually exclusive with 'exclude'. |
exclude | list | example: hDotNtPerYear | Return all fields except these (comma-separated). |
format | enum | default: json allowed: json | ndjson | csv example: csv | Response format: json envelope, ndjson (one record per line) or csv. |
pretty | boolean | default: false example: true | Pretty-print the JSON response. |
unwrap | boolean | default: false example: true | Drop the envelope: return the raw array/object without data/meta wrapper. |
count int Limit the number of returned records (1–100). Defaults to all matches.
fields list Return only these fields (comma-separated). Mutually exclusive with 'exclude'.
exclude list Return all fields except these (comma-separated).
format enum Response format: json envelope, ndjson (one record per line) or csv.
pretty boolean Pretty-print the JSON response.
unwrap boolean Drop the envelope: return the raw array/object without data/meta wrapper.
| Field | Type | Description | Example |
|---|---|---|---|
degree | integer (1-12) | Degree n. | 1 |
order | integer (0-12) | Order m. | 0 |
gNt | float | Main-field cosine coefficient gₙᵐ at epoch 2025.0, nanotesla. | -29351.8 |
hNt nullable | float | Main-field sine coefficient hₙᵐ, nanotesla. **`null` when `order` is 0** — hₙ⁰ does not exist, because its sin(0·λ) term vanishes. The coefficient file writes `0.0` in that column as padding, and padding is not published here as though it were a value. | null |
gDotNtPerYear | float | Secular-variation rate ġₙᵐ, nanotesla per year. | 12 |
hDotNtPerYear nullable | float | Secular-variation rate ḣₙᵐ, nanotesla per year; `null` when `order` is 0, for the same reason as `hNt`. | null |
degree integer (1-12) Degree n.
example: 1
order integer (0-12) Order m.
example: 0
gNt float Main-field cosine coefficient gₙᵐ at epoch 2025.0, nanotesla.
example: -29351.8
hNt float nullable Main-field sine coefficient hₙᵐ, nanotesla. **`null` when `order` is 0** — hₙ⁰ does not exist, because its sin(0·λ) term vanishes. The coefficient file writes `0.0` in that column as padding, and padding is not published here as though it were a value.
example: null
gDotNtPerYear float Secular-variation rate ġₙᵐ, nanotesla per year.
example: 12
hDotNtPerYear float nullable Secular-variation rate ḣₙᵐ, nanotesla per year; `null` when `order` is 0, for the same reason as `hNt`.
example: null
/api/magnetic-declination/coefficients {
"data": [
{
"degree": 1,
"order": 0,
"gNt": -29351.8,
"hNt": null,
"gDotNtPerYear": 12,
"hDotNtPerYear": null
},
{
"degree": 1,
"order": 1,
"gNt": -1410.8,
"hNt": 4545.4,
"gDotNtPerYear": 9.7,
"hDotNtPerYear": -21.5
},
{
"degree": 2,
"order": 0,
"gNt": -2556.6,
"hNt": null,
"gDotNtPerYear": -11.6,
"hDotNtPerYear": null
},
{
"degree": 2,
"order": 1,
"gNt": 2951.1,
"hNt": -3133.6,
"gDotNtPerYear": -5.2,
"hDotNtPerYear": -27.7
},
{
"degree": 2,
"order": 2,
"gNt": 1649.3,
"hNt": -815.1,
"gDotNtPerYear": -8,
…
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination/coefficients?degree=1 {
"data": [
{
"degree": 1,
"order": 0,
"gNt": -29351.8,
"hNt": null,
"gDotNtPerYear": 12,
"hDotNtPerYear": null
},
{
"degree": 1,
"order": 1,
"gNt": -1410.8,
"hNt": 4545.4,
"gDotNtPerYear": 9.7,
"hDotNtPerYear": -21.5
}
],
"meta": {
"endpoint": "magnetic-declination",
"route": "/coefficients",
"count": 2,
"params": {
"degree": 1
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination/coefficients?degree=12&order=12 {
"data": [
{
"degree": 12,
"order": 12,
"gNt": -0.7,
"hNt": 0.2,
"gDotNtPerYear": -0.1,
"hDotNtPerYear": -0.1
}
],
"meta": {
"endpoint": "magnetic-declination",
"route": "/coefficients",
"count": 1,
"params": {
"degree": 12,
"order": 12
},
"generatedAt": "2026-07-30T15:14:08.000Z"
}
} /api/magnetic-declination/coefficients?order=0&format=csv degree,order,gNt,hNt,gDotNtPerYear,hDotNtPerYear
1,0,-29351.8,,12,
2,0,-2556.6,,-11.6,
3,0,1361,,-1.3,
4,0,895,,-1.6,
5,0,-233.2,,0.6,
6,0,64.4,,-0.2,
7,0,79.5,,0,
8,0,23.2,,-0.1,
9,0,4.6,,0,
10,0,-1.3,,0.1,
11,0,2.9,,0,
12,0,-2,,0,
Declination — the angle between true north and where a compass needle actually points — evaluated from the official World Magnetic Model 2025 coefficients. NOAA calls WMM "the standard model for navigation, attitude, and heading referencing systems" that use the geomagnetic field, and ships it as an HTML calculator plus a zipped coefficient file; this endpoint is the JSON version, with no key, no signup and no quota form.
/api/magnetic-declination?lat=…&lng=… — declination, inclination, H/F, the X/Y/Z components, grid variation, NOAA's per-element uncertainty and the secular-variation rates at one point./api/magnetic-declination/true-heading — the conversion, spelled out: true = magnetic + declination, east declination positive. Supply exactly one of magneticHeading or trueHeading and the other comes back, normalised into [0, 360), with the declination's own error bar beside it./api/magnetic-declination/model — the pinned model's epoch, validity window, degree/order, coefficient counts, provenance and whether a given date falls inside it. This route never rejects a date; that is its job./api/magnetic-declination/coefficients — all 90 Gauss coefficient rows, so you can diff your own client-side implementation against a published copy.The evaluator reproduces all 112 of NOAA's published WMM2025 test values — the 12-row file NCEI publishes beside the model and the 100-row set inside the coefficient archive — to within one unit in their last published digit, across both official epochs, both official altitudes and every published coordinate. That comparison is a committed test, not a claim. The coefficients themselves are transcribed by script from WMM2025COF/WMM.COF (4554 bytes, pinned by SHA-256), never by hand, and a parity script re-derives and re-hashes everything on demand. Nothing is fetched while your request is served.
WMM2025 has a five-year life. A date outside its window returns a 400, never an extrapolated heading — the model simply is not defined there. date is optional: omit it and the field is evaluated for today in UTC, with the resolved date echoed in the date field and in meta.params.date. The documented examples all pin an explicit date on purpose, so the docs table keeps working for the life of the model; the default itself is the live clock. /model answers for any date at all and reports withinValidity plus a daysUntilExpiry that goes negative after expiry, which is how you detect staleness programmatically. (NOAA's own online calculator accepts dates from 2024-11-13, the date stamped in the coefficient file's header; this endpoint starts at the 2025.0 epoch rather than publishing values for dates before the model's own five-year period.)
NOAA's error model is returned with every answer: 137/89/141 nT on X/Y/Z, 133 nT on H, 138 nT on F, 0.20° on inclination, and √(0.26² + (5417/H)²)° on declination — so the uncertainty grows as the horizontal field weakens, reaching about 2.7° at the blackout-zone edge. Where H < 2000 nT you are inside NOAA's Blackout Zone and a compass should not be relied on at all; compassZone says so and a warning names the measured H.
Deliberately not modelled, because pretending otherwise would be the dishonest part:
tz param. Declination drifts ~0.16°/year at Copenhagen — about 0.0004°/day, three orders of magnitude below the model's own 0.26° uncertainty floor. A timezone would imply a precision the model does not have.No navigational, aeronautical, legal or safety-critical authority is claimed. Runway designators, VOR radials and charted isogonals are published values and are the authority; use them.
GET /api/magnetic-declination?lat=55.6761&lng=12.5683 returns declination, inclination, field strength and the annual rate of change — no signup, no key, no quota form. date is optional and defaults to today in UTC; the date actually used comes back in the date field and in meta.params.date.
/api/magnetic-declination/true-heading?lat=55.6761&lng=12.5683&magneticHeading=45 applies the convention verbatim: true = magnetic + declination, with east declination positive. Pass trueHeading instead for the inverse, and the response repeats the rule in a rule field so nobody has to guess the sign.
NOAA's own error model is returned with every answer — the declination uncertainty is √(0.26² + (5417/H)²) degrees, so it grows where the horizontal field is weak. The bigger reason is that WMM models only the core field: NOAA notes local, regional and temporal declination anomalies "can exceed 10 degrees", with 3–4° anomalies "not uncommon". Deviation from ferrous metal near your own compass is not modelled by anything.
Dates outside 2025-01-01…2029-12-31 return a 400 — the endpoint refuses to extrapolate. That includes an omitted date: once the model expires, the clock-resolved default is out of window and the request fails by design rather than serving a quietly wrong heading. /api/magnetic-declination/model still answers for any date, with withinValidity: false and a negative daysUntilExpiry.
No. This is WMM2025: degree and order 12, 336 coefficients, the standard model. WMMHR2025 is a separate, much larger model — core field to degree 15 and a crustal field to degree 133, 18,210 non-zero coefficients in a 534 KB file — and is deliberately not shipped here.
No certification is claimed. It is the same model those charts are derived from, but the published values — runway designators, VOR radials, charted isogonals — are the authority for navigation, and local anomalies plus your own vehicle's deviation are outside what any coordinate-based model can tell you.
Great-circle distance, bearings, destinations and bounding boxes for WGS 84 coordinates on an explicitly documented mean-Earth sphere.
Parse messy DMS, DDM, decimal or ISO 6709 coordinate text into WGS 84 decimal degrees, reformat a point in any notation, and convert Maidenhead locators.
Random geographic coordinates: uniform across the globe (no pole clustering), inside a bounding box, or within a radius of a point — with haversine distances.
Sunrise, sunset, solar noon, day length, the three twilights and solar elevation/azimuth for any coordinate and date, from the NOAA equations.
Moon phase, illumination, moonrise, moonset, lunar transit and topocentric position for any coordinate, plus every primary phase instant of a year. No key.
Every scheduled-service airport with an IATA code — 4,159 rows with ICAO code, city, country, coordinates, elevation and IANA time zone.