はじめに
Zaim API と Zaim Developers Center は 2026-12-07 に提供終了します。ドキュメントと実際の動きの差は終了後に確かめられなくなるため、消える前に読み取り系と書き込み系のエンドポイントを叩いて記録しました。結論として、手入力した家計簿データと一覧情報は取得できますが、ドキュメントどおりに動かない箇所が複数あります。
Zaim API は、家計簿アプリ Zaim のデータを外部のプログラムから読み書きするための API です。公式のお知らせによると、新規アプリの登録は 2026-11-09 に締め切られ、後継の API や代替手段は用意されません。今から新しく使い始める人に向けた手順ではなく、検証結果の記録として読んでください。
本記事のまとめ
- 取得できるのは手入力の家計簿データと、カテゴリ・ジャンル・口座・通貨の一覧である。口座やカードの連携データは取得できない。
limitとpageは無視され、1 回のリクエストで条件に合う全件が返る。date=2026/11/01を送ると、エラーなしで2025-11-30として保存された。- BigQuery へのロードは通るが、レコードの種類に関係しない ID の列は NULL ではなく
0で入るので、絞り込みの条件に注意が要る。

Zaim API でできること・できないこと
Zaim API でできるのは、手入力した家計簿レコードの読み書きと、分類や口座の一覧の取得です。読み取り系の 9 本は、実際に叩いてすべて 200 が返りました。表の mode は、支出(payment)、収入(income)、振替(transfer)の区分です。
| やりたいこと | 可否 | 補足 |
| 手入力の家計簿レコードを取得する | できる | GET /v2/home/money |
| 支出・収入・振替を登録、更新、削除する | できる(登録は支出と収入、更新は支出、削除は収入で確認。振替を含むほかの組み合わせは未確認) | mode を含むパスで通る |
| カテゴリ、ジャンル、口座、通貨の一覧を取得する | できる | ドキュメント上、既定の一覧は認証なしで取得できる |
| 口座やカードの連携データを取得する | できない | ドキュメント上も手入力のデータだけが対象 |
| 残高を取得する | できない | 該当するエンドポイントが無い |
| 口座、カテゴリ、ジャンルを作成する | できない | 該当するエンドポイントが無い |
私の家計簿の件数の変化も、これと合っています。連携中心の運用に切り替えた時期を境に、API で取得できる件数が大きく減りました。
アプリの登録に審査はなく、フォームを保存するとその場で登録されました。ローカルのスクリプトから試すため、サービス種は「クライアントアプリ」を選んでいます。ドキュメントによると、アクセスレベルの「永続的に許可する」を付けないと権限は 24 時間で失効します。検証では 3 つとも付けました。認証の仕組みは OAuth 1.0a で、詳しい流れはOAuth 1.0a と 2.0 を実装で比べた記事で扱います。

保存すると、次のようにアプリが一覧に追加されました。

登録した内容は次のとおりです。

