法人番号Web-APIについて


こんにちは、ライトパスの松野です。

今年(2017年)の4月よりWeb-APIのVer.2がリリースされ、法人名より法人番号が取得できるようになりました。

法人番号は国内で登記されれている「法人、団体」全てに割り振られ、原則全ての番号は公開という、企業情報を管理するという観点からはなんとも嬉しい番号です。

今後は企業情報のキーを法人番号にすることにより、今まで何かと煩わしかったシステム間の連携が容易になってきそうです。また、法人番号検索等のWeb-APIも公開されていますので、わざわざ全ての法人番号を自分のデータベースに持っていなくても、容易に法人番号の検索が出来るのも良いですね。

というわけで今後、法人番号で連携する要件が増えてきそうなので、Web-APIの連携について調べ、どのような感じで動くのか実際にC#でサンプルを作成してみました。

 

アプリケーションIDの取得

Web-APIを使用するためにはアプリケーションIDを国税庁より発行してもらう必要があります。IDの発行は無料で以下より申請が可能です。Web-APIを試したい場合はまずはアプリケーションIDを取得して下さい。

アプリケーションIDの発行届出フォーム

 

Web-APIで出来ること

Web-APIで出来ることは3つあります。

  • 法人番号を指定して法人情報を取得
  • 期間を指定して新規、変更、閉鎖の差分情報を取得
  • 法人名を指定して法人番号を検索

Web-APIへリクエストをすると、指定され他フォーマット(CSVもしくはXML)で応答が返ってきます。今後はWeb系のシステムからの連携も多いのではと考えると、JSONに対応をしていれば良いのにと思いますが、この手のAPIとしてはまだJSONは新しすぎるのでしょうか・・。

今回は法人情報をXML形式で取得し、オブジェクトにDesrializeという流れでサンプルを作成してみました。

嬉しいところ(ポイント?)は上記3通りのAPI全て同じストラクチャで応答があるところですね。Deserialize先のクラスとしてCorporations、Corporationの2つを用意しておけば上記3通りの応答が取得できます。

Web-APIの詳細はWeb-APIのリクエストの 設定方法及び提供データの内容について(Ver.2)に載っていますので参考にして下さい。

取得できる法人情報は大きく「法人番号」「法人名」「登記住所」です。

 

 Deserialize用クラス

それでは、まず最初にDeserialize用クラスの定義です。

Corporationsクラスはレスポンスのヘッダ情報です。1回の返答で返ってくる最大法人数は2,000件なので2,000件以上取得する場合はdivideNumberを使用して、複数回リクエストする必要があります。

Corporationクラスは法人レコードになります。

Corporations.cs

using System;
using System.Collections.Generic;
using System.Xml.Serialization;

[Serializable(), XmlRoot("corporations")]
public class Corporations
{
    [XmlElement("lastUpdateDate")]
    public string lastUpdateDate { get; set; }

    [XmlElement("count")]
    public int count { get; set; }

    [XmlElement("divideNumber")]
    public int divideNumber { get; set; }

    [XmlElement("divideSize")]
    public int divideSize { get; set; }

    [XmlElement("corporation")]
    public List corporations { get; set; }
}

Corporation.cs

using System;
using System.Xml.Serialization;

[Serializable()]
public class Corporation
{
    [XmlElement("sequenceNumber")]
    public int sequenceNumber { get; set; }

    [XmlElement("corporateNumber")]
    public string corporateNumber { get; set; }

    [XmlElement("process")]
    public string process { get; set; }

    [XmlElement("correct")]
    public string correct { get; set; }

    [XmlElement("updateDate")]
    public string updateDate { get; set; }

    [XmlElement("changeDate")]
    public string changeDate { get; set; }

    [XmlElement("name")]
    public string name { get; set; }

    [XmlElement("kind")]
    public string kind { get; set; }

    [XmlElement("prefectureName")]
    public string prefectureName { get; set; }

    [XmlElement("cityName")]
    public string cityName { get; set; }

    [XmlElement("streetNumber")]
    public string streetNumber { get; set; }

    [XmlElement("addressImageId")]
    public string addressImageId { get; set; }

    [XmlElement("prefectureCode")]
    public string prefectureCode { get; set; }

    [XmlElement("cityCode")]
    public string cityCode { get; set; }

    [XmlElement("postCode")]
    public string postCode { get; set; }

    [XmlElement("addressOutside")]
    public string addressOutside { get; set; }

    [XmlElement("addressOutsideImageId")]
    public string addressOutsideImageId { get; set; }

    [XmlElement("closeDate")]
    public string closeDate { get; set; }

    [XmlElement("closeCause")]
    public string closeCause { get; set; }

