APIリファレンス · v1

APIドキュメント

予約1件につき1回の呼び出しで、各泊をその日の規則で課税します。泊ごとの料金・人数・課税主体別の内訳まで、JSONで返します。

  • ベースURL: https://yadozei.jp/v1
  • JSON
  • CORS対応
  • 全国66エリア
  • データ 2026.10
  • 日付は日本時間
  • 料金は1泊ごと・税抜
目次

クイックスタート

  1. キーなしで始められます

    APIキーがなくても、IPアドレスごとに1日100回・毎分10回まで呼び出せます(POST /v1/resolve、GET /v1/data を除く)。

    キーなしの呼び出しにもAPIキーでの利用にも利用規約が適用され、契約内容となります。

  2. 最初のリクエスト

    東京都で1人1泊¥15,000(税抜)、2泊・2名の場合:

    リクエスト
    cURL
    curl -X POST https://yadozei.jp/v1/calculate \
      -H 'content-type: application/json' \
      -d '{"areaId":"tokyo","ratePerNight":15000,"date":"2026-12-01","nights":2,"guests":2}'
    JavaScript
    const res = await fetch("https://yadozei.jp/v1/calculate", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        "areaId": "tokyo",
        "ratePerNight": 15000,
        "date": "2026-12-01",
        "nights": 2,
        "guests": 2
      }),
    });
    const data = await res.json();
    if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
    Python
    import requests
    
    res = requests.post(
        "https://yadozei.jp/v1/calculate",
        json={"areaId": "tokyo", "ratePerNight": 15000, "date": "2026-12-01", "nights": 2, "guests": 2},
        timeout=10,
    )
    data = res.json()
    if not res.ok:
        raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")
    レスポンス 200
    {
      "areaId": "tokyo",
      "areaName": {
        "en": "Tokyo",
        "ja": "東京都"
      },
      "currency": "JPY",
      "dateUsed": "2026-12-01",
      "basis": "per_person",
      "perNightTax": 200,
      "breakdown": [
        {
          "authority": {
            "en": "Tokyo Metropolitan Government",
            "ja": "東京都"
          },
          "amount": 200,
          "type": "fixed"
        }
      ],
      "nights": 2,
      "guests": 2,
      "nightly": [
        {
          "date": "2026-12-01",
          "ratePerNight": 15000,
          "perNightTax": 200,
          "breakdown": [
            {
              "authority": {
                "en": "Tokyo Metropolitan Government",
                "ja": "東京都"
              },
              "amount": 200,
              "type": "fixed"
            }
          ]
        },
        {
          "date": "2026-12-02",
          "ratePerNight": 15000,
          "perNightTax": 200,
          "breakdown": [
            {
              "authority": {
                "en": "Tokyo Metropolitan Government",
                "ja": "東京都"
              },
              "amount": 200,
              "type": "fixed"
            }
          ]
        }
      ],
      "stayTotal": {
        "perPerson": 400,
        "total": 800,
        "breakdown": [
          {
            "authority": {
              "en": "Tokyo Metropolitan Government",
              "ja": "東京都"
            },
            "amount": 800,
            "type": "fixed"
          }
        ]
      }
    }

    宿泊全体の税額は stayTotal.total(この例では¥800)です。

  3. APIキーを取得する

    本番ではAPIキーをお使いください。お問い合わせから、システム名と月間の想定リクエスト数をお知らせください。お見積りのうえ、キー(yz_…)を発行します。キーは X-API-Key ヘッダで送ります。

APIが扱わないこと

  • 免税・課税免除(修学旅行など)は自動では適用されません。対象の方は guests から除くか、別に計算してください。
  • 料金の異なる宿泊者や、途中で人数が変わる宿泊は、条件ごとに分けて呼び出してください。
  • 本結果は参考情報であり税務助言ではありません。最終的な金額は各自治体の公式情報をご確認ください。

試してみる

本番のAPIに実際にリクエストを送ります。キーは不要です。

料金の入力

キーなしの呼び出しにもAPIキーでの利用にも利用規約が適用され、契約内容となります。

送信のたびに、あなたのIPの無料枠(1日100回・毎分10回。ほかの匿名の呼び出しと共通)を1回使います。

リクエスト
cURL
curl -X POST https://yadozei.jp/v1/calculate \
  -H 'content-type: application/json' \
  -d '{"areaId":"tokyo","ratePerNight":15000,"nights":2,"guests":2}'