ドキュメントに書いてあるのに効かないパラメータ
最も影響が大きいのは、limit と page が効かず、ページングの仕組みが実際には無いことです。Zaim Developers Center の API ドキュメント(2018-07-04 が最終更新)では、GET /v2/home/money のパラメータとして次のように説明されています。
page: number of current page (default 1)
limit: number of items per page (default 20, max 100)この記述なら、未指定で 20 件、limit=5 で 5 件が返り、page=2 で次のページへ進むはずです。実際には、どの指定でも同じ件数が返りました。ほかのパラメータも含め、記述と実際の動きが違ったものは次のとおりです。
| パラメータ | ドキュメント | 実測の結果 |
mapping(GET) | 必須 | 付けなくても 200 で、結果も同じ |
limit | 既定 20、最大 100 | 5、100、101、未指定のどれでも同じ件数 |
page | 既定 1 | page=2 でも同じ件数 |
mapping(PUT) | 必須 | 外しても 200 |
id(DELETE) | 必須 | 外しても 200。パスに含まれている |
date(income) | 過去 3 か月 | 5 年 10 か月前も 3 年以上先も 200 |
一方で、絞り込みは正しく動きます。全件を手元で集計し、API の結果と突き合わせたところ、mode、category_id、genre_id の件数はすべて一致しました。start_date と end_date、order、group_by も効いています。
取得処理は、期間で絞って 1 回呼ぶだけで足ります。検証で使ったコードは次のとおりです。署名を作る authorization_header の中身は省略しています。
# limit / page は API に無視され、1 リクエストで全件返るのでページングしない。
# mapping も no-op だが、ドキュメントが必須としているので送る。
params = {"mapping": "1", "start_date": start_date, "end_date": end_date}
req = urllib.request.Request(f"{MONEY_URL}?{urllib.parse.urlencode(params)}")
req.add_header("Authorization", authorization_header(MONEY_URL, params, cred))
with urllib.request.urlopen(req, timeout=60) as res:
return json.load(res)["money"]ドキュメントに無いのに使えるもの
逆に、ドキュメントに記載が無くても動く項目が 4 種類ありました。
GET /v2/home/moneyのaccount_idは、口座で正しく絞り込める。手元の集計と件数が一致した。POSTのreceipt_idは入力できる。999999を送ると、そのまま保存された。PUTのnameとplaceは、パラメータの一覧に無いが更新に反映される。- レスポンスに未記載のキーがある。
activeとcreated(ユーザー情報)、place_uid(家計簿レコード)、original_money_ids(振替のレコード)の 4 つである。
未記載の項目は、提供元が動作を約束していないものです。検証の記録としては残しますが、仕様として頼るものではありません。なお、20 回の連続リクエストでレート制限は観測されませんでした。上限が無いという意味ではなく、この回数では出なかったという結果です。
エラーにならず別の日付で保存される
この検証で最も注意が必要なのは、日付の形式が違っても拒否されず、別の日付で保存されることです。1 円のテストレコードで試した結果は次のとおりです。
POST /v2/home/money/income に date=2026/11/01 を送信
-> 200
-> 保存された日付は 2025-11-30原因は確認できていません。月と日が 0 として扱われると計算上はこの日付になりますが、API の内部は見えないため、推測にとどまります。
200 が返るので、呼び出し側は失敗に気づけません。登録する前に、自分のコードで YYYY-MM-DD の形式を確かめる必要があります。取得するときも範囲外の日付が混ざらないかを確かめるため、検証のスクリプトには次の処理を入れました。
# API は日付の範囲を検証しないので、範囲外が混ざっていないかをここで確かめる。
outside = [r for r in records if not args.start_date <= r["date"] <= args.end_date]
if outside:
print(f"エラー: 範囲外の日付が {len(outside)} 件ある", file=sys.stderr)
return 1もう 1 つ、エラーの内容が原因と合わない例があります。ドキュメントの索引には更新と削除のパスが /v2/home/money/:id と載っていますが、ここを呼ぶと PUT は 404、DELETE は 401 を返しました。401 の本文は次のとおりで、権限の不足に見えます。
This consumer key does not have a permission for the action.正しいパスは、ドキュメント本文にある /v2/home/money/payment/:id のように mode を含む形です。こちらは 200 で通りました。この 401 が出たら、権限を調べる前にパスを確かめてください。
BigQuery へロードして分かったこと
取得したレコードは BigQuery へそのままロードできますが、mode に関係しない ID の列は NULL ではなく 0 で入ります。分析できる形になるかを確かめるため、取得結果を JSON Lines(1 行に 1 レコードの JSON)で Cloud Storage へ置き、スキーマの自動検出でロードしました。
bq --project_id=PROJECT_ID --location=asia-northeast1 load \
--replace --autodetect --source_format=NEWLINE_DELIMITED_JSON \
DATASET.money gs://BUCKET_NAME/money/money.jsonlロード後の件数は API の返り件数と一致しました。スキーマの自動検出は 18 列を作りました。date は DATE、created は TIMESTAMP、振替にしか無い original_money_ids は INTEGER REPEATED と判定されています。

0 で埋まる列は mode によって次のように分かれました。ロードした期間だけの結果で、全期間では確認していません。
| mode | 0 で埋まる列 |
payment | from_account_id、to_account_id |
income | from_account_id、to_account_id、多くの genre_id |
transfer | category_id、genre_id |
これらの列を IS NULL で絞っても、該当なしのレコードは見つかりません。0 と比較してください。
検証後はアプリとデータを削除した
検証を終えたあと、登録したアプリを削除すると、access token は使えなくなりました。削除後に GET /v2/home/user/verify を呼ぶと、401 が返っています。

公式のお知らせでは、API で取得して保存したデータと認証情報の削除期限が 2027-01-07 とされています。アプリのほかに、検証で作ったものを次のように片付けました。
- テストレコードは削除し、全件を取得し直して残っていないことを確かめた。
- BigQuery のデータセットと Cloud Storage のバケットを削除した。どちらも削除後 7 日間は復元できる状態が残り、BigQuery にはさらに Google 側の保持期間が 7 日ある。
- 手元に保存した認証情報と取得データを削除した。
まとめ
Zaim API で確実にできるのは、手入力の家計簿レコードと一覧の取得で、ページングは要りません。実測で分かった注意点は次のとおりです。
- 連携データと残高は取得できない。
- 日付は送る前に形式を確かめる。不正な形式でも 200 が返り、別の日付で保存される。
- BigQuery では、mode に関係しない ID の列を
0との比較で判定する。
API を使っている場合は、提供終了までにデータの扱いを確認してください。提供の終了は順次進むとされているので、日程と手順は最新のお知らせで確認してください。

