0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Misoca API v3で取引先を特定しようとしたら、ドキュメントに3回騙された

0
Last updated at Posted at 2026-03-09

GASで請求書発行を自動化している。ボタン一つで請求書PDF作成→メール送信→チャット報告→スプレッドシート更新まで全部走る仕組みだ。

最初のプロジェクトは順調だった。取引先のMisoca IDもわかっていたし、APIドキュメント通りに叩けば動いた。問題は2つ目。新しい取引先のIDが必要になった。

「APIで取引先一覧を取ればいいだろ」

甘かった。ここからMisoca API v3の罠に3回ハマることになる。

そもそも何を自動化しているのか

毎月、取引先から明細メールが届く。中身は売上報告とPDF明細書。これを見て請求書を作り、返信メールに添付し、社内チャットで報告し、経理用スプレッドシートに記帳する。

手作業だと毎月15分。ミスると請求漏れ。地味だけど放置すると痛い。

GASで組んだフローはこう:

① Gmailから明細メールを自動検索
② 金額をパース → プレビュー画面で確認
③ Misoca APIで請求書作成 → PDF取得
④ スプレッドシートに記帳
⑤ Gmailで請求書PDF添付の返信
⑥ Chatworkで社内報告
⑦ Google Driveに請求書・明細書を保存

ボタン1回。全部終わる。完成形のプレビュー画面はこんな感じだ。

この仕組みを別の取引先にも展開しようとして、取引先IDの壁にぶつかった。

罠① リストAPIの返却フィールドが直感と違う

まず取引先の一覧を取得する。ここは素直にいける。

function listMisocaContacts() {
  var service = getMisocaService();
  if (!service.hasAccess()) {
    Logger.log('Misoca未認証です。先にOAuth認証を実行してください。');
    return;
  }

  var url = 'https://app.misoca.jp/api/v3/contacts?per_page=50&page=1';
  var res = UrlFetchApp.fetch(url, {
    headers: { 'Authorization': 'Bearer ' + service.getAccessToken() },
    muteHttpExceptions: true
  });
  var contacts = JSON.parse(res.getContentText());

  Logger.log('=== Misoca取引先一覧 ===');
  contacts.forEach(function(c) {
    Logger.log(c.id + ' : ' + c.recipient_name +
      (c.recipient_name1 && c.recipient_name1 !== c.recipient_name
        ? ' (name1: ' + c.recipient_name1 + ')' : ''));
  });
  Logger.log('合計: ' + contacts.length + '');

  if (contacts.length === 50) {
    Logger.log('※ 50件以上あります。page=2以降も確認してください。');
  }
}

コードは動く。問題は返ってくるJSON。

取引先の名前を取りたいとき、普通は name とか company を探すだろう。ない。 そんなフィールドは存在しない。

正解は recipient_name

「recipient(受取人)」——つまり請求書の宛名フィールドそのまま。考えてみれば当たり前なんだけど、最初に name で検索して undefined が返ってきたときは「おい嘘だろ」と声が出た。

ドキュメントにフィールド一覧がちゃんと載っていればこんなことにはならない。が、Misoca APIのドキュメントは必要最低限しか書いてない。結局、レスポンスを丸ごとダンプして眺めるのが一番早かった。

罠② 同名の取引先が複数ある

一覧を取得してログを眺めていたら、同じ名前の取引先が2件。

ID: 8165600 : 株式会社A商事
ID: 8406825 : 株式会社A商事

同じ会社と複数の取引がある場合、用途ごとに取引先を分けて登録していることがある。経費精算用とレベニューシェア用、のように。

で、どっちがどっちだ?

ここで recipient_name1 が効いてくる。Misocaの取引先には recipient_name の他に recipient_name1 というフィールドがある。請求書の宛名2行目に相当するもので、部署名や担当者名を入れるのが一般的。うちの場合は「支払元の別名」を入れて区別していた。

ID: 8165600 : 株式会社A商事 (name1: 株式会社A商事)    ← 経費精算用
ID: 8406825 : 株式会社A商事 (name1: B株式会社)          ← レベニューシェア用

これで区別がつく。でもログだけでは「どっちがどの取引に紐づくか」がわからない。

