🚀

郵便局の「デジタルアドレス」のAPIを使って見えたメリットと課題

に公開

背景

先日、2025年5月26日、日本郵便から「デジタルアドレス」という新しいサービスが発表されました。

世間の期待

世間ではこのサービスにおおよそ2つの期待がされています。

1. CSVの更新不要

1つ目は、KEN_ALL.csv の定期的な更新が不要になること。
従来、郵便番号と住所の組み合わせはcsv形式で配布されてきたため、郵便番号を扱う多くのシステムではこのファイルの定期更新を行うプログラムが稼働していることが多い状況となっていました。
公式からWebAPIが提供されることにより、このファイルの定期更新が不要になります。

2. デジタルアドレス

2つ目は「デジタルアドレス」という新サービスです。
住所を郵便番号と同様の7桁の英数字で表すため、住所の入力が容易になる可能性を秘めています。
このサービスは勘違いされがちですが、「すべての住所に新たな郵便番号が割り当てられるサービスではない」です。
あくまで「申請した場合に限り」新しいデジタルアドレスという番号が割り当てられるサービスです。
イメージとしては、短縮URLサービスに近いサービスです。

これらのうち、両方を扱えるAPIエンドポイントを使用してみたため、メモと情報共有として記事に起こします。

手順

アカウント作成

  1. ゆうIDを取得
    公式サイトからゆうID(郵便局のID)を取得します。

  2. Biz版に登録
    以下のページから「郵便番号・デジタルアドレス for Biz」に新規登録を行います
    https://guide-biz.da.pf.japanpost.jp/api/

新規登録したゆうIDでログインして必要事項を入力します
法人または個人事業主のみ使用できるようです。私は手持ちの法人があるためそちらで申請

  1. 結果
    ログインすると次のような画面になります。

APIの使用方法

APIは次のようにtokenを取得して各機能を使用することとなります。

  1. token エンドポイントに「クライアントID」と「クライアントシークレット」を送信して token を取得
  2. token を認証に使用して各エンドポイントを使用

APIエンドポイント

APIには3つのエンドポイントがあります。

token

searchcode や addresszip を使用するための token を発行します。

searchcode

次のいずれかの情報を引数にして住所情報を取得できます。

  • 郵便番号 (3桁以上の数値。入力された値が7桁未満であった場合、入力値から始まるデータをパターン検索する。)
  • 事業所個別郵便番号
  • デジタルアドレス

addresszip

住所情報から郵便番号を取得します。
ただし、品質はかなり低いため外部サービスを使用したほうが良いでしょう。
試しに総務省の住所「東京都千代田区霞が関2丁目1-2」を試してみたところ、千代田区の郵便番号がズラズラと返されてきました。このAPIを使用する場合は住所の正規化・分離した上で使用する必要があるようで、使用には少々ハードルが高いように思いました。

    {
      "zip_code": "1020081",
      "pref_code": "13",
      "pref_name": "東京都",
      "pref_kana": "トウキョウト",
      "pref_roma": "TOKYO",
      "city_code": "13101",
      "city_name": "千代田区",
      "city_kana": "チヨダク",
      "city_roma": "CHIYODA-KU",
      "town_name": "四番町",
      "town_kana": "ヨンバンチョウ",
      "town_roma": "YOMBANCHO"
    },
....

実際には、searchcode だけが使用されることになると思います。

実装例

実際にコードを書いてみました。

searchcodeを使用する例

import requests
import json
import sys

# トークン取得用の認証情報
CLIENT_ID = "Biz_DaPfJapanpost_MockAPI_j3QKS"
SECRET_KEY = "uXuN0ejHG7nAn89AfAwa"
TOKEN_URL = "https://stub-qz73x.da.pf.japanpost.jp/api/v1/j/token"
API_URL = "https://stub-qz73x.da.pf.japanpost.jp/api/v1/searchcode/"

