API Documentation

Base URL: https://yadozei.jp/v1. JSON only. Every response carries an X-Data-Version header.

Auth & rate limits

Send your key in the X-API-Key header. Anonymous: 100 req/day + 10 req/min (per IP). Pro/Vendor: monthly quota (100k / 1M) + 60 req/min. /v1/data is paid-only. Over the limit returns 429 with Retry-After.

GET /v1/areas

curl https://yadozei.jp/v1/areas
const res = await fetch("https://yadozei.jp/v1/areas");
const { areas } = await res.json(); // [{ id, name, prefecture, level, taxBase }]

GET /v1/areas/:id

curl https://yadozei.jp/v1/areas/kyoto

POST /v1/calculate

Body: { areaId, ratePerNight, date?, nights?, guests?, basis? } (body ≤ 1 KB).

curl -X POST https://yadozei.jp/v1/calculate \
  -H 'content-type: application/json' \
  -d '{"areaId":"tokyo","ratePerNight":15000,"date":"2026-06-13","guests":2}'
// { perNightTax: 200, basis: "per_person",
//   stayTotal: { perPerson: 200, total: 400 }, breakdown: [...] }

basis (pricing unit)

basis says whether the tax is per person or per room/unit. per_person areas multiply by guests; per_unit do not. variable areas (Kutchan) depend on how the facility prices, so pass an optional basis ("per_person"|"per_unit", default per_unit). The response basis reflects what was applied.

GET /v1/changes?since_seq=N

Returns changes after seq, ascending. Anonymous callers see only the latest 5.

curl 'https://yadozei.jp/v1/changes?since_seq=0' -H 'x-api-key: yz_...'

GET /v1/data (paid)

curl https://yadozei.jp/v1/data -H 'x-api-key: yz_...'
// { dataVersion: "2026.06", areas: [ ...full dataset... ] }

GET /healthz

curl https://yadozei.jp/healthz // { status: "ok", dataVersion, db: "ok" }

Errors

Shape: { "error": { "code": "...", "message": "..." } }. Codes: 400 (validation) / 401 (key) / 403 (tier) / 404 (area, with suggestions) / 413 (body too large) / 429 (limits).