temsor API
← Guides

Parsing Turkish addresses: mahalle, sokak, kapı no, daire

Turkish addresses are written free-form and read right-to-left in scope. Here is why western parsers fail on them and how to get province, district, street and door number reliably.

Updated 2026-07-26

If you ship to Türkiye, your checkout collects one free-text field and your warehouse needs five structured ones. Western address parsers get this wrong in a specific way, and the failure is quiet: you do not get an error, you get a package in the wrong district.

Why a western parser fails here

A typical Turkish address:

Atatürk Mah. 1234 Sok. No:5 Daire:3 Kadıköy/İstanbul 34710

Four things break a generic parser:

The dotted-i trap in one line: 'İSTANBUL'.toLowerCase() === 'istanbul' is false in JavaScript. Use a Turkish-aware fold (İ→i, I→ı) before comparing anything.

The parts you actually need

TurkishEnglishTypical markers
İlProvince (81 of them, plate-coded 1–81)usually last, after a slash
İlçeDistrictimmediately before the province
MahalleNeighbourhoodMah. Mh. Mahallesi
Cadde / Sokak / BulvarAvenue / street / boulevardCad. Sok. Blv.
Kapı noBuilding numberNo: No. Nu.
DaireApartmentD: Daire Kat (floor)
Posta koduPostal code5 digits; first two encode the province

One call, structured out

curl -X POST https://api.temsor.com/v1/tr/address/parse \
  -H 'content-type: application/json' \
  -d '{"address":"Atatürk Mah. 1234 Sok. No:5 Daire:3 Kadıköy/İstanbul 34710"}'
{
  "normalized": "Atatürk Mah. 1234 Sok. No: 5 D: 3 34710 Kadıköy / İstanbul",
  "province": "İstanbul",
  "provinceCode": 34,
  "district": "Kadıköy",
  "districtSource": "dictionary",
  "neighborhood": "Atatürk",
  "street": { "name": "1234", "type": "Sokak" },
  "buildingNumber": "5",
  "apartment": "3",
  "postalCode": "34710",
  "confidence": 1,
  "unparsed": [],
  "warnings": []
}

Read these three fields before you trust the rest

Validating what you parsed

Parsing tells you the shape; it does not tell you the values agree. The postcode carries the province in its first two digits, so a mismatch between postalCode and provinceCode is a cheap, high-signal check — it catches the very common case of a customer changing the city on a saved address but leaving the old postcode.

import Client from 'temsor-api';
const api = new Client();

const a = await api.trAddressParse({ address: input });
const postalProvince = Number(a.postalCode?.slice(0, 2));

if (a.confidence < 0.6) return needsReview(a);
if (a.postalCode && postalProvince !== a.provinceCode) return needsReview(a, 'postcode/province mismatch');
return a;

Practical advice for the form itself

The cheapest fix is upstream: split the province and district into selects and leave one free-text line for the rest. Parsing then only has to handle the street, door and apartment — the part that genuinely cannot be enumerated. Parse what you cannot control; control what you can.

Frequently asked

What is a "mahalle"?

The neighbourhood, the smallest administrative unit in a Turkish address. It is written before the street and is required for correct delivery in most cities.

How many provinces does Türkiye have?

81. Each has a plate code from 1 to 81, and the first two digits of a five-digit postal code identify the province.

Why does my JavaScript lowercase comparison fail on Turkish city names?

Because "İ".toLowerCase() produces an i followed by a combining dot. Fold İ→i and I→ı explicitly before comparing.

Endpoints used here

/v1/tr/address/parse

Open the reference, run it in the browser, no key required.

/v1/tr/validate

Open the reference, run it in the browser, no key required.