def get_access_token():
    """JWTトークンを取得する"""
    data = {
        "grant_type": "client_credentials",
        "client_id": CLIENT_ID,
        "secret_key": SECRET_KEY
    }
    headers = {
        "Content-Type": "application/json"
    }
    
    response = requests.post(TOKEN_URL, json=data, headers=headers)

    try:
        response.raise_for_status()
        return response.json().get("token")
    except requests.exceptions.HTTPError as e:
        print(f"トークン取得エラー詳細:")
        print(f"URL: {TOKEN_URL}")
        print(f"Status Code: {response.status_code}")
        print(f"Response: {response.text}")
        raise

def fetch_address_data(token, code, limit=10):
    """住所データを取得する"""
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }
    # 住所検索用のJSONデータを送信
    params = {"limit": limit}
    url = API_URL + code
    print(url)
    response = requests.get(url, headers=headers, params=params)
    response.raise_for_status()
    return response.json()

if __name__ == "__main__":
    try:
        # コマンドライン引数からcodeとlimitを取得
        DEFAULT_CODE = "A7E2FK2" # 公式サンプルのコードA7E2FK2
        DEFAULT_LIMIT = 10
        code = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_CODE
        limit = int(sys.argv[2]) if len(sys.argv) > 2 else DEFAULT_LIMIT
        
        # トークン取得
        token = get_access_token()
        print(f"トークン取得成功: {token}")
        
        # APIからデータ取得
        data = fetch_address_data(token, code, limit)
        print(f"郵便番号 {code} の取得データ:")
        print(json.dumps(data, indent=2, ensure_ascii=False))
        
    except requests.exceptions.RequestException as e:
        print(f"エラーが発生しました: {e}")

応答

{
  "page": 1,
  "limit": 10,
  "count": 1,
  "searchtype": "dgacode",
  "addresses": [
    {
      "dgacode": "A7E2FK2",
      "zip_code": "100-0005",
      "pref_code": "13",
      "pref_name": "東京都",
      "pref_kana": null,
      "pref_roma": null,
      "city_code": "13101",
      "city_name": "千代田区",
      "city_kana": null,
      "city_roma": null,
      "town_name": "丸の内",
      "town_kana": null,
      "town_roma": null,
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": "2丁目7−2",
      "other_name": "部屋番号:サンプル1",
      "address": "東京都千代田区丸の内2丁目7−2部屋番号:サンプル1",
      "longitude": null,
      "latitude": null
    }
  ]
}

良いところ

シンプルにデジタルアドレスが便利

試しに自宅住所のデジタルアドレスを取得してみましたが、番号を入力するだけで住所を出力できました。
様々な入力フォームでサポートされるようになれば、かなり便利だと思います。

KEN_ALLのcsvファイルがイケてない問題が大幅に改善している

KEN_ALL.csv は中身がイケていないという問題を抱えていたのですが、これが大幅に改善しています。
しかしながら、完全には解決していません。
例えば以下のようなものがあります。

協和問題

例えば、関係者の中では有名な協和問題(1つの行に複数の番地が列挙されている)では、カッコ書きを削除する対応が行われています。
最低限の対応は行われていますが、これは本来は配列ですべての住所を返すべきです。

{
  "page": 1,
  "limit": 10,
  "count": 1,
  "searchtype": "zipcode",
  "addresses": [
    {
      "dgacode": null,
      "zip_code": "0660005",
      "pref_code": "01",
      "pref_name": "北海道",
      "pref_kana": "ホッカイドウ",
      "pref_roma": "HOKKAIDO",
      "city_code": "01224",
      "city_name": "千歳市",
      "city_kana": "チトセシ",
      "city_roma": "CHITOSE-SHI",
      "town_name": "協和",
      "town_kana": "キョウワ",
      "town_roma": "KYOWA",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    }
  ]
}

複数の県にまたがるケース

一方で、同じ郵便番号が複数の県にまたがっているケースでは配列で返されるという良い結果が得られています。

