この記事でできること
前回の記事「Claude Codeで銀行APIを実行する(準備編)」で、GMOあおぞらネット銀行のAPI実験場 sunabar(スナバー)の残高照会を、curl と Claude Code の両方から実行しました。今回はその続きです。仮想の口座に10,000円を入金し、振込APIで1,000円を別の仮想口座へ動かして、承認から完了確認までを通します。
読み終えると、銀行の振込が「受付 → 承認 → 実行」の3つのステップで動くことと、それぞれのステップでAPIが何を返すかが、実行結果つきで分かります。
- 対象読者:銀行の振込APIの「受付 → 承認 → 実行」の流れを動かしてみたい方/Claude Code に銀行操作を任せるとどこで止まるか見てみたい方
- 前提:前回の記事のとおり、sunabar のアクセストークンが手元にあること
- かかるお金:0円。動かすのは仮想のお金で、振込手数料も0円でした
- 試した日と環境:2026年8月29日〜30日・Claude Code 2.1.226
先に3つだけ
| # | 押さえること | 中身 |
|---|---|---|
| 1 | HTTP 201 は「受け付けた」であって「振り込んだ」ではない | 振込依頼APIが201を返しても、残高はまだ1円も動いていません。承認して初めてお金が動きます(3章・6章) |
| 2 | 承認しないまま指定日を過ぎると、振込依頼は消える | 照会APIにもヒットしなくなりました。実測です(4章) |
| 3 | Claude Code は振込の送信を実行しない | 振込コマンドの実行前に止まりました。リクエストのJSONとcurlコマンドは Claude Code が作り、送信は私がターミナルで実行しました(3章) |
使用する仮想口座
| # | 口座 | 役割 |
|---|---|---|
| 1 | 個人の仮想口座 | 振込元。入出金シミュレーターで10,000円を入れます |
| 2 | 法人の仮想口座 | 振込先。sunabar は法人の仮想口座も一緒に配ってくれます |
2つの口座の支店・口座番号・名義は、sunabarポータルの「sunabarサービスサイトで使える銀行口座」の画面にまとまって載っています。この記事ではあとで振込先の情報として使います。値そのものは仮想のものですが、銀行の公式ページが伏せているのに合わせて、この記事でも伏せます。
この記事の流れ
1. 仮想のお金を入金する
sunabarポータルのメニューにある「入出金シミュレーター」を開き、対象の口座(今回は個人の仮想口座)を選んで、ATM入金で10,000円を入れました。画面で金額を入れて実行するだけです。
残高照会で映ったかを確かめます(APIは前回と同じです)。
curl -X GET "https://api.sunabar.gmo-aozora.com/personal/v1/accounts/balances?accountId=<口座のID>" \
-H "accept: application/json;charset=UTF-8" \
-H "x-access-token: $TOKEN"
| # | 項目 | 入金前 | 入金後 |
|---|---|---|---|
| 1 | balance | 0 | 10000 |
| 2 | withdrawableAmount | 0 | 10000 |
| 3 | previousDayBalance | 0 | 0 |
入れた10,000円がそのまま映りました。previousDayBalance(前日残高)が0のままなのは、入金したのが当日だからです。
2. 入出金明細を見る
その入金が明細にどう記録されるかを見ます。入出金明細照会は今回初めて実行するAPIです。
curl -X GET "https://api.sunabar.gmo-aozora.com/personal/v1/accounts/transactions?accountId=<口座のID>&dateFrom=2026-08-28&dateTo=2026-08-29" \
-H "accept: application/json;charset=UTF-8" \
-H "x-access-token: $TOKEN"
返ってきた明細は1件でした。
| # | 項目 | 値 |
|---|---|---|
| 1 | transactionDate | 2026-08-29 |
| 2 | amount | "10000" |
| 3 | remarks | ATM セブン |
| 4 | balance(取引後残高) | "10000" |
気づいたことが2つあります。
- remarks が「ATM セブン」。シミュレーターのATM入金は、明細の上ではセブン銀行のATMから入金した体で記録されます。仮想でも、明細の見た目は本物と同じ形です
-
金額や残高が、数値ではなく文字列で返ります(
"10000")。残高照会の balance も同じでした。プログラムで金額を計算するときは、数値への変換が要ります
3. 振込依頼を送る
リクエストの形
個人の口座から法人の口座へ、1,000円を送ります。振込依頼API(POST /personal/v1/transfer/request)に渡すJSONはこの形です。
{
"accountId": "<振込元の口座ID>",
"remitterName": "<振込元の名義(カナ)>",
"transferDesignatedDate": "2026-08-30",
"transfers": [
{
"itemId": "1",
"transferAmount": "1000",
"beneficiaryBankCode": "0310",
"beneficiaryBranchCode": "<振込先の支店コード>",
"accountTypeCode": "1",
"accountNumber": "<振込先の口座番号>",
"beneficiaryName": "<振込先の名義(カナ)>"
}
]
}
埋める値はこう集めました。
| # | 値 | どこから取るか |
|---|---|---|
| 1 | accountId(振込元) | 前回の口座一覧照会の返り値 |
| 2 | remitterName(振込元の名義カナ) | 口座一覧照会の accountNameKana。ポータルの「sunabarサービスサイトで使える銀行口座」画面にも載っています |
| 3 | 振込先の支店コード・口座番号・名義カナ | 同じくポータルの「sunabarサービスサイトで使える銀行口座」画面。法人の仮想口座の分もここにあります |
| 4 | beneficiaryBankCode | 0310 = GMOあおぞらネット銀行の銀行コード。今回は同じ銀行あての振込です |
| 5 | accountTypeCode | 口座種別。普通預金の 1 を入れました |
| 6 | itemId | transfers 配列の中の連番。1件目なので "1" |
金額はここでも文字列で渡します。transferDesignatedDate は振込の指定日で、当日を指定できました(実測)。あとで書く理由(4章)から、当日を指定して当日中に承認まで進めるのがよいです。
Claude Code が送信を止めた
ここで想定していなかったことが起きました。Claude Code に「このJSONで振込依頼を送って」と頼んだところ、curl を実行する手前で止まりました。
止まり方には特徴がありました。ふだん Claude Code がコマンドを実行する前に出す「実行してよいですか」という許可の確認は出ませんでした。許可を押せば通る、という形ではなく、確認より手前で実行そのものが拒否される止まり方です。残高照会や明細照会(読み取りのAPI)は、いつもどおり許可の確認を経てそのまま実行できていたので、振込だけ扱いが違いました。仮想のお金でも、振込の形をしたAPIの送信は実行しない、という線が引かれているようです。
一方で、リクエストのJSONを書くところまでは止まりませんでした。口座IDや名義入りのJSONも、実行するcurlコマンドも、Claude Code は普通に作ります。止まるのは送信の瞬間だけです。分担の形も Claude Code のほうから出てきました。「コマンドは用意するので、実行はご自身でお願いします」という形です。
そこで、リクエストのJSONと実行するcurlコマンドは Claude Code が作り、送信は私がターミナルで実行しました。送信は結局2回ありましたが(2回目の事情は4章)、2回とも同じ分担です。
対象読者の2行目に書いた「どこで止まるか」の答えがこれです。私が実測できたのは振込APIについてだけなので、書き込み系がすべて止まるのかまでは分かりませんが、少なくとも振込は、確認を求めるのではなく実行しない、という止まり方でした。試す前は「仮想口座なら全部やってくれるだろう」と思っていたので、この線の引かれ方は発見でした。
なお2つ、切り分けておきます。今回の送信はエージェント(MCP)経由ではなく、アクセストークンをヘッダに載せた curl の直接実行です。そして止めたのは Claude Code 側で、前回の記事で登録した銀行側のエージェントのポリシー(150文字の日本語)が振込を止めるかどうかは別の話です。そちらは次回試します。
curl -X POST "https://api.sunabar.gmo-aozora.com/personal/v1/transfer/request" \
-H "accept: application/json;charset=UTF-8" \
-H "Content-Type: application/json" \
-H "x-access-token: $TOKEN" \
-d @振込依頼リクエスト.json
返ってきたもの
| # | 項目 | 値 |
|---|---|---|
| 1 | HTTP | 201 |
| 2 | applyNo(受付番号) | 2026083000000001 |
**201は「受け付けた」であって「振り込んだ」ではありません。**この時点で残高は1円も動いていません。applyNo は「日付+その日の連番」の形で採番されていました。
4. 振込依頼が消えていた
実は3章の前に、1回失敗しています。前日の夜(8月29日)に指定日8月29日で振込依頼を出して201をもらい、「承認は翌朝でいいだろう」と寝ました。
翌朝、承認しようとしたら、どこにもありませんでした。照会(読み取り)はいつもどおり Claude Code に実行してもらっています。振込状況照会APIのcurlは6章に載せています。
| # | 確かめた場所 | 結果 |
|---|---|---|
| 1 | サービスサイトの「引落し・振込予定」 | 表示対象がありません |
| 2 | 振込状況照会API(受付番号で照会) | count 0 |
| 3 | 振込状況照会API(日付範囲で照会) | count 0 |
指定日のうちに承認しなかった振込依頼は、期限切れで消えるようです(実測でそうなった、という話です。公式の記述は見つけていません)。エラーも通知も見当たらず、照会にもヒットしないので、「出したはずの振込が無い」状態になります。
教訓はひとつです。**振込依頼は、出した日のうちに承認まで済ませる。**3章に載せた実行結果は、指定日を8月30日に直して出し直した2回目のものです。
5. 承認する
承認する場所は「4つ目のサイト」
前回の記事で「ログインするサイトは3つあります」と書きましたが、振込の承認で4つ目が登場します。sunabarサービスサイト sso.sunabar.gmo-aozora.com です。
| # | サイト | 何をするところ |
|---|---|---|
| 1 | 銀行のサービスサイト sso.gmo-aozora.com
|
いつも使う本物の銀行のサイト |
| 2 | sunabarポータル portal.sunabar.gmo-aozora.com
|
トークン・エージェント登録・入出金シミュレーター |
| 3 | 開発者ポータル | APIの詳しい仕様書 |
| 4 | sunabarサービスサイト sso.sunabar.gmo-aozora.com
|
仮想口座の名義人としてログインし、振込を承認する |
言ってみれば「仮想世界の銀行窓口」で、振込元(個人の仮想口座)の名義人、つまり架空の人としてログインします。IDとパスワードは、sunabarポータルの「sunabarサービスサイトで使える銀行口座」の画面に載っています。3章で振込先の口座情報を拾ったのと同じ画面です。
私は最初、1番の本物の銀行のサイトへお知らせを見に行き、何も届いていなくて途方に暮れました。承認の入口は4番です。ここはブラウザの操作なので、Claude Code に任せることは試さず、最初から自分でやると決めていました。銀行のログインを伴うためです。
メールトークンの期限は約6分
sunabarサービスサイトにログインすると、ベルのアイコンの「お知らせ」に「メールトークンを発行しました(オープンAPI連携-振込)」という通知が入っています。振込依頼APIを送ったことが引き金で届く通知です。通知の詳細を開くと、承認ページへのリンクと6桁のメールトークンが載っています。
承認ページでは、このメールトークンと取引パスワード(承認の本人確認に入れる文字列)の2つを入れます。ここで少し急ぐ必要があります。メールトークンの有効期限は発行から約6分でした(画面に期限の時刻が出ます)。2つを入れて承認すると、「振込を受け付けました。(受付番号 : <受付番号>)」と表示されました。
FAQにはメールトークンは任意の文字列でよいという趣旨の記述がありますが、私の画面では実物の6桁が発行されていたので、それを入れました。取引パスワードのほうは任意の文字列で通りました。期限が切れた場合の再発行は試していません。私の場合は依頼そのものを出し直したら、新しい通知が届きました。
6. 完了を確認する
振込状況照会
承認の直後に、振込状況照会APIで状態を見ます。
curl -X GET "https://api.sunabar.gmo-aozora.com/personal/v1/transfer/status?accountId=<口座のID>&queryKeyClass=1&applyNo=<受付番号>" \
-H "accept: application/json;charset=UTF-8" \
-H "x-access-token: $TOKEN"
queryKeyClass は必須で、1(受付番号で引く)か2(日付範囲で引く)を指定します。2のときに applyNo を一緒に渡すと「受付番号(振込申請番号)は指定できません」と弾かれました。
transferStatus は 20(手続済) になっていました。承認前はこの照会が count 0 だったので、承認するまでは照会に出ない期間があることも分かりました。
残高が動いた
| # | 口座 | 承認前 | 承認後 |
|---|---|---|---|
| 1 | 個人(振込元) | 10,000 | 9,000 |
| 2 | 法人(振込先) | 0 | 1,000 |
1,000円が動きました。同じ銀行あてなので、振込手数料は0円です(transferFee "0")。
法人口座の残高を見るには、もうひと手間ありました。個人用のトークンでは法人の口座は見えません。実測では HTTP 404 で「ご指定のお取引は、お取り扱いできません。」が返ります。sunabarポータルのトークン発行画面で対象に法人口座を選んで法人用のアクセストークンをもう1本発行し、法人用の口座一覧照会(GET /corporation/v1/accounts)で法人側の accountId を取ってから、/corporation/v1/accounts/balances で確認しました。
まとめ
| # | 分かったこと |
|---|---|
| 1 | 振込は「受付(201)→ 承認 → 実行」の3つのステップ。承認して初めて残高が動く |
| 2 | 承認しないまま指定日を過ぎると、振込依頼は照会にも出ない形で消える(実測) |
| 3 | 承認の入口は4つ目のサイト(sunabarサービスサイト)のお知らせ。メールトークンの期限は約6分 |
| 4 | Claude Code は読み取りのAPIは実行するが、振込の送信は許可の確認も出さずに実行しない。JSONとコマンドの用意まではやってくれるので、送信の1回だけ人間の手が要る |
| 5 | 金額・残高・件数は文字列で返る |
次回は、前回登録した参照専用ポリシーのエージェントに振込を頼むとどう断られるか、金額上限つきのエージェントを作るとどこまで通るか、を試します。