Skip to main content

DMS to Decimal Degrees Converter API

REAL DATA

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.

Authoritative reference data or standards computation

Base URL
/api/coordinate-formats
Capabilities
3 routes
Last updated
July 29, 2026
Data source

GET /api/coordinate-formats/parse

Accepts DMS, degrees + decimal minutes, decimal degrees and ISO 6709 string expressions. Ambiguous text is rejected with a named reason instead of being guessed.

Live requestRuns against the public API
No key required
GET/api/coordinate-formats/parse?value=57%C2%B042%2712.3%22N%2C+011%C2%B058%2701%22W

Request parameters

Coordinate text in any supported notation — DMS, degrees and decimal minutes, decimal degrees, or an ISO 6709 string expression. Spaces, colons and slashes separate the parts of one coordinate; a comma or semicolon separates the two, and that split is honoured exactly rather than re-guessed. Signs and N/S/E/W letters may not both appear. Unicode prime marks, smart quotes, '' and the Unicode minus sign are folded to their ASCII equivalents.

Which coordinate comes first when the text itself cannot say. Omit it for text with N/S/E/W letters, for ISO 6709, and where one value exceeds 90 degrees; a bare pair with both values inside ±90 is rejected until you supply it. When you do supply it for letterless text it is authoritative, so a value that cannot sit on the axis you assigned is a 400 rather than a silent swap. The resolved order is echoed in meta.params.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/coordinate-formats/parse?value=57%C2%B042%2712.3%22N%2C%20011%C2%B058%2701%22W"
const res = await fetch("https://randomapi.dev/api/coordinate-formats/parse?value=57%C2%B042%2712.3%22N%2C%20011%C2%B058%2701%22W");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/coordinate-formats/parse?value=57%C2%B042%2712.3%22N%2C%20011%C2%B058%2701%22W").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/coordinate-formats/parse?value=57%C2%B042%2712.3%22N%2C%20011%C2%B058%2701%22W"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 2
value string required

Coordinate text in any supported notation — DMS, degrees and decimal minutes, decimal degrees, or an ISO 6709 string expression. Spaces, colons and slashes separate the parts of one coordinate; a comma or semicolon separates the two, and that split is honoured exactly rather than re-guessed. Signs and N/S/E/W letters may not both appear. Unicode prime marks, smart quotes, '' and the Unicode minus sign are folded to their ASCII equivalents.

allowed: 3 – 128
example: value=57°42'12.3"N, 011°58'01"W
order enum

Which coordinate comes first when the text itself cannot say. Omit it for text with N/S/E/W letters, for ISO 6709, and where one value exceeds 90 degrees; a bare pair with both values inside ±90 is rejected until you supply it. When you do supply it for letterless text it is authoritative, so a value that cannot sit on the axis you assigned is a 400 rather than a silent swap. The resolved order is echoed in meta.params.

allowed: latlng | lnglat
example: order=lnglat
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=input,detectedFormat
exclude list

Return all fields except these (comma-separated).

example: exclude=warnings
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 8
input string

The coordinate text exactly as received, before notation folding.

example: 57°42'12.3"N, 011°58'01"W

detectedFormat string

Notation found in the text: decimal, ddm, dms, mixed (one of each) or iso6709.

example: dms

detectedOrder string

Which coordinate came first — latlng or lnglat. Decided by hemisphere letters, by a value above 90, or by the 'order' parameter.

example: latlng

latitude float

Latitude in WGS 84 decimal degrees, rounded to 9 decimals. No datum transformation is applied.

example: 57.703416667

longitude float

Longitude in WGS 84 decimal degrees, rounded to 9 decimals.

example: -11.966944444

hemisphereSource string

How the hemispheres were established, per axis: letter (both carry N/S/E/W), sign (signed notation, where an unsigned value means north/east), inferred (neither letters nor signs) or mixed (only one axis carries a letter — the other was assumed, and a warning says which).

example: letter

precisionDigits integer

Fractional digits carried by the smallest unit in the text, taken as the larger of the two coordinates.

example: 1

warnings string[]

Parser notes: an overridden 'order', a missing ISO 6709 solidus, an ignored height, or an axis whose hemisphere was assumed because it carried no letter. Empty when there is nothing to report.

example: []

Documented examples