{
  "page": 1,
  "limit": 10,
  "count": 2,
  "searchtype": "zipcode",
  "addresses": [
    {
      "dgacode": null,
      "zip_code": "4980000",
      "pref_code": "23",
      "pref_name": "愛知県",
      "pref_kana": "アイチケン",
      "pref_roma": "AICHI",
      "city_code": "23235",
      "city_name": "弥富市",
      "city_kana": "ヤトミシ",
      "city_roma": "YATOMI-SHI",
      "town_name": "",
      "town_kana": "",
      "town_roma": "",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    },
    {
      "dgacode": null,
      "zip_code": "4980000",
      "pref_code": "24",
      "pref_name": "三重県",
      "pref_kana": "ミエケン",
      "pref_roma": "MIE",
      "city_code": "24303",
      "city_name": "桑名郡木曽岬町",
      "city_kana": "クワナグンキソサキチョウ",
      "city_roma": "KUWANA-GUN KISOSAKI-CHO",
      "town_name": "",
      "town_kana": "",
      "town_roma": "",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    }
  ]
}

京都の通り名が列挙されているケース

また、京都の通り名が列挙されているケースもあります。
この場合もすべての候補が返されるという良い結果が得られています。

{
  "page": 1,
  "limit": 10,
  "count": 3,
  "searchtype": "zipcode",
  "addresses": [
    {
      "dgacode": null,
      "zip_code": "6028143",
      "pref_code": "26",
      "pref_name": "京都府",
      "pref_kana": "キョウトフ",
      "pref_roma": "KYOTO",
      "city_code": "26102",
      "city_name": "京都市上京区",
      "city_kana": "キョウトシカミギョウク",
      "city_roma": "KYOTO-SHI KAMIGYO-KU",
      "town_name": "中之町 猪熊通竹屋町上る",
      "town_kana": "ナカノチョウ",
      "town_roma": "NAKANOCHO",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    },
    {
      "dgacode": null,
      "zip_code": "6028143",
      "pref_code": "26",
      "pref_name": "京都府",
      "pref_kana": "キョウトフ",
      "pref_roma": "KYOTO",
      "city_code": "26102",
      "city_name": "京都市上京区",
      "city_kana": "キョウトシカミギョウク",
      "city_roma": "KYOTO-SHI KAMIGYO-KU",
      "town_name": "中之町 猪熊通丸太町下る",
      "town_kana": "ナカノチョウ",
      "town_roma": "NAKANOCHO",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    },
    {
      "dgacode": null,
      "zip_code": "6028143",
      "pref_code": "26",
      "pref_name": "京都府",
      "pref_kana": "キョウトフ",
      "pref_roma": "KYOTO",
      "city_code": "26102",
      "city_name": "京都市上京区",
      "city_kana": "キョウトシカミギョウク",
      "city_roma": "KYOTO-SHI KAMIGYO-KU",
      "town_name": "中之町 西堀川通丸太町下る",
      "town_kana": "ナカノチョウ",
      "town_roma": "NAKANOCHO",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    }
  ]
}

総じて、一部問題あれど大幅に問題が改善しています。

課題

一方で課題も見えてきました。

固定IPアドレスから利用する必要がある

本番で使用する場合は固定IPアドレスを登録する必要があります。

現在主流の郵便番号から住所を補完するシステム・プログラムでは、yubinbangou.js などを使用してフロントエンドで完結するシステム構成をしていることが多いのですが、固定IPでしか使用できないため、このようなフロントエンドで完結する方式は採用できません。
https://github.com/yubinbango/yubinbango

また、バックエンドで使用する場合でも Gateway を固定にする必要があるため使用するクラウド・構成によっては考慮が必要になります。

逆引きは使い物にならない

住所情報から郵便番号を取得する機能については、まだまだ使用できるレベルに達していません。
エンドポイントが用意されているのは評価されても良いと思いますが、今後に期待という印象です。

事業でしか使用できない

法人、または個人事業主でしか利用できないため、それ以外の入力フォームでは使用できません。
例えば、学校や、地域の集まりなど、身近な関係では使用できませんし、最近流行りの個人開発で作成したサービスでも使用できません。

BANされる懸念がある

事前の予告なく強制退会される懸念があり、大量に使用する用途では採用に懸念があります。
基準も特に提示されていないようです。

所感

いくつかの問題はありますが、デジタルアドレスは広く普及するだろうという所感を持ちました。
比較的使用方法も簡単で、導入へのハードルはそれほど高くありません。
利用するユーザーは限定的だろうと思いますが、利便性も高いためジワジワと普及していきそうです。

Discussion