経理には「新規の取引先、この会社ほんとに実在する?商号合ってる?インボイス番号は正しい?」を確認する地味な作業があります。国税庁のサイトで番号を一件ずつ引く、あれです。これをAIに「チェック担当」として任せてみました。バクラクの申請を渡すと、AIが国税庁に照合してOK/要確認を返してきます。やってみたら、人が見落としがちな「消えた会社」まで拾ってきました。
連載「経理をAIに任せる」(全4回)
- 「経理はAIに任せられない」の先へ——AI前提の統制を、いま設計する
- 新規取引先チェックをAIに任せたら、合併で消えた会社を見つけてきた(この記事)
- 経費精算のレシートと明細を、AIに全部突合させてみた
- AI前提の経理は、会計ソフトを「APIが開いているか」で選ぶ
たび名前は合っているのに、番号は死んでいる——目視では、まず拾えないやつでした。
そもそも、何を確認する作業か
新規取引先の登録申請が来るたび、確認するのはこの4点——実在するか/商号は正しいか/インボイス登録番号は整合するか/法人番号は妥当か。単純ですが件数があり、合併で閉鎖された番号のような落とし穴は目視だと普通に見逃します。
AIに「チェック担当」として渡してみた
やったことはシンプルです。AIに申請とツール(API)を渡して、こう動かします。まずバクラク側から対象の申請を取ってきます(ここはベンダーのAPIなので擬似コード)。
# バクラクAPIで「申請中の新規取引先申請」を取得し、
# 各申請から 法人番号・取引先名・インボイス番号 を取り出す
applications = bakuraku.fetch_requests(status="IN_PROGRESS", form="新規取引先申請")
次が本題です。法人番号は「それっぽい13桁」でも、チェックディジットで真偽が分かります。ここは国が公開している計算式なので、実コードを載せます。
def validate_corporate_number(number: str) -> bool:
"""法人番号13桁のチェックディジットを検証する。"""
if not number or len(number) != 13 or not number.isdigit():
return False
check_digit = int(number[0])
base = number[1:] # 下位12桁が基礎番号
total = 0
for i, ch in enumerate(reversed(base)):
weight = 2 if i % 2 == 1 else 1 # 右から 奇数桁=1, 偶数桁=2
total += int(ch) * weight
return (9 - (total % 9)) == check_digit
そして実在・商号・「閉鎖」は、国税庁の公式Web-APIに当てます。AIが数字を捏造する余地がないのは、ここで一次情報に照合しているからです。
import csv, requests
NTA_API = "https://api.houjin-bangou.nta.go.jp"
def nta_lookup(numbers: list[str], app_id: str, version: str = "4") -> dict:
"""国税庁 法人番号Web-APIで 実在・商号・閉鎖 を照会する。"""
resp = requests.get(
f"{NTA_API}/{version}/num",
params={
"id": app_id, # 無料発行のアプリID
"number": ",".join(numbers), # 最大10件まとめて
"type": "02", # CSV(Unicode)で受け取る
"history": "0", # 最新の登記のみ
},
)
resp.raise_for_status()
records = {}
for row in csv.reader(resp.content.decode("utf-8").splitlines()):
if len(row) <= 20:
continue # ヘッダー行などをskip
records[row[1]] = { # row[1] = 法人番号
"name": row[6], # 商号
"closeDate": row[18], # 閉鎖年月日(合併・解散など)
"successor": row[20], # 承継先の法人番号
}
return records
最後に、結果を「OK」と「要確認」に振り分けます。人が見るのは要確認だけです。
issues = []
if not validate_corporate_number(corp):
issues.append("法人番号CD不正")
if invoice and invoice != "T" + corp:
issues.append("インボイス番号不整合")
if record is None:
issues.append("国税庁に該当なし")
elif record["closeDate"]: # ← ここが効いた
issues.append("閉鎖/合併(承継先: " + (record["successor"] or "不明") + ")")
elif normalize(client_name) != normalize(record["name"]):
issues.append("商号不一致")
verdict = "要確認" if issues else "OK"
捏造が起きない理由
数字の検算も国税庁照合も、AIが「道具」(計算式・公式API)を使って機械的にやっています。AIが法人番号を勝手に作るわけじゃないから、捏造が起きません。
やってみたら、消えた会社を拾ってきた
実際に回したら、ある申請の法人番号が合併ですでに閉鎖済みのものでした。存続する会社は別の番号を持っています。名前は合っているので目視なら通しかねないところを、閉鎖年月日と承継先番号を見て自動で「要確認」に落としました。差し戻したのは自分です。
APIキーが無くても、AIがWebで代替照合する
実はこのチェック、国税庁の公式Web-APIには無料のアプリIDが要ります。発行が間に合わないこともあります。でも止まりません。APIが使えないときは、AIに法人番号データベース(houjin.info など)で一件ずつ実在・商号・閉鎖を調べさせます。やることは人間の手作業と同じです——番号で引いて、登記の商号と申請名を見比べ、閉鎖していないか確認する。
しかもこの手順はプロジェクトのREADMEに書いてあって、AIはそれを読んでそのまま実行します。人に手順書を渡して仕事を任せるのと同じです。要点はこれだけです。
- houjin.info で登記の商号・所在地・登記状態(現存/閉鎖)・承継先番号を読む
- houjin.jp でもクロスチェック(※旧住所が出ることがある→最新は houjin.info を優先)
- 申請名・住所と照合し、商号不一致/閉鎖/所在地相違なら「要確認」
- 番号はAIが生成しない/参照URLを根拠に残す/承認は人
APIが無くても止まらない理由
APIが理想ですが、無くてもAIが「人と同じ手作業」を代行できます。しかも手順をREADMEに書いておけば、AIは毎回それを読んで同じ品質で動きます。「道具が無いから止まる」が減ります。
どこまで任せて、どこは自分がやるか
任せたのは「全件照合して、要確認を上げてくる」ところまで。承認・差し戻しは自分です。
役割分担
作業(照合・振り分け)はAI。判断(承認・差し戻し)と責任は人。AIは「優秀な確認担当」、自分は「最終承認者」です。
おまけ:このコード、全部AIに書かせた
最後に正直に言うと、ここに載せたコードは自分でゴリゴリ書いていません。要件(何を確認したいか)をAIに渡して、実装はAI、レビューと検証は自分、という分担です。経理がコードを書けなくても、AIを相棒にすればこの手の道具は作れます。
まとめ
バクラクの新規取引先チェックは「全件照合して要確認だけ上げるAI担当」になり、閉鎖済みの番号も自動検知。任せるのは作業、判断は自分。実装すらAIに任せられる時代です。
次は「レシートと明細の照合」をAIにやらせた話です(画像をAIに読ませる、より「AIらしい」処理です)。→ 経費精算のレシートと明細を、AIに全部突合させてみた