Build-generated requests and complete responses
6
Degrees, minutes and seconds with hemisphere letters
GET /api/coordinate-formats/parse?value=57%C2%B042%2712.3%22N%2C%20011%C2%B058%2701%22W
{
  "data": {
    "input": "57°42'12.3\"N, 011°58'01\"W",
    "detectedFormat": "dms",
    "detectedOrder": "latlng",
    "latitude": 57.703416667,
    "longitude": -11.966944444,
    "hemisphereSource": "letter",
    "precisionDigits": 1,
    "warnings": []
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/parse",
    "params": {
      "value": "57°42'12.3\"N, 011°58'01\"W",
      "order": "latlng"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
ISO 6709 string expression
GET /api/coordinate-formats/parse?value=%2B57.7034-011.9669%2F
{
  "data": {
    "input": "+57.7034-011.9669/",
    "detectedFormat": "iso6709",
    "detectedOrder": "latlng",
    "latitude": 57.7034,
    "longitude": -11.9669,
    "hemisphereSource": "sign",
    "precisionDigits": 4,
    "warnings": []
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/parse",
    "params": {
      "value": "+57.7034-011.9669/",
      "order": "latlng"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Degrees and decimal minutes, letters first
GET /api/coordinate-formats/parse?value=N57%2042.205%20W011%2058.017
{
  "data": {
    "input": "N57 42.205 W011 58.017",
    "detectedFormat": "ddm",
    "detectedOrder": "latlng",
    "latitude": 57.703416667,
    "longitude": -11.96695,
    "hemisphereSource": "letter",
    "precisionDigits": 3,
    "warnings": []
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/parse",
    "params": {
      "value": "N57 42.205 W011 58.017",
      "order": "latlng"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Bare pair read as longitude then latitude
GET /api/coordinate-formats/parse?value=11.9669%2C%2057.7034&order=lnglat
{
  "data": {
    "input": "11.9669, 57.7034",
    "detectedFormat": "decimal",
    "detectedOrder": "lnglat",
    "latitude": 57.7034,
    "longitude": 11.9669,
    "hemisphereSource": "inferred",
    "precisionDigits": 4,
    "warnings": [
      "No hemisphere letters or signs were present, so both values were read as northern and eastern."
    ]
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/parse",
    "params": {
      "value": "11.9669, 57.7034",
      "order": "lnglat"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Integer-minute DDM split by an explicit separator
GET /api/coordinate-formats/parse?value=57%2042%2C%20011%2058&order=latlng
{
  "data": {
    "input": "57 42, 011 58",
    "detectedFormat": "ddm",
    "detectedOrder": "latlng",
    "latitude": 57.7,
    "longitude": 11.966666667,
    "hemisphereSource": "inferred",
    "precisionDigits": 0,
    "warnings": [
      "No hemisphere letters or signs were present, so both values were read as northern and eastern."
    ]
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/parse",
    "params": {
      "value": "57 42, 011 58",
      "order": "latlng"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
European decimal commas
GET /api/coordinate-formats/parse?value=57%2C7034%3B%20-11%2C9669&order=latlng
{
  "data": {
    "input": "57,7034; -11,9669",
    "detectedFormat": "decimal",
    "detectedOrder": "latlng",
    "latitude": 57.7034,
    "longitude": -11.9669,
    "hemisphereSource": "sign",
    "precisionDigits": 4,
    "warnings": []
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/parse",
    "params": {
      "value": "57,7034; -11,9669",
      "order": "latlng"
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}

GET /api/coordinate-formats/convert

Rounds half away from zero at the requested precision and carries seconds or minutes that reach 60 into the next larger unit.

Live requestRuns against the public API
No key required
GET/api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=dms

Request parameters

Latitude in WGS 84 decimal degrees, -90 to 90 inclusive. Required.

Longitude in WGS 84 decimal degrees, -180 to 180 inclusive; +180 is the same meridian as -180. Required.

Output notation: dd (signed decimal degrees), ddm (degrees + decimal minutes), dms (degrees, minutes, seconds) or iso6709 (an ISO 6709 Annex H string expression in the decimal-degrees form).

Fractional digits on the smallest unit of the chosen notation: degrees for dd and iso6709, minutes for ddm, seconds for dms.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=dms"
const res = await fetch("https://randomapi.dev/api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=dms");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=dms").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=dms"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 4
lat float required

Latitude in WGS 84 decimal degrees, -90 to 90 inclusive. Required.

allowed: -90 – 90
example: lat=57.703417
lng float required

Longitude in WGS 84 decimal degrees, -180 to 180 inclusive; +180 is the same meridian as -180. Required.

allowed: -180 – 180
example: lng=-11.966944
format enum required

Output notation: dd (signed decimal degrees), ddm (degrees + decimal minutes), dms (degrees, minutes, seconds) or iso6709 (an ISO 6709 Annex H string expression in the decimal-degrees form).

allowed: dd | ddm | dms | iso6709
example: format=dms
precision int

Fractional digits on the smallest unit of the chosen notation: degrees for dd and iso6709, minutes for ddm, seconds for dms.

default: 3
allowed: 0 – 8
example: precision=4
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=latitude,longitude
exclude list

Return all fields except these (comma-separated).

example: exclude=carried
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 11
latitude float

Input latitude in WGS 84 decimal degrees, echoed unchanged.

example: 57.703417

longitude float

Input longitude in WGS 84 decimal degrees, echoed unchanged.

example: -11.966944

format string

Requested output notation: dd, ddm, dms or iso6709.

example: dms

precision integer

Fractional digits applied to the smallest unit of the requested notation.

example: 3

latitudeText string

Formatted latitude. dd is signed decimal degrees, ddm and dms carry an N/S letter, iso6709 is a sign plus two-digit degrees.

example: 57°42'12.301"N

longitudeText string

Formatted longitude; longitude degrees are zero-padded to three digits in ddm, dms and iso6709.

example: 011°58'00.998"W

text string

Both coordinates in one string: comma-separated for dd, space-separated for ddm and dms, concatenated and solidus-terminated for iso6709.

example: 57°42'12.301"N 011°58'00.998"W

roundedLatitude float

The exact decimal-degree value latitudeText denotes after rounding — nothing about the rounding is left implicit.

example: 57.703417

roundedLongitude float

The exact decimal-degree value longitudeText denotes after rounding.

example: -11.966944

rounding string

The rounding method, stated rather than left to the reader: always half-away-from-zero.

example: half-away-from-zero

carried boolean

True when rounding pushed seconds or minutes to 60 and the value carried into the next larger unit. Always false for dd and iso6709, which have no sub-degree units.

example: false

Documented examples

Build-generated requests and complete responses
4
Decimal degrees to DMS
GET /api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=dms
{
  "data": {
    "latitude": 57.703417,
    "longitude": -11.966944,
    "format": "dms",
    "precision": 3,
    "latitudeText": "57°42'12.301\"N",
    "longitudeText": "011°58'00.998\"W",
    "text": "57°42'12.301\"N 011°58'00.998\"W",
    "roundedLatitude": 57.703416944,
    "roundedLongitude": -11.966943889,
    "rounding": "half-away-from-zero",
    "carried": false
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/convert",
    "params": {
      "lat": 57.703417,
      "lng": -11.966944,
      "format": "dms",
      "precision": 3
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Decimal degrees to degrees and decimal minutes
GET /api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=ddm
{
  "data": {
    "latitude": 57.703417,
    "longitude": -11.966944,
    "format": "ddm",
    "precision": 3,
    "latitudeText": "57°42.205'N",
    "longitudeText": "011°58.017'W",
    "text": "57°42.205'N 011°58.017'W",
    "roundedLatitude": 57.703416667,
    "roundedLongitude": -11.96695,
    "rounding": "half-away-from-zero",
    "carried": false
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/convert",
    "params": {
      "lat": 57.703417,
      "lng": -11.966944,
      "format": "ddm",
      "precision": 3
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
ISO 6709 string expression
GET /api/coordinate-formats/convert?lat=57.703417&lng=-11.966944&format=iso6709&precision=4
{
  "data": {
    "latitude": 57.703417,
    "longitude": -11.966944,
    "format": "iso6709",
    "precision": 4,
    "latitudeText": "+57.7034",
    "longitudeText": "-011.9669",
    "text": "+57.7034-011.9669/",
    "roundedLatitude": 57.7034,
    "roundedLongitude": -11.9669,
    "rounding": "half-away-from-zero",
    "carried": false
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/convert",
    "params": {
      "lat": 57.703417,
      "lng": -11.966944,
      "format": "iso6709",
      "precision": 4
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Seconds rounding up into the next minute
GET /api/coordinate-formats/convert?lat=12.583333222&lng=0&format=dms&precision=3
{
  "data": {
    "latitude": 12.583333222,
    "longitude": 0,
    "format": "dms",
    "precision": 3,
    "latitudeText": "12°35'00.000\"N",
    "longitudeText": "000°00'00.000\"E",
    "text": "12°35'00.000\"N 000°00'00.000\"E",
    "roundedLatitude": 12.583333333,
    "roundedLongitude": 0,
    "rounding": "half-away-from-zero",
    "carried": true
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/convert",
    "params": {
      "lat": 12.583333222,
      "lng": 0,
      "format": "dms",
      "precision": 3
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}

GET /api/coordinate-formats/maidenhead

Supply lat and lng to encode, or locator to decode. Either way the response describes the squaroid: its centre, its bounds and its size.

Live requestRuns against the public API
No key required
GET/api/coordinate-formats/maidenhead?lat=48.858222&lng=2.2945

Request parameters

Latitude in WGS 84 decimal degrees, -90 to 90 inclusive. Supply together with 'lng' to encode a point; omit both when decoding.

Longitude in WGS 84 decimal degrees, -180 to 180 inclusive; +180 is the same meridian as -180. Supply together with 'lat' to encode a point; omit both when decoding.

Maidenhead locator to decode, in any case. Character pairs run A–R, 0–9, A–X, 0–9, A–X. Mutually exclusive with 'lat'/'lng'.

Locator length when encoding: an even number from 2 to 10, defaulting to 6. When decoding it must be omitted or match the locator's own length.

Advanced response options4 options

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/coordinate-formats/maidenhead?lat=48.858222&lng=2.2945"
const res = await fetch("https://randomapi.dev/api/coordinate-formats/maidenhead?lat=48.858222&lng=2.2945");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/coordinate-formats/maidenhead?lat=48.858222&lng=2.2945").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/coordinate-formats/maidenhead?lat=48.858222&lng=2.2945"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 4
lat float

Latitude in WGS 84 decimal degrees, -90 to 90 inclusive. Supply together with 'lng' to encode a point; omit both when decoding.

allowed: -90 – 90
example: lat=48.858222
lng float

Longitude in WGS 84 decimal degrees, -180 to 180 inclusive; +180 is the same meridian as -180. Supply together with 'lat' to encode a point; omit both when decoding.

allowed: -180 – 180
example: lng=2.2945
locator string

Maidenhead locator to decode, in any case. Character pairs run A–R, 0–9, A–X, 0–9, A–X. Mutually exclusive with 'lat'/'lng'.

allowed: 2 – 10
example: locator=JN18DU
length int

Locator length when encoding: an even number from 2 to 10, defaulting to 6. When decoding it must be omitted or match the locator's own length.

allowed: 2 – 10
example: length=10
Universal parameters Shared response and formatting options 4
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=operation,locator
exclude list

Return all fields except these (comma-separated).

example: exclude=heightDegrees
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 12
operation string

encode when a lat/lng pair was supplied, decode when a locator was supplied.

example: encode

locator string

Canonical locator in this API's mixed-case rendering: uppercase field, digits, lowercase sub-square, digits, lowercase extended sub-square.

example: JN18du

locatorUpperCase string

The same locator in the all-uppercase notation the IARU Region 1 VHF Handbook prescribes. Both strings identify the same squaroid.

example: JN18DU

length integer

Locator length in characters: 2, 4, 6, 8 or 10.

example: 6

latitude float

Latitude of the squaroid's centre, which is the locator's IARU reference location. When encoding this is NOT the point you supplied.

example: 48.854166667

longitude float

Longitude of the squaroid's centre.

example: 2.291666667

south float

Southern edge of the squaroid in decimal degrees. A point exactly on an edge belongs to the square that edge starts, so south is inclusive.

example: 48.833333333

west float

Western edge of the squaroid in decimal degrees, inclusive on the same rule as south.

example: 2.25

north float

Northern edge of the squaroid in decimal degrees, exclusive — except at +90, where the pole is clamped into the top row of squares.

example: 48.875

east float

Eastern edge of the squaroid in decimal degrees, exclusive; +180 is the same meridian as -180 and encodes into the first column.

example: 2.333333333

widthDegrees float

Longitude span of the squaroid in degrees — 1/12, or 5 arcminutes, at six characters.

example: 0.083333333

heightDegrees float

Latitude span of the squaroid in degrees — 1/24, or 2.5 arcminutes, at six characters.

example: 0.041666667

Documented examples

Build-generated requests and complete responses
4
Encode the Eiffel Tower to a six-character locator
GET /api/coordinate-formats/maidenhead?lat=48.858222&lng=2.2945
{
  "data": {
    "operation": "encode",
    "locator": "JN18du",
    "locatorUpperCase": "JN18DU",
    "length": 6,
    "latitude": 48.854166667,
    "longitude": 2.291666667,
    "south": 48.833333333,
    "west": 2.25,
    "north": 48.875,
    "east": 2.333333333,
    "widthDegrees": 0.083333333,
    "heightDegrees": 0.041666667
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/maidenhead",
    "params": {
      "lat": 48.858222,
      "lng": 2.2945,
      "length": 6
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Encode a ten-character precision locator
GET /api/coordinate-formats/maidenhead?lat=48.858222&lng=2.2945&length=10
{
  "data": {
    "operation": "encode",
    "locator": "JN18du55ix",
    "locatorUpperCase": "JN18DU55IX",
    "length": 10,
    "latitude": 48.858246528,
    "longitude": 2.294618056,
    "south": 48.858159722,
    "west": 2.294444444,
    "north": 48.858333333,
    "east": 2.294791667,
    "widthDegrees": 0.000347222,
    "heightDegrees": 0.000173611
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/maidenhead",
    "params": {
      "lat": 48.858222,
      "lng": 2.2945,
      "length": 10
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Decode a six-character locator to its square
GET /api/coordinate-formats/maidenhead?locator=JN18DU
{
  "data": {
    "operation": "decode",
    "locator": "JN18du",
    "locatorUpperCase": "JN18DU",
    "length": 6,
    "latitude": 48.854166667,
    "longitude": 2.291666667,
    "south": 48.833333333,
    "west": 2.25,
    "north": 48.875,
    "east": 2.333333333,
    "widthDegrees": 0.083333333,
    "heightDegrees": 0.041666667
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/maidenhead",
    "params": {
      "locator": "JN18du",
      "length": 6
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}
Decode a four-character HF locator
GET /api/coordinate-formats/maidenhead?locator=IO91
{
  "data": {
    "operation": "decode",
    "locator": "IO91",
    "locatorUpperCase": "IO91",
    "length": 4,
    "latitude": 51.5,
    "longitude": -1,
    "south": 51,
    "west": -2,
    "north": 52,
    "east": 0,
    "widthDegrees": 2,
    "heightDegrees": 1
  },
  "meta": {
    "endpoint": "coordinate-formats",
    "route": "/maidenhead",
    "params": {
      "locator": "IO91",
      "length": 4
    },
    "generatedAt": "2026-07-29T08:13:22.000Z"
  }
}

About this API

Coverage & behavior

The front door to the geo category. Every coordinate-taking endpoint here — geodesy, coordinates, cities/nearest, airports/nearby — wants clean decimal degrees, while real input looks like 57°42'12.3"N, 011°58'01"W, N57 42.205 W011 58.017, +57.7034-011.9669/ or a spreadsheet cell with a comma decimal separator.

  • /parse reads degrees/minutes/seconds, degrees and decimal minutes, plain decimal degrees and ISO 6709 Annex H string expressions, folding Unicode prime marks (′ ″), smart quotes, '', the Unicode minus sign and non-breaking spaces to their ASCII equivalents first. Spaces, colons and slashes separate the parts of one coordinate; a comma or semicolon separates the two coordinates, and it is honoured as the split rather than treated as decoration — 51 30, 0 7 is 51°30' / 0°07' and 51 30 0, 7 is 51°30'00" / 7°, where the same numbers without a separator are refused as ambiguous. It reports the notation and axis order it detected, where each hemisphere came from, and how many fractional digits the input carried.
  • /convert renders a point as dd, ddm, dms or iso6709. Rounding is half away from zero at the requested precision and the sexagesimal carry is handled: 12°34'59.9996" at three decimals becomes 12°35'00.000", never 12°34'60.000". The response also returns the exact decimal degrees the formatted text denotes, so nothing about the rounding is left implicit.
  • /maidenhead encodes a point to an IARU locator or decodes one, alternating base 18 / 10 / 24 / 10 / 24 across lengths 2 to 10.

Ambiguous input is rejected, never guessed

A silently swapped coordinate is the failure that ruins a dataset, so /parse answers 400 with a named reason instead of picking a favourite reading:

reason example
ambiguous-axis-order 51.5074, -0.1278 — no letters and both values within ±90; add order=latlng or order=lnglat
ambiguous-degree-grouping 51 30 0 7 — 51° / 30°00'07", or 51°30' / 0°07', or 51°30'00" / 7°. The message lists your competing readings, not a canned example
ambiguous-comma-role 51,5 30 — is that comma a decimal separator or the coordinate separator?
sign-with-hemisphere-letter -011°58'01"W — applying both the sign and the letter double-negates, so a +/- anywhere in text that also carries an N/S/E/W letter is refused. That includes a hyphen used as a separator (57 42 N - 011 58 W) and a half-converted Annex H string (N57.7034+011.9669/)
value-out-of-range 95°N, or 57°42'75"

One thing is not rejected: a pair with a letter on only one axis, such as 57 11W. The letter fixes both axes, so the point is unambiguous — but the axis without a letter had its hemisphere assumed, so hemisphereSource reports mixed and a warning names the axis and the hemisphere that was used.

Scope limits, stated plainly

  • Not a geocoder. No place names, addresses, postcodes or reverse lookup — this converts coordinate notation only.
  • No datum transformation. Everything in and out is treated as WGS 84 decimal degrees. NAD27, OSGB36, ED50 and other datums are out of scope: silently reading their numbers as WGS 84 would move a point by hundreds of metres.
  • A Maidenhead locator is a square, not a point. The IARU defines its reference location as the centroid of the squaroid, so latitude/longitude are the centre and south/west/north/east are returned alongside them. Locators are accepted in any case; the canonical locator is normalized to the conventional mixed-case rendering (uppercase field, lowercase sub-square), and locatorUpperCase uses the all-uppercase notation the IARU Region 1 VHF Handbook prescribes. Both strings denote the same squaroid.
  • Geohash lives next door. Geohash encoding and decoding belong to the geohash endpoint; this one does not duplicate that algorithm.

Use it for

  • Normalize pasted survey, aviation or EXIF coordinate strings into WGS 84 decimal degrees before storing them
  • Render stored decimal degrees as DMS, DDM or ISO 6709 text for a report, flight plan or map label
  • Turn an amateur-radio Maidenhead grid locator into a square with a centre and bounds for mapping
  • Fail a spreadsheet import loudly on an ambiguous coordinate column instead of silently swapping latitude and longitude

Frequently asked questions

How do I convert DMS to decimal degrees with an API?

Call /parse?value=57°42'12.3"N, 011°58'01"W and read latitude and longitude. /convert goes the other way, turning decimal degrees back into dms, ddm or iso6709 text.

Why does 51.5074, -0.1278 return a 400 error?

Because it is genuinely ambiguous: with no N/S/E/W letters and both values inside ±90 it could be latitude/longitude or longitude/latitude. Add order=latlng or order=lnglat — the API never guesses which axis you meant.

Does this API convert between datums such as NAD27 or OSGB36?

No. Every value is treated as WGS 84 decimal degrees and no datum transformation is performed. Reading NAD27 or OSGB36 numbers as WGS 84 would move the point by hundreds of metres, so those datums are deliberately out of scope.

Is a Maidenhead grid locator a point or an area?

An area. /maidenhead returns the squaroid's centre — the IARU reference location — plus its south, west, north and east bounds and its size in degrees. A six-character locator covers 5′ of longitude by 2.5′ of latitude.

What happens when seconds round up to 60?

/convert rounds half away from zero and then carries, so 12°34'59.9996" at three decimals becomes 12°35'00.000" rather than 12°34'60.000". The response sets carried to true whenever that happens.

Can I look up coordinates from a place name or address?

No. This is a notation parser, not a geocoder: it converts coordinate text between formats and never resolves place names, addresses or postcodes.

Standards & references