JavaScript
const res = await fetch("https://yadozei.jp/v1/calculate", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    "areaId": "tokyo",
    "ratePerNight": 15000,
    "nights": 2,
    "guests": 2
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import requests

res = requests.post(
    "https://yadozei.jp/v1/calculate",
    json={"areaId": "tokyo", "ratePerNight": 15000, "nights": 2, "guests": 2},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

「リクエストを送信」を押すと、ここにAPIの応答が表示されます。

認証

APIキーは X-API-Key ヘッダで送ります。キーは yz_ で始まり、発行時に一度だけ表示されます。

リクエスト
cURL
curl https://yadozei.jp/v1/areas/tokyo \
  -H "x-api-key: $YADOZEI_API_KEY"
JavaScript
const res = await fetch("https://yadozei.jp/v1/areas/tokyo", {
  headers: { "x-api-key": process.env.YADOZEI_API_KEY },
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import os
import requests

res = requests.get(
    "https://yadozei.jp/v1/areas/tokyo",
    headers={"x-api-key": os.environ["YADOZEI_API_KEY"]},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

キーはサーバー側で保管してください。 ブラウザやモバイルアプリに埋め込まないでください。CORSは開いていますが、公開されたキーは誰でもあなたの枠で使えてしまいます。

  • 存在しない・失効したキーは 401 unauthorized です。匿名の枠に切り替わることはありません。
  • 誤ったキーを繰り返し送ると、IPごとに毎分10回を超えた時点で 429 になります。
  • プランと料金は料金ページをご覧ください。

レート制限

プラン毎分枠リセット
匿名(キーなし・IPごと、IPv6は/64単位)101日 100回毎日 0:00(日本時間)
Standard30月 10,000回毎月1日 0:00(日本時間)
Pro60月 100,000回毎月1日 0:00(日本時間)
Vendor60月 1,000,000回毎月1日 0:00(日本時間)
  • 枠は /v1 の全エンドポイントで共通です。POST /v1/resolve、GET /v1/data は有料プラン限定です。
  • POST /v1/resolve は、住所の件数によらず1回の呼び出しを1リクエストと数えます。
  • 毎分の上限は時計の1分ごとにリセットされます。
  • キーの確認を通ったリクエストは、検証エラー(400)になったものも含めてすべて数えます。1日・1か月の枠を超えて断られたリクエストも数えます(毎分の上限で断られたものは数えません)。
  • 枠を超えたキーは、リセットまで 429 になります。
  • Retry-After と error.retryAfter は、最初に当たった上限がリセットされるまでの秒数です。待って再試行しても 429 なら、より長い枠を使い切っています。その応答の値に従ってください。

残りの枠を知る

キーの確認を通った応答(成功と、その後の 400・404・413)には、次のヘッダが付きます。キーなしは今日の枠、キーありは今月の枠です。毎分の上限はここには含まれません(超えると 429 と Retry-After)。

ヘッダ意味
X-RateLimit-Limit枠の上限。キーなしは1日、キーありは1か月の回数。
X-RateLimit-Remainingこの呼び出しを数えたあとの残り回数。
X-RateLimit-Reset枠がリセットされるまでの秒数(日本時間の0時、またはキーありは月初)。

エラー

エラーは共通の形式で返ります。error.code で分岐してください(message は人が読むためのものです)。

404
{
  "error": {
    "code": "unknown_area",
    "message": "Unknown area: Kyoto",
    "suggestions": [
      "kyoto"
    ]
  }
}
ステータスコード発生条件対処
400invalid_json本文が正しいJSONではないcontent-type: application/json で、正しいJSONの本文を送ってください。
400validation_error本文またはクエリが検証に失敗した(message に最初の問題を記載)パラメータ表の型と範囲を確認してください。未定義のキーと null は受け付けません。
401unauthorizedX-API-Key が存在しない、または失効しているキーを確認してください。匿名の枠に切り替わることはありません。
403forbidden有料プランのキーが必要なエンドポイント有料プランのキーを X-API-Key で送ってください。
404unknown_area+ suggestionsエリアIDが見つからないsuggestions(最大3件の候補ID)か GET /v1/areas から正しいIDを選んでください。
413payload_too_large本文が上限を超えている(/v1/calculate は 4KB、/v1/resolve は 128KB)余分なキーを除いてください(365泊分の nightlyRates は収まります)。/v1/resolve の住所は、複数の呼び出しに分けてください。
429rate_limited+ retryAfter毎分の上限、または1日・1か月の枠を超えたRetry-After(秒)待ってから再試行してください。再び 429 なら、より長い枠を使い切っています。
503unhealthy+ dataVersion/healthz のみ:データベースに書き込めない一時的な障害です。少し時間をおいて確認してください。

上の表以外の応答

  • CORSのプリフライト(OPTIONS)は 204 を返します。
  • 対応していないメソッドは、本文なしの 405 です。
  • 想定外の障害では、JSONでない 500 が返ることがあります。間隔を空けて再試行してください。
  • X-Data-Version ヘッダは、APIのJSON応答に付きます(これらの応答には付きません)。

データバージョンと変更フィード

すべてのJSON応答に X-Data-Version ヘッダが付き、使ったデータのバージョンがわかります(ブラウザの fetch からも読めます)。規則には施行日があり、施行予定の規則もデータに含まれるため、将来の日付はその日に適用される規則で計算されます。

変更の同期(APIキーが必要)

  1. 処理済みの最大の seq を保存します(最初は 0)。
  2. APIキー付きで GET /v1/changes?since_seq=<seq> を呼びます。seq がそれより大きい変更が古い順にすべて返ります。
  3. 各変更の areaIds を GET /v1/areas/{id}(有料プランなら /v1/data)で取り直してから、その seq を保存します。

匿名の呼び出しは、条件に合う変更のうち最新5件だけを返します(プレビュー用)。これで同期すると変更を取りこぼします。

メールで受け取りたい方は、改定アラートにご登録ください。

エンドポイント

POST /v1/calculate

キー任意#

1件の宿泊の宿泊税を計算します。各泊をその泊の日付の規則で課税し、泊ごとの結果、宿泊全体の合計、課税主体(県・市町村)別の内訳を返します。

パラメータ

名前型必須説明
X-API-Keyheaderstring任意APIキー。省略すると匿名(IPごとの無料枠)で処理されます。
areaIdbodystring必須エリアID(GET /v1/areas で取得。例:tokyo、kyoto、onna)。存在しないIDは 404 unknown_area(候補付き)。
ratePerNightbodyintegerいずれか1泊あたりの課税対象料金(円・消費税抜き)。1人あたり(適用される課税単位が per_unit の場合は1室/1棟あたり)の、素泊まり・サービス料込みの金額で、全泊にこの料金を使います。税込の金額は送らないでください。0–10,000,000
nightlyRatesbodyinteger[]いずれか泊ごとの料金(円・消費税抜き、ratePerNight と同じ単位)の配列。nightlyRates[0] がチェックイン日(date)の泊、nightlyRates[i] が date + i 日の泊で、泊数は配列の長さです。各泊は個別に課税されるため、平均せず実際の料金を送ってください。1〜365件、各 0–10,000,000
datebodystring (YYYY-MM-DD)任意チェックイン日(1泊目)。YYYY-MM-DD。2020-01-01 – 2030-12-31 · 既定値: 日本時間の今日
nightsbodyinteger任意泊数。nightlyRates と一緒に送る場合は、配列の長さと一致させてください。1–365 · 既定値: 1(nightlyRates を送った場合はその長さ)
guestsbodyinteger任意宿泊人数。適用される課税単位が per_person の場合、合計に掛けます。1–100 · 既定値: 1
basisbodystring任意課税単位の指定。variable の地域(「課税単位」を参照)でのみ使われ、ほかの地域では無視されます。per_person | per_unit · 既定値: per_unit

未定義のキーは受け付けません。任意の項目は省略できますが、null は送れません。本文は4KBまでです。

リクエスト

リクエスト
cURL
curl -X POST https://yadozei.jp/v1/calculate \
  -H 'content-type: application/json' \
  -d '{"areaId":"tokyo","ratePerNight":15000,"date":"2026-12-01","nights":2,"guests":2}'
JavaScript
const res = await fetch("https://yadozei.jp/v1/calculate", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    "areaId": "tokyo",
    "ratePerNight": 15000,
    "date": "2026-12-01",
    "nights": 2,
    "guests": 2
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import requests

res = requests.post(
    "https://yadozei.jp/v1/calculate",
    json={"areaId": "tokyo", "ratePerNight": 15000, "date": "2026-12-01", "nights": 2, "guests": 2},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "areaId": "tokyo",
  "areaName": {
    "en": "Tokyo",
    "ja": "東京都"
  },
  "currency": "JPY",
  "dateUsed": "2026-12-01",
  "basis": "per_person",
  "perNightTax": 200,
  "breakdown": [
    {
      "authority": {
        "en": "Tokyo Metropolitan Government",
        "ja": "東京都"
      },
      "amount": 200,
      "type": "fixed"
    }
  ],
  "nights": 2,
  "guests": 2,
  "nightly": [
    {
      "date": "2026-12-01",
      "ratePerNight": 15000,
      "perNightTax": 200,
      "breakdown": [
        {
          "authority": {
            "en": "Tokyo Metropolitan Government",
            "ja": "東京都"
          },
          "amount": 200,
          "type": "fixed"
        }
      ]
    },
    {
      "date": "2026-12-02",
      "ratePerNight": 15000,
      "perNightTax": 200,
      "breakdown": [
        {
          "authority": {
            "en": "Tokyo Metropolitan Government",
            "ja": "東京都"
          },
          "amount": 200,
          "type": "fixed"
        }
      ]
    }
  ],
  "stayTotal": {
    "perPerson": 400,
    "total": 800,
    "breakdown": [
      {
        "authority": {
          "en": "Tokyo Metropolitan Government",
          "ja": "東京都"
        },
        "amount": 800,
        "type": "fixed"
      }
    ]
  }
}

レスポンスの項目

項目型説明
areaIdstring計算したエリアのID。
areaName{ en, ja }エリア名(英語・日本語)。
currency"JPY"常に JPY。
dateUsedYYYY-MM-DDチェックイン日(送った date。省略時は日本時間の今日)。
basis"per_person" | "per_unit"適用された課税単位。per_unit の場合、金額は1室/1棟あたりです。
nightsinteger泊数。
guestsinteger人数。
nightly[]array泊ごとの結果:date(その泊の日付)、ratePerNight(その泊の税抜料金)、perNightTax(1人または1単位あたり)、breakdown(課税主体別)。
stayTotal.perPersoninteger全泊の合計(1人あたり。per_unit の場合は1単位あたり)。
stayTotal.totalinteger請求する合計額。per_person の場合は人数を掛けた額です。
stayTotal.breakdown[]array課税主体(県・市町村)ごとの宿泊全体の合計で、total と一致します。type は最後の泊の規則の方式です。泊ごとの方式は nightly[].breakdown を見てください。
perNightTax, breakdowncompat互換用:1泊目の値のみ。宿泊全体には stayTotal を使ってください。

エラー: invalid_jsonvalidation_errorunauthorizedunknown_areapayload_too_largerate_limited

GET /v1/areas

キー任意#

対応している全エリアの一覧(ID、名称、都道府県、行政区分、課税単位)を返します。

パラメータ

名前型必須説明
X-API-Keyheaderstring任意APIキー。省略すると匿名(IPごとの無料枠)で処理されます。

リクエスト

リクエスト
cURL
curl https://yadozei.jp/v1/areas
JavaScript
const res = await fetch("https://yadozei.jp/v1/areas");
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import requests

res = requests.get(
    "https://yadozei.jp/v1/areas",
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "areas": [
    {
      "id": "tokyo",
      "name": {
        "en": "Tokyo",
        "ja": "東京都"
      },
      "prefecture": {
        "en": "Tokyo",
        "ja": "東京都"
      },
      "level": "prefecture",
      "taxBase": "per_person"
    },
    {
      "id": "osaka",
      "name": {
        "en": "Osaka",
        "ja": "大阪府"
      },
      "prefecture": {
        "en": "Osaka",
        "ja": "大阪府"
      },
      "level": "prefecture",
      "taxBase": "per_person"
    },
    {
      "id": "kyoto",
      "name": {
        "en": "Kyoto",
        "ja": "京都市"
      },
      "prefecture": {
        "en": "Kyoto",
        "ja": "京都府"
      },
      "level": "city",
      "taxBase": "per_person"
    }
  ]
}
全66件中3件を表示

エラー: unauthorizedrate_limited

GET /v1/areas/{id}

キー任意#

1エリアの全規則(施行日・終了日、税額の区分または税率、上限、免税点)、免税・課税免除の項目、公式の出典URLを返します。

パラメータ

名前型必須説明
X-API-Keyheaderstring任意APIキー。省略すると匿名(IPごとの無料枠)で処理されます。
idpathstring必須エリアID。

リクエスト

リクエスト
cURL
curl https://yadozei.jp/v1/areas/tokyo
JavaScript
const res = await fetch("https://yadozei.jp/v1/areas/tokyo");
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import requests

res = requests.get(
    "https://yadozei.jp/v1/areas/tokyo",
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "id": "tokyo",
  "name": {
    "en": "Tokyo",
    "ja": "東京都"
  },
  "prefecture": {
    "en": "Tokyo",
    "ja": "東京都"
  },
  "level": "prefecture",
  "taxBase": "per_person",
  "rules": [
    {
      "authority": {
        "en": "Tokyo Metropolitan Government",
        "ja": "東京都"
      },
      "effectiveFrom": "2002-10-01",
      "effectiveUntil": "2027-03-31",
      "type": "fixed",
      "tiers": [
        {
          "min": 0,
          "max": 9999,
          "amount": 0
        },
        {
          "min": 10000,
          "max": 14999,
          "amount": 100
        },
        {
          "min": 15000,
          "max": null,
          "amount": 200
        }
      ]
    },
    {
      "authority": {
        "en": "Tokyo Metropolitan Government",
        "ja": "東京都"
      },
      "effectiveFrom": "2027-04-01",
      "effectiveUntil": null,
      "type": "percentage",
      "rate": 0.03,
      "cap": null,
      "threshold": 13000
    }
  ],
  "exemptions": [
    "school_trips"
  ],
  "notes": "Revision consented by the Minister of Internal Affairs 2026-06-30, in effect from 2027-04-01: flat 3% of the nightly charge (no cap), exempt threshold raised to stays under 13,000 yen per person per night, and hostels (kan'i-shukusho) / minpaku added to the scope (their operators register as collection agents from 2026-07-01).",
  "source": "https://www.tax.metro.tokyo.lg.jp/kazei/leisure/shuk"
}

エラー: unauthorizedunknown_arearate_limited

GET /v1/resolve

キー任意#

住所から、その物件の課税エリア(areaId)を判定します。市町村が独自に課税しているか、都道府県全域の課税か、宿泊税がないかを、都道府県と市町村から決めます。

パラメータ

名前型必須説明
X-API-Keyheaderstring任意APIキー。省略すると匿名(IPごとの無料枠)で処理されます。
addressquerystringいずれか住所。都道府県から書いてください(例:沖縄県国頭郡恩納村…)。郵便番号、先頭の「日本」、全角文字、空白はそのままで構いません。200文字まで
prefecturequerystringいずれかaddress の代わりに送る都道府県名(例:沖縄県)。municipality と一緒に送ります。200文字まで
municipalityquerystringいずれかaddress の代わりに送る市区町村名(例:国頭郡恩納村、那覇市)。200文字まで

address か、prefecture と municipality の組み合わせで送ってください(両方は送れません)。住所は都道府県から書いてください。都道府県がないと、データ内に一つしかない市町村名しか判定できません。

リクエスト

リクエスト
cURL
curl -G https://yadozei.jp/v1/resolve \
  --data-urlencode 'address=沖縄県国頭郡恩納村字恩納2451'
JavaScript
const res = await fetch("https://yadozei.jp/v1/resolve?" + new URLSearchParams({"address":"沖縄県国頭郡恩納村字恩納2451"}));
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import requests

res = requests.get(
    "https://yadozei.jp/v1/resolve",
    params={"address": "沖縄県国頭郡恩納村字恩納2451"},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "input": "沖縄県国頭郡恩納村字恩納2451",
  "areaId": "onna",
  "match": "municipal",
  "areaName": {
    "ja": "恩納村",
    "en": "Onna"
  },
  "prefecture": "沖縄県",
  "municipality": "恩納村"
}

レスポンスの項目

項目型説明
inputstring送った住所(そのまま)。prefecture と municipality で送った場合は、その二つをつなげたものです。
areaIdstring | nullPOST /v1/calculate に渡すエリアID。宿泊税がない場合と判定できない場合は null です。
match"municipal" | "prefecture" | "no_tax" | "unresolved"判定の種類(下の表)。
areaName{ en, ja }エリア名。areaId があるときだけ含まれます。
prefecturestring見つかった都道府県(日本語)。見つからなかったときは含まれません。
municipalitystring | null一致した市町村エリアの名前。市町村エリアに一致しなかったときは null です。
messagestringunresolved のときだけ:住所に足りないもの(英語)。

match の値

値意味
municipal独自に課税している市町村です。areaId はその市町村のエリアで、都道府県の税がかかる場合はそれも含みます(例:沖縄県国頭郡恩納村 → onna)。
prefecture都道府県全域の課税です。その市町村には独自のエリアがありません(例:沖縄県那覇市 → okinawa_other、東京都新宿区 → tokyo)。
no_tax宿泊税はかかりません。都道府県に全域の課税がなく、市町村も課税していません(例:京都府宇治市)。areaId は null です。
unresolved判定できませんでした。都道府県が見つからない場合(都道府県がなくても、データ内で一つしかない市町村名なら判定します)と、市町村で結果が変わる都道府県で市町村がない場合です。message に従って住所を補ってください。

エラー: validation_errorunauthorizedrate_limited

POST /v1/resolve

有料キー必須#

最大100件の住所をまとめて判定し、送った順に結果を返します。件数によらず1回の呼び出しを1リクエストと数えます。有料プラン限定です。

パラメータ

名前型必須説明
X-API-Keyheaderstring必須有料プランのAPIキー(必須)。
addressesbodystring[]必須住所の配列。それぞれ GET の address と同じように書きます。1〜100件、各200文字まで

未定義のキーは受け付けません。本文は128KBまでです。results は送った順に並び、各要素は GET /v1/resolve の応答と同じ形です。

リクエスト

リクエスト
cURL
curl -X POST https://yadozei.jp/v1/resolve \
  -H 'content-type: application/json' \
  -H "x-api-key: $YADOZEI_API_KEY" \
  -d '{"addresses":["沖縄県国頭郡恩納村字恩納2451","沖縄県那覇市泉崎1-2-2","京都府宇治市宇治琵琶33","那覇市泉崎1-2-2"]}'
JavaScript
const res = await fetch("https://yadozei.jp/v1/resolve", {
  method: "POST",
  headers: { "content-type": "application/json", "x-api-key": process.env.YADOZEI_API_KEY },
  body: JSON.stringify({
    "addresses": [
      "沖縄県国頭郡恩納村字恩納2451",
      "沖縄県那覇市泉崎1-2-2",
      "京都府宇治市宇治琵琶33",
      "那覇市泉崎1-2-2"
    ]
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import os
import requests

res = requests.post(
    "https://yadozei.jp/v1/resolve",
    json={"addresses": ["沖縄県国頭郡恩納村字恩納2451", "沖縄県那覇市泉崎1-2-2", "京都府宇治市宇治琵琶33", "那覇市泉崎1-2-2"]},
    headers={"x-api-key": os.environ["YADOZEI_API_KEY"]},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "results": [
    {
      "input": "沖縄県国頭郡恩納村字恩納2451",
      "areaId": "onna",
      "match": "municipal",
      "areaName": {
        "ja": "恩納村",
        "en": "Onna"
      },
      "prefecture": "沖縄県",
      "municipality": "恩納村"
    },
    {
      "input": "沖縄県那覇市泉崎1-2-2",
      "areaId": "okinawa_other",
      "match": "prefecture",
      "areaName": {
        "ja": "沖縄県(その他地域)",
        "en": "Okinawa Prefecture (other areas)"
      },
      "prefecture": "沖縄県",
      "municipality": null
    },
    {
      "input": "京都府宇治市宇治琵琶33",
      "areaId": null,
      "match": "no_tax",
      "prefecture": "京都府",
      "municipality": null
    },
    {
      "input": "那覇市泉崎1-2-2",
      "areaId": null,
      "match": "unresolved",
      "message": "Could not identify the prefecture: start the address with it (e.g. 沖縄県那覇市…)."
    }
  ]
}

エラー: invalid_jsonvalidation_errorunauthorizedforbiddenpayload_too_largerate_limited

GET /v1/changes

キー任意#

データセットの変更を、since_seq より後のものから古い順に返します。同期にはAPIキーが必要です(匿名では最新5件のみ)。

パラメータ

名前型必須説明
X-API-Keyheaderstring任意APIキー。省略すると匿名(IPごとの無料枠)で処理されます。
since_seqqueryinteger任意この seq より大きいものを返します。処理済みの最大の seq を保存して渡してください。既定値: 0

リクエスト

リクエスト
cURL
curl 'https://yadozei.jp/v1/changes?since_seq=5' \
  -H "x-api-key: $YADOZEI_API_KEY"
JavaScript
const res = await fetch("https://yadozei.jp/v1/changes?since_seq=5", {
  headers: { "x-api-key": process.env.YADOZEI_API_KEY },
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import os
import requests

res = requests.get(
    "https://yadozei.jp/v1/changes",
    params={"since_seq": 5},
    headers={"x-api-key": os.environ["YADOZEI_API_KEY"]},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "changes": [
    {
      "seq": 6,
      "releasedAt": "2026-09-20",
      "dataVersion": "2026.09",
      "areaIds": [
        "kutchan",
        "niseko"
      ],
      "type": "corrected",
      "summary": {
        "en": "Notes clarified, no rate or date change: in Kutchan, and in Niseko from 2026-11-01, the Hokkaido prefectural tiers legally still apply but the town tax is 3% minus the prefectural amount, collected as one 3% charge by the town. The dataset keeps a single 3% town rule, so the breakdown does not split out the prefectural share.",
        "ja": "注記の明確化(税率・施行日に変更なし):倶知安町、および2026年11月1日以降のニセコ町では道税の定額区分が法的に存続するが、町税=3%-道税額として町が3%を一括徴収する。データは単一の3%町ルールを維持し、内訳は道税分を分離しない。"
      },
      "effectiveFrom": null,
      "sources": [
        "https://www.town.kutchan.hokkaido.jp/town_administration/AccommodationTax/3108/",
        "https://www.pref.hokkaido.lg.jp/kz/kkd/191976.html"
      ]
    }
  ]
}
全3件中1件を表示

エラー: validation_errorunauthorizedrate_limited

GET /v1/data

有料キー必須#

全エリアの完全なデータ(全規則)とデータバージョンを一度に返します。有料プラン限定です。

パラメータ

名前型必須説明
X-API-Keyheaderstring必須有料プランのAPIキー(必須)。

リクエスト

リクエスト
cURL
curl https://yadozei.jp/v1/data \
  -H "x-api-key: $YADOZEI_API_KEY"
JavaScript
const res = await fetch("https://yadozei.jp/v1/data", {
  headers: { "x-api-key": process.env.YADOZEI_API_KEY },
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import os
import requests

res = requests.get(
    "https://yadozei.jp/v1/data",
    headers={"x-api-key": os.environ["YADOZEI_API_KEY"]},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "dataVersion": "2026.10",
  "areas": [
    {
      "id": "tokyo",
      "name": {
        "en": "Tokyo",
        "ja": "東京都"
      },
      "prefecture": {
        "en": "Tokyo",
        "ja": "東京都"
      },
      "level": "prefecture",
      "taxBase": "per_person",
      "rules": [
        {
          "authority": {
            "en": "Tokyo Metropolitan Government",
            "ja": "東京都"
          },
          "effectiveFrom": "2002-10-01",
          "effectiveUntil": "2027-03-31",
          "type": "fixed",
          "tiers": [
            {
              "min": 0,
              "max": 9999,
              "amount": 0
            },
            {
              "min": 10000,
              "max": 14999,
              "amount": 100
            },
            {
              "min": 15000,
              "max": null,
              "amount": 200
            }
          ]
        },
        {
          "authority": {
            "en": "Tokyo Metropolitan Government",
            "ja": "東京都"
          },
          "effectiveFrom": "2027-04-01",
          "effectiveUntil": null,
          "type": "percentage",
          "rate": 0.03,
          "cap": null,
          "threshold": 13000
        }
      ],
      "exemptions": [
        "school_trips"
      ],
      "notes": "Revision consented by the Minister of Internal Affairs 2026-06-30, in effect from 2027-04-01: flat 3% of the nightly charge (no cap), exempt threshold raised to stays under 13,000 yen per person per night, and hostels (kan'i-shukusho) / minpaku added to the scope (their operators register as collection agents from 2026-07-01).",
      "source": "https://www.tax.metro.tokyo.lg.jp/kazei/leisure/shuk"
    }
  ]
}
全66件中1件を表示

エラー: unauthorizedforbiddenrate_limited

GET /healthz

キー不要#

稼働状況とデータバージョンを返します。レート制限の対象外なので、監視にお使いください。

リクエスト

リクエスト
cURL
curl https://yadozei.jp/healthz
JavaScript
const res = await fetch("https://yadozei.jp/healthz");
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import requests

res = requests.get(
    "https://yadozei.jp/healthz",
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")

レスポンス

200 OK
{
  "status": "ok",
  "dataVersion": "2026.10",
  "db": "ok"
}

エラー: unhealthy

計算の考え方

料金(1泊ごと・税抜)

  • 料金は1泊ごとの金額です。ratePerNight は全泊に同じ料金を使い、nightlyRates は1泊目から1日ずつ、各日付の泊の料金を並べます(nightlyRates[0] がチェックイン日 date の泊、nightlyRates[i] が date + i 日の泊)。予約の総額や平均は送らないでください。
  • 料金は消費税抜きの金額です(消費税・地方消費税の10%を含めません)。食事代は除き(素泊まり)、サービス料は含めます。
  • 単位は1人あたりです。per_unit が適用される場合は1室/1棟あたりになります(課税単位)。

税込の料金を送ると:京都市、1泊

送った料金税額
¥19,000(税抜・正しい)¥400
¥20,900(税込・誤り)¥1,000

税込の料金を送ると、区分が上がって税額が過大になることがあります。税込の金額しかない場合は、税を加えたときと同じ端数処理で、整数演算で本体価格に戻してください。浮動小数点の割り算は1円ずれることがあり、Math.floor(6600 / 1.1) は 5,999 になります。京都市では¥400の泊が¥200になります。

泊ごとの課税

宿泊税は1人1泊ごとに課税されます。APIは各泊をその泊の日付の規則で計算して合計するため、課税開始日や税率改定をまたぐ宿泊も、1回の呼び出しで正しく計算できます。

課税開始をまたぐ:恩納村、2027-01-30から4泊

泊日付料金(税抜)税額
1泊目¥10,500¥0
2泊目¥10,500¥0
3泊目¥10,500¥200
4泊目¥10,500¥200

課税は2027-02-01の泊から始まるため、それより前の泊は0円です。合計¥400。

料金が泊ごとに違う:nightlyRates

リクエスト
cURL
curl -X POST https://yadozei.jp/v1/calculate \
  -H 'content-type: application/json' \
  -d '{"areaId":"kyoto","nightlyRates":[18000,22000,51000],"date":"2026-12-01"}'
JavaScript
const res = await fetch("https://yadozei.jp/v1/calculate", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    "areaId": "kyoto",
    "nightlyRates": [
      18000,
      22000,
      51000
    ],
    "date": "2026-12-01"
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${res.status} ${data.error.code}: ${data.error.message}`);
Python
import requests

res = requests.post(
    "https://yadozei.jp/v1/calculate",
    json={"areaId": "kyoto", "nightlyRates": [18000, 22000, 51000], "date": "2026-12-01"},
    timeout=10,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{res.status_code} {data['error']['code']}: {data['error']['message']}")
泊日付料金(税抜)税額
1泊目¥18,000¥400
2泊目¥22,000¥1,000
3泊目¥51,000¥4,000

各泊をその料金の区分で課税するため、合計は¥5,400です。平均料金(¥30,333)を ratePerNight で送ると¥3,000になり、正しくありません。

宿泊中に規則が変わる:東京都、2027-03-31から2泊

泊日付料金(税抜)方式税額
1泊目¥20,000fixed¥200
2泊目¥20,000percentage¥600

泊ごとに方式が変わります(fixed → percentage)。stayTotal.breakdown の type は最後の泊の方式を示すため、泊ごとの方式は nightly[].breakdown で確認してください。

課税単位(basis)

各エリアの taxBase が、料金と税額の単位を決めます。per_unit が適用される場合、料金の項目と stayTotal.perPerson は1室/1棟あたりの意味になります。

taxBase意味対象エリア
per_person1人1泊ごとに課税。合計に人数を掛けます。全国64エリア
per_unit1室/1棟ごとに課税。人数は掛けません。料金も1室/1棟あたりで送ります。現在なし
variable施設の料金設定による。basis で per_person / per_unit を指定します(既定は per_unit)。倶知安町、山形市

日付と日本時間

  • 日付はすべて日本の暦日です。date を省略すると、日本時間の今日(UTCではなく)になります。
  • date はチェックイン日で、1泊目の日付です。n泊目は date + (n − 1) 日です。
  • 受け付けるチェックイン日は 2020-01-01〜2030-12-31 です。2泊目以降はこの範囲を越えてもかまいません。
  • データは各エリアの最初に記録された規則から始まります(/v1/areas/{id} の effectiveFrom)。規則がない泊は0円・内訳なしになりますが、過去の日付では「税がかからなかった」ことの証明にはなりません。
  • レート制限の枠も日本時間でリセットされます。

本番導入の準備はできましたか?

システム名と月間の想定リクエスト数をお知らせください。お見積りとAPIキーをお送りします。