確実なのは、過去の請求書を引っ張ること。ただし使うのは contact_id ではなく contact_group_id。ここも罠。

function identifyContactByInvoices(contactGroupId) {
  var service = getMisocaService();
  var url = 'https://app.misoca.jp/api/v3/invoices?per_page=5&page=1'
          + '&contact_group_id=' + contactGroupId;
  var res = UrlFetchApp.fetch(url, {
    headers: { 'Authorization': 'Bearer ' + service.getAccessToken() },
    muteHttpExceptions: true
  });
  var invoices = JSON.parse(res.getContentText());
  invoices.forEach(function(inv) {
    Logger.log(inv.issue_date + ' | ' + inv.subject + ' | '
      + (inv.body.total_amount_including_tax || ''));
  });
}

過去の請求書の件名と金額を見れば、どの取引先がどの用途かすぐわかる。contact_group_id は取引先一覧のレスポンスに含まれているので、一覧取得→請求書検索の2ステップで特定できる。

なぜ contact_id ではなく contact_group_id なのか? 正直よくわからない。Misocaの内部では取引先を「グループ」で束ねているらしいが、ドキュメントに説明はない。試して動いたからそう使っている。

罠③ 個別取得エンドポイントがHTMLを返す

取引先の詳細を見たくて /contacts/{id} を叩いた。

var res = UrlFetchApp.fetch(
  'https://app.misoca.jp/api/v3/contacts/' + contactId,
  { headers: { 'Authorization': 'Bearer ' + token } }
);
Logger.log(res.getContentText());

返ってきたのは <!DOCTYPE html>

は?

HTMLだ。Misocaの取引先編集画面のHTMLが丸ごと返ってくる。JSONじゃない。APIエンドポイントに投げて、ブラウザ用のHTMLが返ってくる体験。なかなか新鮮だった。

「Content-Typeの指定が足りないのか?」と思って Accept: application/json をつけてみた。

変わらない。HTMLが返る。

請求書の個別取得 /invoices/{id} も試した。同じ。HTML。

一瞬、自分のコードがおかしいのかと疑った。URLを3回見直した。間違ってない。エンドポイントも合ってる。認証も通ってる。なのにHTMLが返る。

結論: v3のAPIでまともにJSONが返るのはリストエンドポイントだけ。個別取得は全部ブラウザ用のHTMLにリダイレクトされる。仕様なのかバグなのか判断がつかないが、2026年3月時点でこの挙動だった。

つまりMisoca APIでやりたいことがあるなら、リストAPIで per_page を大きめに取って一括取得し、クライアント側でフィルタする。これしかない。

まとめ:Misoca API v3で取引先を扱うときの鉄則

やりたいこと 方法
取引先の名前を取得 recipient_name を見る(name は存在しない)
同名取引先の区別 recipient_name1 で確認 + contact_group_id 経由で過去の請求書を検索
取引先の詳細情報 個別APIは使えない。リストAPIで全件取得してフィルタ
請求書の検索 contact_group_id でフィルタ(contact_id ではない)

このハマりを経て自動化したもの

最終的に、GASのスプレッドシートメニューからボタン1つで以下が全自動で動くようになった:

  1. Gmailから取引先の明細メールを自動検索・金額パース
  2. プレビュー画面で確認(金額の自動計算・チャットメッセージのプレビュー付き)
  3. Misoca APIで請求書作成 → PDF取得
  4. スプレッドシートに記帳
  5. Gmailで請求書PDF添付の返信を自動送信
  6. Chatworkで関係者に報告
  7. Google Driveに請求書・明細書PDFを自動保存

月次の精算が15分 → 30秒に。人的ミスはゼロになった。請求書の金額間違い、メール送り忘れ、スプレッドシートの記入漏れ——全部消えた。

Misoca APIのドキュメントは正直つらい。ネット上にも情報がほとんどない。でもリストAPIさえ理解すれば、GASとの相性は抜群にいい。OAuth認証を一度通せば、あとは UrlFetchApp.fetch で何でもできる。

取引先IDの特定に半日使った。そのおかげで毎月15分の作業が消えた。投資回収は2ヶ月。悪くない。


使用技術: Google Apps Script / Misoca API v3 / OAuth2 for Apps Script

シリーズ:

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?