Skip to main content

Country Land Borders & Neighbours API

REAL DATA

Land neighbours for all 250 countries and territories, published border lengths in km, the 45 landlocked entries and shortest land-border paths.

Authoritative reference data or standards computation

Base URL
/api/country-borders
Capabilities
4 routes
Last updated
July 30, 2026
Data sources · 3

GET /api/country-borders

All 250 entries, English alphabetical order by name unless 'sort' says otherwise — the same alphabet as /api/countries, so accented names sort under their base letter ('Åland Islands' is second, not last). Land borders only — maritime neighbours are never listed. Filters compose; 'count' is capped at 100 by the platform, so use 'offset' to page through the whole table.

Live requestRuns against the public API
No key required
GET/api/country-borders?region=europe&count=60

Request parameters

Only return entries in this lowercase geographic region (africa 60, americas 57, asia 51, europe 52, oceania 29, antarctic 1).

Case- and diacritic-insensitive substring match against the English name (aland finds Åland Islands).

Restrict to the 45 landlocked entries (true) — 44 officially assigned ISO codes plus XK — or the 205 that are not (false).

Restrict to entries whose every land neighbour is itself landlocked (true) — exactly LI and UZ — or exclude them (false).

Return the land neighbours of this country as full records. Accepts alpha-2 or alpha-3 (XK/XKX included), case-insensitively.

Only return entries with at least this many land neighbours.

Only return entries with at most this many land neighbours. 0 isolates the 87 entries that have none.

name is ascending in English alphabetical order (locale-aware, so 'Åland Islands' sorts under A and 'Türkiye' between 'Tunisia' and 'Turkmenistan'); neighbours and borderLength are descending. All three break ties on code ascending, and entries whose totalBorderLengthKm is null sort last under borderLength.

Skip this many rows, applied after filtering and sorting. Use it with count to page.

Advanced response options6 options

Limit the number of returned records (1–100). Defaults to 50.

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

Return all fields except these (comma-separated).

Response format: json envelope, ndjson (one record per line) or csv.

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/country-borders?region=europe&count=60"
const res = await fetch("https://randomapi.dev/api/country-borders?region=europe&count=60");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/country-borders?region=europe&count=60").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/country-borders?region=europe&count=60"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 9
region enum

Only return entries in this lowercase geographic region (africa 60, americas 57, asia 51, europe 52, oceania 29, antarctic 1).

allowed: africa | americas | asia | europe | oceania | antarctic
example: region=europe
search string

Case- and diacritic-insensitive substring match against the English name (aland finds Åland Islands).

allowed: 1 – 100
example: search=germany
landlocked boolean

Restrict to the 45 landlocked entries (true) — 44 officially assigned ISO codes plus XK — or the 205 that are not (false).

example: landlocked=true
doublyLandlocked boolean

Restrict to entries whose every land neighbour is itself landlocked (true) — exactly LI and UZ — or exclude them (false).

example: doublyLandlocked=true
neighbourOf string

Return the land neighbours of this country as full records. Accepts alpha-2 or alpha-3 (XK/XKX included), case-insensitively.

example: neighbourOf=DE
minNeighbours int

Only return entries with at least this many land neighbours.

allowed: 0 – 14
example: minNeighbours=5
maxNeighbours int

Only return entries with at most this many land neighbours. 0 isolates the 87 entries that have none.

allowed: 0 – 14
example: maxNeighbours=0
sort enum

name is ascending in English alphabetical order (locale-aware, so 'Åland Islands' sorts under A and 'Türkiye' between 'Tunisia' and 'Turkmenistan'); neighbours and borderLength are descending. All three break ties on code ascending, and entries whose totalBorderLengthKm is null sort last under borderLength.

default: name
allowed: name | neighbours | borderLength
example: sort=neighbours
offset int

Skip this many rows, applied after filtering and sorting. Use it with count to page.

default: 0
allowed: 0 – 249
example: offset=50
Universal parameters Shared response and formatting options 6
count int

Limit the number of returned records (1–100). Defaults to 50.

default: 50
allowed: 1 – 100
example: count=3
fields list

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

example: fields=code,name
exclude list

Return all fields except these (comma-separated).

example: exclude=notes
format enum

Response format: json envelope, ndjson (one record per line) or csv.

default: json
allowed: json | ndjson | csv
example: format=csv
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
code string

ISO 3166-1 alpha-2 code, or XK — the one user-assigned code carried here.

