# Vietnam Address Converter (63 to 34 provinces) (`puk.ora/vietnam-address-converter`) Actor

Convert old Vietnamese addresses (63 provinces, 3 levels) to the new post-merger format (34 provinces, 2 levels). Returns new ward, province, official codes and coordinates, and flags addresses that need manual review.

- **URL**: https://apify.com/puk.ora/vietnam-address-converter.md
- **Developed by:** [Phúc Dương](https://apify.com/puk.ora) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 address processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Vietnam Address Converter: old 63-province addresses to the new 34-province format

On 1 July 2025 Vietnam merged its 63 provinces into 34 and removed the district level. Every address written before that date is now out of date. This Actor converts old addresses to the new format in bulk, so you can fix a customer list, a CRM export or a shipping database without writing code.

**What you get for each address**

- The new address, new ward and new province, with correct Vietnamese accents
- Ward and province codes, plus ward coordinates
- The old ward, district and province it was matched to, so you can audit the result
- A `needsReview` flag on every row that is not a clean one-to-one conversion

### Example

Input:

```json
{
  "addresses": [
    "720A Điện Biên Phủ, Phường 22, Quận Bình Thạnh, TP.HCM",
    "so 1 Dai Co Viet, P. Bach Khoa, Q. Hai Ba Trung, Ha Noi",
    "12 Đường A, Xã Hòa Liên, Huyện Hòa Vang, Đà Nẵng"
  ]
}
```

Output (shortened):

```json
[
  {
    "input": "720A Điện Biên Phủ, Phường 22, Quận Bình Thạnh, TP.HCM",
    "status": "converted",
    "newAddress": "720A Điện Biên Phủ, Phường Thạnh Mỹ Tây, Thành phố Hồ Chí Minh",
    "newWard": "Phường Thạnh Mỹ Tây",
    "newProvince": "Thành phố Hồ Chí Minh",
    "newWardCode": "26956",
    "newProvinceCode": "79",
    "oldWard": "Phường 22",
    "oldDistrict": "Quận Bình Thạnh",
    "needsReview": false
  },
  {
    "input": "so 1 Dai Co Viet, P. Bach Khoa, Q. Hai Ba Trung, Ha Noi",
    "status": "converted",
    "newAddress": "So 1 Dai Co Viet, Phường Bạch Mai, Thành phố Hà Nội",
    "needsReview": false
  },
  {
    "input": "12 Đường A, Xã Hòa Liên, Huyện Hòa Vang, Đà Nẵng",
    "status": "converted",
    "newWard": "Phường Liên Chiểu",
    "wardWasSplit": true,
    "candidateWards": ["Phường Hải Vân", "Phường Liên Chiểu"],
    "needsReview": true
  }
]
```

### Who uses this

- **E-commerce and logistics teams** updating delivery addresses so couriers accept them
- **CRM and ERP owners** cleaning customer, supplier and branch records
- **Data and AI teams** that need one consistent address key to join datasets
- **AI agents** that need to normalise a Vietnamese address inside a workflow (works through the Apify MCP server)

### It handles messy input

- Missing accents: `Phuong Ben Nghe, Quan 1, Ho Chi Minh`
- Abbreviations: `P.`, `Q.`, `TP.HCM`, `TX.`, `TT.`
- Province only: `Bình Dương` becomes `Thành phố Hồ Chí Minh`, marked `province_only`
- Input that is not an address: returned as `not_found`, never a crash, and **not charged**

### Honest about uncertainty

About 470 old wards were split across two or more new wards. The street alone cannot tell you which one is right, so the Actor picks a default, sets `wardWasSplit: true`, lists every possibility in `candidateWards`, and sets `needsReview: true`. Filter on `needsReview` to get the short list a person should check.

Addresses are processed inside the Actor. Nothing is sent to an external geocoding service.

### Input

| Field | Type | Description |
| --- | --- | --- |
| `addresses` | array of strings | One address per item, smallest unit first: street, ward, district, province |
| `mode` | `convert` or `standardize` | `convert` (default) for old-format addresses. `standardize` for addresses already in the new format that only need cleaning and codes |

### Output fields

| Field | Description |
| --- | --- |
| `index` | Position of the address in your input |
| `status` | `converted`, `province_only` or `not_found` |
| `newAddress` | Full address in the new format |
| `street` | Street part, kept as you wrote it |
| `newWard`, `newProvince` | New administrative units |
| `newWardCode`, `newProvinceCode` | Administrative unit codes |
| `latitude`, `longitude` | Approximate centre of the new ward (not of the street address) |
| `oldWard`, `oldDistrict`, `oldProvince` | What the input was matched to |
| `wardWasSplit`, `candidateWards` | Set when the old ward maps to several new wards |
| `needsReview` | `true` when a person should check the row |
| `note` | Plain-language reason when review is needed |

A run summary with counts per status is saved in the key-value store under `SUMMARY`.

### Pricing

Pay per result: you pay only for addresses that were recognised. Rows returned as `not_found` are free.

### Coverage and limits

- Tested against all 10,040 pre-merger ward names: every one was matched when written with accents, and 99.6% when written without accents (a few unaccented names are ambiguous and fall back to `province_only`).
- That test measures whether an address is *recognised*. The old-to-new mapping itself comes from the open-source [`vietnamadminunits`](https://github.com/tranngocminhhieu/vietnamadminunits) dataset (MIT licence). Treat results as a strong starting point and review flagged rows before using them for legal or official documents.
- Write addresses from smallest to largest unit. Reversed order is not supported.
- Coordinates are ward centres, not rooftop geocodes.

### FAQ

**Does it work on addresses that are already in the new format?** Use `mode: "standardize"`.

**Can I run it from code?** Yes, through the Apify API, the Python or JavaScript client, Make, Zapier, n8n, or the Apify MCP server.

**I found a wrong result.** Open an issue on the Issues tab with the input address.

*This is an independent tool and is not affiliated with any government body.*

# Actor input Schema

## `addresses` (type: `array`):

One Vietnamese address per line, written from smallest to largest unit: street, ward, district, province. Accents are optional and common abbreviations (P., Q., TP.HCM) are understood.

## `mode` (type: `string`):

convert: the input uses the old 63-province system and should be converted. standardize: the input already uses the new 34-province system and only needs cleaning and codes.

## Actor input object example

```json
{
  "addresses": [
    "720A Điện Biên Phủ, Phường 22, Quận Bình Thạnh, TP.HCM",
    "so 1 Dai Co Viet, P. Bach Khoa, Q. Hai Ba Trung, Ha Noi",
    "Xã Tân Lộc, Huyện Thới Bình, Cà Mau"
  ],
  "mode": "convert"
}
```

# Actor output Schema

## `results` (type: `string`):

One row per input address, with the new ward, province, codes and review flags.

## `summary` (type: `string`):

Totals per status (converted, province_only, not_found) and how many rows need review.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "addresses": [
        "720A Điện Biên Phủ, Phường 22, Quận Bình Thạnh, TP.HCM",
        "so 1 Dai Co Viet, P. Bach Khoa, Q. Hai Ba Trung, Ha Noi",
        "Xã Tân Lộc, Huyện Thới Bình, Cà Mau"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("puk.ora/vietnam-address-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "addresses": [
        "720A Điện Biên Phủ, Phường 22, Quận Bình Thạnh, TP.HCM",
        "so 1 Dai Co Viet, P. Bach Khoa, Q. Hai Ba Trung, Ha Noi",
        "Xã Tân Lộc, Huyện Thới Bình, Cà Mau",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("puk.ora/vietnam-address-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "addresses": [
    "720A Điện Biên Phủ, Phường 22, Quận Bình Thạnh, TP.HCM",
    "so 1 Dai Co Viet, P. Bach Khoa, Q. Hai Ba Trung, Ha Noi",
    "Xã Tân Lộc, Huyện Thới Bình, Cà Mau"
  ]
}' |
apify call puk.ora/vietnam-address-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,puk.ora/vietnam-address-converter"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RzdDTlr82QRJefRfq/builds/bi2AR86gWI7RkhOWc/openapi.json