    [XmlElement("successorCorporateNumber")]
    public string successorCorporateNumber { get; set; }

    [XmlElement("changeCause")]
    public string changeCause { get; set; }

    [XmlElement("assignmentDate")]
    public string assignmentDate { get; set; }

    [XmlElement("latest")]
    public string latest { get; set; }

    [XmlElement("enName")]
    public string enName { get; set; }

    [XmlElement("enPrefectureName")]
    public string enPrefectureName { get; set; }

    [XmlElement("enCityName")]
    public string enCityName { get; set; }

    [XmlElement("enAddressOutside")]
    public string enAddressOutside { get; set; }

}

 

リクエスト

あとは指定されたフォーマットでリクエストを送信し、応答内容をDeserializeするだけです。

今回は法人番号検索、差分検索、名前検索の3通りでメソッドを作成してみみました。

 

SearchByNumber(string number)

SearchByDiff(System.DateTime fromDate, System.DateTime toDate, int divide = 1)

SearchByName(string name)

 

HojinBangoUtil.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Net;
using System.IO;
using System.Xml.Serialization;
using System.Web;
using System.Xml.Linq;

public class HojinBangoUtil
{

    static string baseUrl = "https://api.houjin-bangou.nta.go.jp/2/";
    public static Corporations SearchByNumber(string number)
    {
        string method = "num";

        System.Collections.Specialized.NameValueCollection parameters = HttpUtility.ParseQueryString(string.Empty);
        parameters.Add("number", number);
        parameters.Add("history", "0");

        return SearchBase(parameters, method);

    }

    public static Corporations SearchByDiff(System.DateTime fromDate, System.DateTime toDate, int divide = 1)
    {
        string method = "diff";

        if (DateTime.Compare(fromDate, new System.DateTime(2015, 12, 1)) < 0) { throw new Exception("開始日は2015年12月1日以降のみです"); } if ((toDate - fromDate).TotalDays >= 50)
        {
            throw new Exception("取得可能な最大日数は50日です");
        }

        System.Collections.Specialized.NameValueCollection parameters = HttpUtility.ParseQueryString(string.Empty);
        parameters.Add("from", fromDate.ToString("yyyy-MM-dd"));
        parameters.Add("to", toDate.ToString("yyyy-MM-dd"));
        parameters.Add("divide", divide.ToString());

        return SearchBase(parameters, method);

    }

    public static Corporations SearchByName(string name)
    {
        string method = "name";

        System.Text.Encoding enc = System.Text.Encoding.GetEncoding("utf-8");
        name = System.Web.HttpUtility.UrlEncode(name, enc);

        System.Collections.Specialized.NameValueCollection parameters = HttpUtility.ParseQueryString(string.Empty);
        parameters.Add("name", name);
        parameters.Add("change", "1");
        parameters.Add("mode", "2");

        return SearchBase(parameters, method);
    }

    private static Corporations SearchBase(System.Collections.Specialized.NameValueCollection parameters, string method)
    {
        WebClient wc = new WebClient();
        string html;

        //取得した法人番号
        parameters.Add("id", System.Configuration.ConfigurationManager.AppSettings["ApplicationID"]);
        parameters.Add("type", "12");

        UriBuilder uri = new UriBuilder(baseUrl + method);
        uri.Query = parameters.ToString();

        using (Stream st = wc.OpenRead(HttpUtility.UrlDecode(uri.Uri.ToString())))
        {
            System.Text.Encoding enc = System.Text.Encoding.GetEncoding("utf-8");
            using (StreamReader sr = new StreamReader(st, enc))
            {
                html = sr.ReadToEnd();
            }
        }

        XElement xelement = XElement.Parse(html);
        XmlSerializer serializer = new XmlSerializer(typeof(Corporations));
        Corporations corporations = (Corporations)serializer.Deserialize(xelement.CreateReader());

        return corporations;

    }
}

 

呼び出し方法

 

HojinBangoUtil.SearchByName("<法人名>");
HojinBangoUtil.SearchByNumber("<法人番号>");
HojinBangoUtil.SearchByDiff(new DateTime(2017, 1, 1), new DateTime(2017, 2, 19));

 

まとめ

実際にはエラー処理や、レスポンスが2,000件以上ある場合の処理は必用ですが、動作確認は出来たので、ここまでということにしておきます。

既存データとのマッチングですが、実際は登記されている法人名と、知れ渡っている法人名が違ったり、(本社)住所が登記住所と違ったりするので、管理の仕方もコツが必要になりそうですが、何れにせよ、法人番号で社内、社外の情報が連携で来るようになれば、得られる恩恵は大きいですね。