example: DE

name string

English name, joined from this project's ISO 3166-1 country dataset.

example: Germany

region string

Lowercase geographic region: africa, americas, asia, europe, oceania or antarctic.

example: europe

neighbours string[]

Alpha-2 codes of every country sharing a LAND border, alphabetically sorted. Maritime neighbours are never included, so FR-GB, US-RU and JP-KR are absent by design. Empty for the 87 entries with no land neighbour.

example: ["AT","BE","CH","CZ","DK","FR","LU","NL","PL"]

neighbourCount integer

Number of land neighbours, 0–14 (CN and RU share the maximum).

example: 9

totalBorderLengthKm float nullable

Sum of the published lengths of the neighbours listed here, excluding any neighbour with no published figure; null when no neighbour has one. This is our sum, not the upstream's own published total: the two differ for 15 entries, and for 1 more (GF) the upstream publishes no total at all. All 16 are explained in notes.

example: 3694

unknownLengthNeighbours string[]

Codes in neighbours for which no border length is published. Empty for 246 of the 250 entries: the only adjacencies without a published figure are AL-RS and CU-US — AL and RS because each country's entry publishes its Kosovo boundary instead, CU and US because the only published segment there is a base perimeter with no ISO code.

example: []

coastlineKm float nullable

Published coastline length. Null for the 12 entries where the upstream has no separate record (AX, BQ, GF, GP, MQ, RE, YT), publishes a per-island breakdown or the literal NA instead of one figure (GS, SH, TF, UM), or publishes no Coastline field at all (BL). Never inferred and never coerced from a non-numeric value.

example: 2389

landlocked boolean

True when the upstream explicitly annotates the coastline as (landlocked) or (doubly landlocked). Never derived from a numeric zero and never from a missing value.

example: false

doublyLandlocked boolean

Landlocked and every land neighbour is itself landlocked. True for exactly LI and UZ.

example: false

isoStatus string

officially-assigned for the 249 ISO 3166-1 entries, user-assigned for XK only. Filter on this to drop XK in one line.

example: officially-assigned

notes string[]

Hand-authored caveats naming the upstream responsible where the two sources disagree, or where an ISO entity does not line up with an upstream entity. Empty for 210 of the 250 entries.

example: []

Documented examples

Build-generated requests and complete responses
5
Every European country and its neighbours
GET /api/country-borders?region=europe&count=60
{
  "data": [
    {
      "code": "AX",
      "name": "Åland Islands",
      "region": "europe",
      "neighbours": [],
      "neighbourCount": 0,
      "totalBorderLengthKm": null,
      "unknownLengthNeighbours": [],
      "coastlineKm": null,
      "landlocked": false,
      "doublyLandlocked": false,
      "isoStatus": "officially-assigned",
      "notes": [
        "The border-length upstream publishes no separate Åland Islands record, so `coastlineKm` is null rather than 0. Åland is not landlocked."
      ]
    },
    {
      "code": "AL",
      "name": "Albania",
      "region": "europe",
      "neighbours": [
        "GR",
        "ME",
        "MK",
        "RS",
        "XK"
      ],
      "neighbourCount": 5,
      "totalBorderLengthKm": 691,
      "unknownLengthNeighbours": [
        "RS"
      ],
      "coastlineKm": 362,
      "landlocked": false,
      "doublyLandlocked": false,
      "isoStatus": "officially-assigned",
      "notes": [
        "GeoNames gives `AL` and `RS` a shared land border, but neither country's entry in the border-length upstream publishes an Albania-Serbia segment (each publishes its Kosovo boundary instead), so `borderLengthKm` is null and the code appears in `unknownLengthNeighbours`.""generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Countries with no land neighbours
GET /api/country-borders?maxNeighbours=0&count=100
{
  "data": [
    {
      "code": "AX",
      "name": "Åland Islands",
      "region": "europe",
      "neighbours": [],
      "neighbourCount": 0,
      "totalBorderLengthKm": null,
      "unknownLengthNeighbours": [],
      "coastlineKm": null,
      "landlocked": false,
      "doublyLandlocked": false,
      "isoStatus": "officially-assigned",
      "notes": [
        "The border-length upstream publishes no separate Åland Islands record, so `coastlineKm` is null rather than 0. Åland is not landlocked."
      ]
    },
    {
      "code": "AS",
      "name": "American Samoa",
      "region": "oceania",
      "neighbours": [],
      "neighbourCount": 0,
      "totalBorderLengthKm": null,
      "unknownLengthNeighbours": [],
      "coastlineKm": 116,
      "landlocked": false,
      "doublyLandlocked": false,
      "isoStatus": "officially-assigned",
      "notes": []
    },
    {
      "code": "AI",
      "name": "Anguilla",
      "region": "americas",
      "neighbours": [],
      "neighbourCount": 0,
      "totalBorderLengthKm": null,
      "unknownLengthNeighbours": [],
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The most-bordered countries first
GET /api/country-borders?sort=neighbours&count=10
{
  "data": [
    {
      "code": "CN",
      "name": "China",
      "region": "asia",
      "neighbours": [
        "AF",
        "BT",
        "IN",
        "KG",
        "KP",
        "KZ",
        "LA",
        "MM",
        "MN",
        "NP",
        "PK",
        "RU",
        "TJ",
        "VN"
      ],
      "neighbourCount": 14,
      "totalBorderLengthKm": 22421,
      "unknownLengthNeighbours": [],
      "coastlineKm": 14500,
      "landlocked": false,
      "doublyLandlocked": false,
      "isoStatus": "officially-assigned",
      "notes": [
        "The border-length upstream publishes this row's Russia boundary as two segments (northeast 4,133 km and northwest 46 km), summed here to 4,179 km. Its own published total (22,457 km) is 36 km above the sum of its own listed segments (22,421 km), which is the figure this row reports."
      ]
    },
    {
      "code": "RU",
      "name": "Russia",
      "region": "europe",
      "neighbours": [
        "AZ",
        "BY",
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Germany's nine land neighbours as full records
GET /api/country-borders?neighbourOf=DE
{
  "data": [
    {
      "code": "AT",
      "name": "Austria",
      "region": "europe",
      "neighbours": [
        "CH",
        "CZ",
        "DE",
        "HU",
        "IT",
        "LI",
        "SI",
        "SK"
      ],
      "neighbourCount": 8,
      "totalBorderLengthKm": 2524,
      "unknownLengthNeighbours": [],
      "coastlineKm": 0,
      "landlocked": true,
      "doublyLandlocked": false,
      "isoStatus": "officially-assigned",
      "notes": []
    },
    {
      "code": "BE",
      "name": "Belgium",
      "region": "europe",
      "neighbours": [
        "DE",
        "FR",
        "LU",
        "NL"
      ],
      "neighbourCount": 4,
      "totalBorderLengthKm": 1297,
      "unknownLengthNeighbours": [],
      "coastlineKm": 66.5,
      "landlocked": false,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The second page of the full table
GET /api/country-borders?offset=100&count=100&fields=code,name,neighbourCount
{
  "data": [
    {
      "code": "HU",
      "name": "Hungary",
      "neighbourCount": 7
    },
    {
      "code": "IS",
      "name": "Iceland",
      "neighbourCount": 0
    },
    {
      "code": "IN",
      "name": "India",
      "neighbourCount": 6
    },
    {
      "code": "ID",
      "name": "Indonesia",
      "neighbourCount": 3
    },
    {
      "code": "IR",
      "name": "Iran",
      "neighbourCount": 7
    },
    {
      "code": "IQ",
      "name": "Iraq",
      "neighbourCount": 6
    },
    {
      "code": "IE",
      "name": "Ireland",
      "neighbourCount": 1
    },
    {
      "code": "IM",
      "name": "Isle of Man",
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

GET /api/country-borders/lookup

Accepts alpha-2 or alpha-3 (XK and XKX included), case-insensitively. Each neighbour carries its own published border length, plus the other side's figure when the two upstream entries disagree. A well-formed unknown code is a 404, never a substitute country.

Live requestRuns against the public API
No key required
GET/api/country-borders/lookup?code=DE

Request parameters

ISO 3166-1 alpha-2 or alpha-3 code, case-insensitive (DE or DEU). XK and XKX are accepted.

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/country-borders/lookup?code=DE"
const res = await fetch("https://randomapi.dev/api/country-borders/lookup?code=DE");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/country-borders/lookup?code=DE").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/country-borders/lookup?code=DE"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 1
code string required

ISO 3166-1 alpha-2 or alpha-3 code, case-insensitive (DE or DEU). XK and XKX are accepted.

example: code=DE
Universal parameters Shared response and formatting options 4
fields list

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

example: fields=code,name
exclude list

Return all fields except these (comma-separated).

example: exclude=notes
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
code string

ISO 3166-1 alpha-2 code, or XK — the one user-assigned code carried here.

example: DE

name string

English name, joined from this project's ISO 3166-1 country dataset.

example: Germany

region string

Lowercase geographic region: africa, americas, asia, europe, oceania or antarctic.

example: europe

isoStatus string

officially-assigned for the 249 ISO 3166-1 entries, user-assigned for XK only. Filter on this to drop XK in one line.

example: officially-assigned

neighbourCount integer

Number of land neighbours in the neighbours array.

example: 9

neighbours object[]

One entry per LAND neighbour, alphabetical by code. Keys: code, name, borderLengthKm (float|null), borderLengthKmAlternate (float|null — the other side's published figure where the two upstream entries disagree; non-null for the 3 pairs DE-PL, IL-JO, MX-US only) and isoStatus.

example: [{"code":"AT","name":"Austria","borderLengthKm":801,"borderLengthKmAlternate":null,"isoStatus":"officially-assigned"}]

totalBorderLengthKm float nullable

Sum of the published lengths of the neighbours listed here, excluding any neighbour with no published figure; null when no neighbour has one. This is our sum, not the upstream's own published total: the two differ for 15 entries, and for 1 more (GF) the upstream publishes no total at all. All 16 are explained in notes.

example: 3694

unknownLengthNeighbours string[]

Codes in neighbours for which no border length is published. Empty for 246 of the 250 entries: the only adjacencies without a published figure are AL-RS and CU-US — AL and RS because each country's entry publishes its Kosovo boundary instead, CU and US because the only published segment there is a base perimeter with no ISO code.

example: []

coastlineKm float nullable

Published coastline length. Null for the 12 entries where the upstream has no separate record (AX, BQ, GF, GP, MQ, RE, YT), publishes a per-island breakdown or the literal NA instead of one figure (GS, SH, TF, UM), or publishes no Coastline field at all (BL). Never inferred and never coerced from a non-numeric value.

example: 2389

landlocked boolean

True when the upstream explicitly annotates the coastline as (landlocked) or (doubly landlocked). Never derived from a numeric zero and never from a missing value.

example: false

doublyLandlocked boolean

Landlocked and every land neighbour is itself landlocked. True for exactly LI and UZ.

example: false

notes string[]

Hand-authored caveats naming the upstream responsible where the two sources disagree, or where an ISO entity does not line up with an upstream entity. Empty for 210 of the 250 entries.

example: []

Documented examples

Build-generated requests and complete responses
4
Germany and its nine neighbours
GET /api/country-borders/lookup?code=DE
{
  "data": {
    "code": "DE",
    "name": "Germany",
    "region": "europe",
    "isoStatus": "officially-assigned",
    "neighbourCount": 9,
    "neighbours": [
      {
        "code": "AT",
        "name": "Austria",
        "borderLengthKm": 801,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "BE",
        "name": "Belgium",
        "borderLengthKm": 133,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "CH",
        "name": "Switzerland",
        "borderLengthKm": 348,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "CZ",
        "name": "Czechia",
        "borderLengthKm": 704,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "DK",
        "name": "Denmark",
        "borderLengthKm": 140,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Denmark by alpha-3, showing the Hans Island note
GET /api/country-borders/lookup?code=DNK
{
  "data": {
    "code": "DK",
    "name": "Denmark",
    "region": "europe",
    "isoStatus": "officially-assigned",
    "neighbourCount": 1,
    "neighbours": [
      {
        "code": "DE",
        "name": "Germany",
        "borderLengthKm": 140,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      }
    ],
    "totalBorderLengthKm": 140,
    "unknownLengthNeighbours": [],
    "coastlineKm": 7314,
    "landlocked": false,
    "doublyLandlocked": false,
    "notes": [
      "The border-length upstream also publishes a 1.3 km Denmark-Canada boundary on Hans Island, divided by the 2022 agreement. GeoNames records no `DK`-`CA` adjacency, so it is not in this graph; with the published total also rounded, this row reports 140 km against a published 141 km."
    ]
  },
  "meta": {
    "endpoint": "country-borders",
    "route": "/lookup",
    "params": {
      "code": "DNK"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Uzbekistan — one of two doubly landlocked countries
GET /api/country-borders/lookup?code=UZ
{
  "data": {
    "code": "UZ",
    "name": "Uzbekistan",
    "region": "asia",
    "isoStatus": "officially-assigned",
    "neighbourCount": 5,
    "neighbours": [
      {
        "code": "AF",
        "name": "Afghanistan",
        "borderLengthKm": 144,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "KG",
        "name": "Kyrgyzstan",
        "borderLengthKm": 1314,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "KZ",
        "name": "Kazakhstan",
        "borderLengthKm": 2330,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "TJ",
        "name": "Tajikistan",
        "borderLengthKm": 1312,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "TM",
        "name": "Turkmenistan",
        "borderLengthKm": 1793,
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Just Serbia's neighbour list
GET /api/country-borders/lookup?code=RS&fields=code,neighbours,unknownLengthNeighbours
{
  "data": {
    "code": "RS",
    "neighbours": [
      {
        "code": "AL",
        "name": "Albania",
        "borderLengthKm": null,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "BA",
        "name": "Bosnia and Herzegovina",
        "borderLengthKm": 345,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "BG",
        "name": "Bulgaria",
        "borderLengthKm": 344,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "HR",
        "name": "Croatia",
        "borderLengthKm": 314,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
        "code": "HU",
        "name": "Hungary",
        "borderLengthKm": 164,
        "borderLengthKmAlternate": null,
        "isoStatus": "officially-assigned"
      },
      {
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

GET /api/country-borders/path

Graph distance over the land-adjacency graph — nothing about roads, ferries, crossing points, open borders or visas, and deliberately no distance or duration field (use /api/geodesy for that). Both codes must exist in this dataset; a bad or unknown code is a 400, because 404 is reserved for the lookup route's key.

Live requestRuns against the public API
No key required
GET/api/country-borders/path?from=PT&to=PL

Request parameters

Origin country, alpha-2 or alpha-3, case-insensitive.

Destination country, alpha-2 or alpha-3, case-insensitive.

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/country-borders/path?from=PT&to=PL"
const res = await fetch("https://randomapi.dev/api/country-borders/path?from=PT&to=PL");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/country-borders/path?from=PT&to=PL").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/country-borders/path?from=PT&to=PL"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 2
from string required

Origin country, alpha-2 or alpha-3, case-insensitive.

example: from=PT
to string required

Destination country, alpha-2 or alpha-3, case-insensitive.

example: to=PL
Universal parameters Shared response and formatting options 4
fields list

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

example: fields=from,to
exclude list

Return all fields except these (comma-separated).

example: exclude=unreachableReason
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 7
from string

Canonical alpha-2 code of the origin.

example: PT

to string

Canonical alpha-2 code of the destination.

example: PL

reachable boolean

Whether a chain of land borders connects the two entries at all.

example: true

hops integer nullable

Border crossings, i.e. path.length - 1. 0 when from equals to; null when unreachable.

example: 4

path string[]

Alpha-2 codes from origin to destination inclusive, empty when unreachable. Deterministic: several chains can be equally short, and the one returned is always the same.

example: ["PT","ES","FR","DE","PL"]

crossings object[]

One entry per crossing (path.length - 1 of them), keys from, to and borderLengthKm (float|null). Empty when unreachable or when from equals to.

example: [{"from":"PT","to":"ES","borderLengthKm":1224}]

unreachableReason string nullable

Null when reachable, otherwise exactly one of origin-has-no-land-neighbours, destination-has-no-land-neighbours or separate-land-masses. The origin is checked first, so this value names which side is isolated and is therefore direction-sensitive; reachable, hops and path are not.

example: null

Documented examples

Build-generated requests and complete responses
4
Portugal to Poland — four crossings
GET /api/country-borders/path?from=PT&to=PL
{
  "data": {
    "from": "PT",
    "to": "PL",
    "reachable": true,
    "hops": 4,
    "path": [
      "PT",
      "ES",
      "FR",
      "DE",
      "PL"
    ],
    "crossings": [
      {
        "from": "PT",
        "to": "ES",
        "borderLengthKm": 1224
      },
      {
        "from": "ES",
        "to": "FR",
        "borderLengthKm": 646
      },
      {
        "from": "FR",
        "to": "DE",
        "borderLengthKm": 418
      },
      {
        "from": "DE",
        "to": "PL",
        "borderLengthKm": 447
      }
    ],
    "unreachableReason": null
  },
  "meta": {
    "endpoint": "country-borders",
    "route": "/path",
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Spain to Singapore — no land route exists
GET /api/country-borders/path?from=ES&to=SG
{
  "data": {
    "from": "ES",
    "to": "SG",
    "reachable": false,
    "hops": null,
    "path": [],
    "crossings": [],
    "unreachableReason": "destination-has-no-land-neighbours"
  },
  "meta": {
    "endpoint": "country-borders",
    "route": "/path",
    "params": {
      "from": "ES",
      "to": "SG"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Lesotho to Papua New Guinea — the longest chain in the graph
GET /api/country-borders/path?from=LS&to=PG
{
  "data": {
    "from": "LS",
    "to": "PG",
    "reachable": true,
    "hops": 18,
    "path": [
      "LS",
      "ZA",
      "MZ",
      "TZ",
      "CD",
      "CF",
      "SD",
      "EG",
      "IL",
      "JO",
      "IQ",
      "IR",
      "AF",
      "CN",
      "LA",
      "TH",
      "MY",
      "ID",
      "PG"
    ],
    "crossings": [
      {
        "from": "LS",
        "to": "ZA",
        "borderLengthKm": 1106
      },
      {
        "from": "ZA",
        "to": "MZ",
        "borderLengthKm": 496
      },
      {
        "from": "MZ",
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The United Kingdom is on its own land mass
GET /api/country-borders/path?from=GB&to=FR
{
  "data": {
    "from": "GB",
    "to": "FR",
    "reachable": false,
    "hops": null,
    "path": [],
    "crossings": [],
    "unreachableReason": "separate-land-masses"
  },
  "meta": {
    "endpoint": "country-borders",
    "route": "/path",
    "params": {
      "from": "GB",
      "to": "FR"
    },
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

GET /api/country-borders/landlocked

The 45 entries the upstream explicitly annotates as landlocked, with the neighbours the classification rests on. Not a duplicate of '?landlocked=true' on the root route: this one carries landlockedNeighbours and hopsToCoast.

Live requestRuns against the public API
No key required
GET/api/country-borders/landlocked

Request parameters

Restrict to the doubly landlocked entries — every land neighbour landlocked too (LI and UZ).

Only return landlocked entries in this region (africa 16, americas 2, asia 12, europe 15, oceania 0, antarctic 0).

Advanced response options6 options

Limit the number of returned records (1–100). Defaults to all matches.

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

Return all fields except these (comma-separated).

Response format: json envelope, ndjson (one record per line) or csv.

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/country-borders/landlocked"
const res = await fetch("https://randomapi.dev/api/country-borders/landlocked");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/country-borders/landlocked").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/country-borders/landlocked"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 2
doubly boolean

Restrict to the doubly landlocked entries — every land neighbour landlocked too (LI and UZ).

default: false
example: doubly=true
region enum

Only return landlocked entries in this region (africa 16, americas 2, asia 12, europe 15, oceania 0, antarctic 0).

allowed: africa | americas | asia | europe | oceania | antarctic
example: region=africa
Universal parameters Shared response and formatting options 6
count int

Limit the number of returned records (1–100). Defaults to all matches.

default: all matches
allowed: 1 – 100
example: count=3
fields list

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

example: fields=code,name
exclude list

Return all fields except these (comma-separated).

example: exclude=hopsToCoast
format enum

Response format: json envelope, ndjson (one record per line) or csv.

default: json
allowed: json | ndjson | csv
example: format=csv
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 9
code string

ISO 3166-1 alpha-2 code, or XK — the one user-assigned code carried here.

example: UZ

name string

English name, joined from this project's ISO 3166-1 country dataset.

example: Uzbekistan

region string

Lowercase geographic region: africa, americas, asia, europe, oceania or antarctic.

example: asia

isoStatus string

officially-assigned for the 249 ISO 3166-1 entries, user-assigned for XK only. Filter on this to drop XK in one line.

example: officially-assigned

coastlineKm float

Always 0 on this route — the published figure the classification rests on.

example: 0

doublyLandlocked boolean

Landlocked and every land neighbour is itself landlocked. True for exactly LI and UZ.

example: true

neighbours string[]

Alpha-2 codes of every country sharing a land border, alphabetically sorted.

example: ["AF","KG","KZ","TJ","TM"]

landlockedNeighbours string[]

Subset of neighbours that are themselves landlocked. Equal to neighbours exactly when doublyLandlocked is true.

example: ["AF","KG","KZ","TJ","TM"]

hopsToCoast integer

Fewest border crossings from here to a country with a published coastline above zero. 1 for 43 of the entries, 2 for LI and UZ.

example: 2

Documented examples

Build-generated requests and complete responses
3
All landlocked countries
GET /api/country-borders/landlocked
{
  "data": [
    {
      "code": "AD",
      "name": "Andorra",
      "region": "europe",
      "isoStatus": "officially-assigned",
      "coastlineKm": 0,
      "doublyLandlocked": false,
      "neighbours": [
        "ES",
        "FR"
      ],
      "landlockedNeighbours": [],
      "hopsToCoast": 1
    },
    {
      "code": "AF",
      "name": "Afghanistan",
      "region": "asia",
      "isoStatus": "officially-assigned",
      "coastlineKm": 0,
      "doublyLandlocked": false,
      "neighbours": [
        "CN",
        "IR",
        "PK",
        "TJ",
        "TM",
        "UZ"
      ],
      "landlockedNeighbours": [
        "TJ",
        "TM",
        "UZ"
      ],
      "hopsToCoast": 1
    },
    {
      "code": "AM",
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
The two doubly landlocked countries
GET /api/country-borders/landlocked?doubly=true
{
  "data": [
    {
      "code": "LI",
      "name": "Liechtenstein",
      "region": "europe",
      "isoStatus": "officially-assigned",
      "coastlineKm": 0,
      "doublyLandlocked": true,
      "neighbours": [
        "AT",
        "CH"
      ],
      "landlockedNeighbours": [
        "AT",
        "CH"
      ],
      "hopsToCoast": 2
    },
    {
      "code": "UZ",
      "name": "Uzbekistan",
      "region": "asia",
      "isoStatus": "officially-assigned",
      "coastlineKm": 0,
      "doublyLandlocked": true,
      "neighbours": [
        "AF",
        "KG",
        "KZ",
        "TJ",
        "TM"
      ],
      "landlockedNeighbours": [
        "AF",
        "KG",
        "KZ",
        "TJ",
        "TM"
      ],
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}
Landlocked countries in Africa
GET /api/country-borders/landlocked?region=africa
{
  "data": [
    {
      "code": "BF",
      "name": "Burkina Faso",
      "region": "africa",
      "isoStatus": "officially-assigned",
      "coastlineKm": 0,
      "doublyLandlocked": false,
      "neighbours": [
        "BJ",
        "CI",
        "GH",
        "ML",
        "NE",
        "TG"
      ],
      "landlockedNeighbours": [
        "ML",
        "NE"
      ],
      "hopsToCoast": 1
    },
    {
      "code": "BI",
      "name": "Burundi",
      "region": "africa",
      "isoStatus": "officially-assigned",
      "coastlineKm": 0,
      "doublyLandlocked": false,
      "neighbours": [
        "CD",
        "RW",
        "TZ"
      ],
      "landlockedNeighbours": [
        "RW"
      ],
      "hopsToCoast": 1
    },
    …
    "generatedAt": "2026-07-30T15:14:08.000Z"
  }
}

About this API

Coverage & behavior

Land borders only. Every one of the 250 entries here — the 249 officially assigned ISO 3166-1 codes plus the user-assigned XK — carries the alpha-2 codes of the countries it shares a land boundary with, the published length of each of those boundaries in kilometres, its published coastline and whether it is landlocked. Maritime neighbours are absent by design: there is no FRGB, USRU, JPKR or EGSA anywhere in this dataset, and 87 of the 250 entries have no land neighbour at all.

Where the numbers come from. Adjacency is the neighbours column of the GeoNames countryInfo.txt dump (CC BY 4.0). Border and coastline lengths are the CIA World Factbook's own published figures, read from its Geography section through the pinned factbook.json mirror. That publication ended in February 2026, so these lengths are frozen at its final edition and will never be updated — and we do not measure geometry ourselves. Names, regions and alpha-3 codes are joined from this project's countries dataset.

Reconciled, never merged. Two sources means disagreements, and each one is written down rather than smoothed over:

  • 321 of the 323 adjacent pairs have a published length. The other 2 — ALRS and CUUS — appear in unknownLengthNeighbours with borderLengthKm: null.
  • 3 pairs (DEPL, ILJO, MXUS) are published differently by the two countries' own entries. We publish the lower figure symmetrically and return the other as borderLengthKmAlternate on the lookup route.
  • 3 published boundaries are not GeoNames adjacencies (BWZM at Kazungula, CADK on Hans Island, MAMR). Adjacency reproduces GeoNames, so they are not in the graph — they are disclosed in the notes of both countries instead.
  • For 15 entries our sum differs from the upstream's own published total (France's includes its overseas departments, China's total exceeds the sum of its own segments, and so on), and for 1 more (GF) the upstream publishes no total at all, so there is nothing to differ from. Every one of the 16 says why in notes.

Filters that genuinely filter. region, search, landlocked, doublyLandlocked, minNeighbours/maxNeighbours and neighbourOf all compose; the default sort=name is English alphabetical order — collated, not UTF-16 code units, so it is the same alphabet as countries and Åland Islands sorts under A — while sort=neighbours and sort=borderLength are descending, all three breaking ties on code ascending with null totals last; and because count is capped at 100 by the platform, offset pages through the full 250-row table.

/path is graph distance, not travel. It answers "how few land borders must I cross", over this adjacency graph and nothing else — no roads, no ferries, no crossing points, no open/closed status, no visas. There is deliberately no distance or duration field: summing border lengths along a chain of countries produces a number that looks like a distance and is not one. For real spherical distance between two points, use geodesy.

Landlocked means annotated landlocked. The flag comes from the upstream's explicit (landlocked) annotation, never from a parsed zero — five coastline values are non-numeric or absent and a naive parse would turn South Georgia, Saint Helena, the French Southern Territories, the US Minor Outlying Islands and Saint Barthélemy into landlocked islands. 45 entries are landlocked, 2 of them doubly (LI and UZ), and the /landlocked route shows the evidence each classification rests on.

Disputed and unusual entries. XK is carried as a 250th row because GeoNames publishes it and gives it as a neighbour of AL, ME, MK and RS; dropping it would silently delete four real land borders. countries excludes it because ISO 3166-1 does not officially assign it, and isoStatus exists so you can filter it out in one line. PS spans two upstream entities (Gaza Strip and West Bank), EH is its own row, and CY's only land boundaries are with two entities that have no ISO code at all. Each of these carries a notes string naming the upstream responsible.

Codes and names are reproduced exactly as published by the source cited on this page; randomapi.dev takes no position on the sovereignty or territorial status of any country, territory or subdivision, and the presence, absence or nesting of any entry implies none.

Use it for

  • Show a country's land neighbours in a travel or logistics UI without paying for a borders API
  • Build a country-adjacency graph for a quiz, map colouring or Risk-style game
  • Filter a country picker down to landlocked or doubly landlocked states
  • Answer 'how many land borders apart are these two countries' with a deterministic shortest chain
  • Sanity-check a geo dataset against published border lengths and coastlines with the disagreements spelled out

Frequently asked questions

Why does this API say France and the United Kingdom are not neighbours?

Because it publishes land borders only. Maritime neighbours are absent by design — FRGB, USRU and JPKR all have no shared land boundary — and 87 of the 250 entries have no land neighbour at all. /path?from=GB&to=FR therefore answers reachable: false with separate-land-masses.

Where do the border lengths in kilometres come from?

They are the figures published in the CIA World Factbook's Geography → Land boundaries field, read through a pinned mirror and frozen at the publication's final edition (it ended in February 2026). 321 of the 323 adjacent pairs carry one; we never measure geometry ourselves.

How many landlocked countries are there?

44 of the 249 officially assigned ISO 3166-1 entries are landlocked and 2 of those are doubly landlocked (LI and UZ). /api/country-borders/landlocked returns 45 rows because it also includes Kosovo (XK), which is a user-assigned code.

How are disputed borders like Kosovo or Western Sahara handled?

Adjacency reproduces the GeoNames neighbours column exactly, including XK, EH and PS, and we take no position on sovereignty. Where the two upstreams read a boundary differently — Morocco–Mauritania is the clearest case — the affected rows carry a notes string naming the upstream responsible.

Can I get the shortest route between two countries?

/api/country-borders/path?from=PT&to=PL returns the fewest land-border crossings and the chain of countries, deterministically. It is graph distance, not travel: no roads, no ferries, no crossing status and deliberately no distance field — use /api/geodesy for real distances.

Standards & references