kintoneからHubSpotへデータを移行する際、CSVエクスポートだけに頼ると「選択肢の定義」と「アプリ間の関連構造」の2つの情報が失われます。 これをREST APIで確実に救うには、3種類ある認証方式の使い分け、CB_OA01エラーの原因切り分け、10,000件を超える場合のページング設計という3つの壁を越える必要があります。
kintoneからHubSpotへデータを移行する際、CSVエクスポートだけに頼ると「選択肢の定義」と「アプリ間の関連構造」の2つの情報が失われます。 これをREST APIで確実に救うには、3種類ある認証方式の使い分け、CB_OA01エラーの原因切り分け、10,000件を超える場合のページング設計という3つの壁を越える必要があります。
ブログ目次
HubSpotゴールドパートナーのStartLinkが、HubSpot導入・AI活用・CRM整備・業務効率化までをまとめて支援しています。記事で気になったテーマを、そのまま相談ベースで整理できます。
kintoneからHubSpotへデータを移行する際、CSVエクスポートだけに頼ると「選択肢の定義」と「アプリ間の関連構造」の2つの情報が失われます。 これをREST APIで確実に救うには、3種類ある認証方式の使い分け、CB_OA01エラーの原因切り分け、10,000件を超える場合のページング設計という3つの壁を越える必要があります。
「CSVでエクスポートしたら、ドロップダウンの選択肢が全部バラバラの文字列になってしまった」「関連レコード一覧に表示されていたはずのデータが、エクスポートすると消えている」——kintoneからHubSpotへの移行を検討する企業様から、こうした声を何度も聞いてきました。
私たちがこれまでの移行支援で確立してきた実務手順は、CSVエクスポートを起点にせず、kintone REST APIから直接データを取得することです。本記事では、認証方式の判別から、時間を溶かしやすい認証エラーの事前チェック、全件取得のページング設計、フィールド定義APIの活用まで、動くレベルの具体的な手順で解説します。移行プロジェクト全体の流れはkintone→HubSpot移行の完全ガイドでも整理していますので、あわせてご覧ください。
CB_OA01エラーで時間を溶かさない事前チェック手順 — 無認証プローブの使い方とエラーコード早見表を掲載します。kintoneからHubSpotへのデータ移行を担当しており、CSVエクスポートだけでは選択肢の定義やアプリ間の関連構造が失われてしまうことに困っている方に、特に読んでいただきたい内容です。ぜひ最後までご確認ください。
kintoneの画面から「エクスポート」ボタンを押せば、誰でも数秒でCSVファイルを取得できます。ただしこの手軽さと引き換えに、移行に必要な情報の一部が失われてしまう点が、結構ミソになってくる部分です。
1つ目は選択肢の定義情報です。CSVエクスポートでは、ドロップダウンやチェックボックスの「選択された値の文字列」しか出力されません。そのフィールドに本来どんな選択肢が用意されていたか、選択肢の並び順や未選択の選択肢が何だったかは、CSVを見ただけでは分かりません。HubSpot側でenumプロパティ(選択リスト)を設計する際、この元の選択肢一覧が欠けていると、後から手作業で選択肢を洗い出す手間が発生します。
2つ目はアプリ間の関連構造です。kintoneの「関連レコード一覧」(ルックアップで参照している別アプリのレコード一覧を画面上に表示する機能)は、あくまで表示専用の機能であり、CSVエクスポートの対象データには含まれません。案件管理アプリの画面上で取引先の過去案件が一覧表示されていても、それはCSVには出力されない「見た目だけの情報」だということです。
REST APIであれば、この2つの情報をどちらも取得できます。フィールド定義API(/k/v1/app/form/fields.json)を呼べば、選択肢の一覧を型情報ごと丸ごと取得できますし、関連構造については、表示用テーブルに頼らず実際のキー項目(数値ID・コード等)でレコード間の紐付けを再構築できます。この実キーによる紐付け設計は、複数アプリを横断してHubSpotオブジェクトへ再設計する際の土台になります(詳しくは後述の複数アプリ統合設計の記事で扱います)。
なお、CSVエクスポートを使った簡易的な移行手順そのものは否定しません。アプリ数が少なく、選択肢の再設計や関連構造の復元が不要なケースでは、CSVを使った移行手順の方が早いこともあります。判断基準を整理したのが以下の表です。
| 情報カバー範囲 | CSVエクスポート | REST API |
|---|---|---|
| レコードの値そのもの | ○ 取得可能 | ○ 取得可能 |
| 選択肢の定義(未選択分含む全選択肢) | × 取得不可 | ○ fields APIで取得可能 |
| フィールドのデータ型(文字列/数値/日付等) | △ 目視推測のみ | ○ fields APIで正確に取得 |
| ルックアップの参照先アプリ情報 | × 取得不可 | ○ fields APIで取得可能 |
| 「関連レコード一覧」の表示データ | × 取得不可 | △ 実キー項目からの再構築が必要 |
| 10,000件超の大量データ | △ 一括ダウンロードのみ | ○ ページング設計で確実に取得 |
| 自動化・定期実行への組み込み | × 手動操作が前提 | ○ スクリプト化・スケジュール実行可能 |
kintone REST APIには3種類の認証方式があり、これを取り違えるとCB_OA01(保護されたリソースにアクセスできません)というエラーで時間を溶かすことになります。顧客から「APIキーをもらいました」と連携された際に、まずどの形式かを見た目で即座に判別することが実務の勘所です。
cy.s.api1.から始まる長い文字列のトークンで、Authorization: Bearerヘッダーで送信します。これはユーザー管理・組織管理・グループ管理といった管理系APIの専用トークンであり、アプリのレコードを取得することはできません。移行担当者からこの形式のトークンを渡された場合は、レコード取得には使えないことを先に伝え、別の形式を発行してもらう必要があります。
64文字の英数字で構成されるトークンで、X-Cybozu-API-Tokenヘッダーで送信します。1つのトークンにつき1つのアプリのレコード操作しかできません。発行しただけでは有効化されず、アプリの設定画面で「アプリを更新」ボタンを押すまでAPIが機能しないという落とし穴があり、これを見落として「トークンが間違っているのでは」と原因調査に時間を取られるケースが多く見られます。
ログインIDとパスワードをbase64(login:password)の形式でエンコードし、X-Cybozu-Authorizationヘッダーで送信する方式です。閲覧権限を持つアカウントが1つあれば、個別にトークンを発行することなく、対象組織の全アプリのレコードを取得できます。データ移行のように複数アプリを横断してデータを抽出する場面では、この形式Cが実務の本命になります。
私たちが移行支援で確立した実務ハックとして、アプリトークン(形式B)の発行が各アプリの管理者承認待ちなどで滞留した場合は、閲覧権限を持つ1つのアカウントのID/パスワードで形式Cのパスワード認証に切り替えることで、個別アプリの発行を待たずに全アプリを一括取得できます。アプリ数が10を超えるような移行案件では、この切り替え判断が全体の作業時間を大きく左右します。
| 形式 | 見た目 | ヘッダー | 用途 |
|---|---|---|---|
| A: 共通管理トークン(JWT) | cy.s.api1.〜 |
Authorization: Bearer |
ユーザー/組織/グループ管理API専用。レコード取得は不可 |
| B: アプリトークン | 64文字の英数字 | X-Cybozu-API-Token |
1トークン=1アプリのレコード操作。発行後「アプリを更新」押下必須 |
| C: パスワード認証 | ログインID/パスワード | X-Cybozu-Authorization: base64(login:pw) |
閲覧権限アカウント1つで全アプリのレコード取得が可能。個別トークン発行不要 |

認証方式を取り違えたまま接続を試みると、CB_OA01のような分かりにくいエラーコードだけが返り、原因の切り分けに時間がかかります。本格的な実装に入る前に、以下の事前チェックを行うことで無駄な試行錯誤を避けられます。
/k/v1/app.json?id=N の使い方まず認証ヘッダーを一切付けずにGET /k/v1/app.json?id=N(Nは対象アプリのID)を叩いてみます。このレスポンスの内容によって、対象環境がどのようなセキュリティ設定になっているかを事前に把握できます。
WWW-Authenticate: Basic が返る=セキュアアクセスONレスポンスヘッダーにWWW-Authenticate: Basicが含まれる場合、その環境では「セキュアアクセス」と呼ばれるBasic認証によるIPアクセス制限が有効になっています。この場合は、通常のAPI認証ヘッダーに加えて、Basic認証用の別の認証情報を追加で送信する必要があります。事前にこれが分かっていれば、後から「なぜ認証情報が正しいのにアクセスできないのか」と悩む時間を省けます。
パスワード認証(形式C)は便利な反面、以下の3つの条件に該当する場合は使用できません。
これらの条件に該当する場合は、パスワード認証ではなく形式B(アプリトークン)を使う必要があります。事前に管理者へ「SSO専用アカウントか」「2段階認証は有効か」を確認しておくと、実装段階での手戻りを防げます。
前述の通り、アプリトークンの発行・承認フローが止まってしまった場合は、閲覧権限を持つアカウントでのパスワード認証に切り替えるのが最も現実的な打開策です。ただし上記3条件に該当する環境では使えないため、事前チェックの結果と合わせて判断する必要があります。
| エラーコード | 意味 | 主な原因 |
|---|---|---|
CB_OA01 |
保護されたリソースにアクセスできません | 認証方式の取り違え・スコープ不足 |
CB_AU01 |
ログインしていません | 認証ヘッダー未設定・認証情報の誤り |
GAIA_IA02 |
アプリIDが不正、またはアプリの更新が未実施 | アプリトークン発行後に「アプリを更新」を押していない |
| 520系エラー | サーバーエラー | サブドメインの指定誤り・ヘッダー形式の誤り |
認証を突破できたら、次は全レコードを漏れなく取得するページング設計です。kintoneのレコード取得APIには1リクエストあたりの上限があり、この上限を正しく処理しないとデータの欠落が起きます。
query="order by $id asc limit 500 offset N"レコード取得には/k/v1/records.jsonエンドポイントを使い、queryパラメータでorder by $id asc limit 500 offset Nのように指定します。1リクエストで取得できる件数は最大500件です。$id(レコード番号)の昇順で並べ、offsetを500ずつずらしながらループすることで、全件を漏れなく取得していきます。
ここで注意が必要なのが、offsetにはハード上限として10,000という制限があることです。offsetが10,000を超えるクエリを送ると正しく動作しません。対象アプリのレコード件数が10,000件を超える場合は、offsetによるページングをそのまま続けるのではなく、直前に取得できた最大の$idを使ってquery="$id > 直前の最大id order by $id asc limit 500"のようにカーソル的に範囲を絞り込む方式に切り替える必要があります。この$id範囲分割方式であれば、件数がどれだけ多くても取りこぼしなく全件取得できます。
以下は、10,000件の壁を超えても動作するよう$id範囲分割方式で実装した全件取得スクリプトの例です。
import requests
import json
SUBDOMAIN = "your-subdomain"
APP_ID = 10
BASE_URL = f"https://{SUBDOMAIN}.cybozu.com/k/v1/records.json"
# 形式C: パスワード認証を使う場合
import base64
login = base64.b64encode(b"login-id:password").decode("utf-8")
headers = {
"X-Cybozu-Authorization": login,
}
# 形式B: アプリトークンを使う場合はこちらに切り替え
# headers = {"X-Cybozu-API-Token": "発行した64文字トークン"}
def fetch_all_records(app_id: int) -> list[dict]:
all_records: list[dict] = []
last_id = 0
limit = 500
while True:
query = f"$id > {last_id} order by $id asc limit {limit}"
params = {"app": app_id, "query": query}
res = requests.get(BASE_URL, headers=headers, params=params, timeout=30)
res.raise_for_status()
records = res.json()["records"]
if not records:
break
all_records.extend(records)
last_id = int(records[-1]["$id"]["value"])
if len(records) < limit:
break
return all_records
if __name__ == "__main__":
records = fetch_all_records(APP_ID)
print(f"取得件数: {len(records)}")
with open("kintone_records.json", "w", encoding="utf-8") as f:
json.dump(records, f, ensure_ascii=False, indent=2)
このスクリプトは$idの昇順でカーソルのように進んでいくため、途中でoffsetの10,000件制限に引っかかることがなく、レコード件数がどれだけ増えても同じロジックで全件取得を継続できます。
動作確認や簡易的な検証には、curlで1ページ分を取得するのが手早い方法です。
# 形式C: パスワード認証
CREDENTIAL=$(echo -n "login-id:password" | base64)
curl -X GET "https://your-subdomain.cybozu.com/k/v1/records.json" \
--data-urlencode "app=10" \
--data-urlencode "query=order by \$id asc limit 500 offset 0" \
-G \
-H "X-Cybozu-Authorization: ${CREDENTIAL}"
# 形式B: アプリトークン
curl -X GET "https://your-subdomain.cybozu.com/k/v1/records.json" \
--data-urlencode "app=10" \
--data-urlencode "query=\$id > 500 order by \$id asc limit 500" \
-G \
-H "X-Cybozu-API-Token: 発行した64文字トークン"
offsetを使う1ページ目の確認にはシンプルなクエリで十分ですが、本番の全件取得では前述のPythonスクリプトのように$id範囲分割へ切り替えることをおすすめします。
レコードの値そのものだけでなく、そのアプリがどんなフィールド構成になっているかを取得できるのがフィールド定義APIです。HubSpot側のプロパティ設計をする際に、この情報が土台になります。
/k/v1/app/form/fields.json?app=N でcode/label/type/選択肢(options)/ルックアップ参照先を取得GET /k/v1/app/form/fields.json?app=Nを呼ぶと、対象アプリの全フィールドについて、フィールドコード(code)、表示ラベル(label)、データ型(type)、ドロップダウン等の選択肢一覧(options)、ルックアップフィールドが参照している先のアプリ情報までを一度に取得できます。ブラウザの開発者コンソールからkintone.api(...)を実行してTSV形式で出力することも可能ですが、移行作業のように再現性が必要な場面ではAPI経由でJSONとして保存しておく方が確実です。
fields APIで取得した選択肢一覧(options)は、そのままHubSpot側のenumプロパティ(選択リスト)の選択肢設計に流用できます。CSVエクスポートでは「選択された値」しか見えませんが、fields APIなら未選択の選択肢も含めて全選択肢を正確に把握できるため、移行後のプロパティ設計で選択肢の抜け漏れが起きにくくなります。
fields APIのレスポンスには、画面レイアウト上の「グループ」(GROUP要素)も含まれますが、これは表示上の区切りであり、レコード自体の値は持ちません。フィールド一覧を処理する際は、GROUP要素をデータフィールドとして扱わないよう除外しておく必要があります。
fields APIのレスポンスに含まれるREFERENCE_TABLE(関連レコード一覧)は、あくまで画面上に別アプリのレコードを表示するための設定情報であり、レコードの実データそのものではありません。案件管理アプリの画面で取引先の過去案件が一覧表示されていても、それはこのREFERENCE_TABLEによる表示であり、レコード値としてエクスポートされることはありません。この関連構造をHubSpot側で再現するには、REFERENCE_TABLEの表示設定を見るのではなく、両アプリに共通して存在する実キー項目(数値の取引先IDなど)を使って、レコード同士の紐付けを自分たちで再構築する必要があります。
ここまでの手順で、選択肢定義・データ型・関連構造まで含めた正確なデータをkintoneから取得できる状態になりました。次のステップは、このデータを複数アプリ横断でHubSpotのオブジェクト(コンタクト・会社・取引等)へどう再設計してマッピングするかという判断です。
1つのkintoneアプリを1つのHubSpotオブジェクトへ単純に移し替えるだけであれば比較的シンプルですが、実際の移行案件では、案件管理アプリと取引先管理アプリのように、複数のアプリが互いに関連付けられているケースがほとんどです。この場合、どのアプリをどのHubSpotオブジェクトに対応させるか、関連付けのキーとして使える実キーがどれくらいの精度でデータに入っているかを事前に実測してから設計する必要があります。この複数アプリの統合設計については、複数アプリをHubSpotオブジェクトに再設計する記事で詳しく解説しています。
ここまでの認証方式の判別、ページング設計、フィールド定義の解析、そして複数アプリのオブジェクト再設計までを自社のエンジニアリソースだけで完結させるのは、特にアプリ数が多い移行案件では相応の工数がかかります。
HubSpot ゴールドパートナーとしての移行支援
StartLinkはHubSpotゴールドパートナーとして、kintoneからHubSpotへのAPI移行を数多く支援してきました。認証方式の判別・全件取得の実装・複数アプリのオブジェクト再設計までを一気通貫で伴走します。自社での実装リソースが不足している場合は、移行を「コスト」ではなく、データ資産をCRMの動く仕組みに載せ替える「投資」として検討いただければと思います。詳しくはお問い合わせページからご相談ください。
なお、kintoneとHubSpotを全面移行せず併用する設計を検討している場合は、kintone×HubSpot連携設計の記事を、そもそも移行するかどうかの判断に迷っている場合は、HubSpot vs kintone比較記事をあわせてご覧ください。
kintone REST APIでのデータ全件取得は、以下の3つの壁を順に越えることで確実に実行できます。
CB_OA01等のエラーは、無認証プローブでの事前チェックとエラーコード早見表で切り分けられる — 本格実装の前にセキュアアクセスの有無を確認しておくと手戻りを防げます$id範囲分割方式に切り替える — この方式であればレコード件数がどれだけ増えても同じロジックで対応できますまずは対象アプリの認証方式を判別し、無認証プローブでセキュアアクセスの有無を確認するところから始めてみてください。そのうえでフィールド定義APIを先に呼んでおけば、レコード本体の取得作業も選択肢の再設計もスムーズに進められます。データが正確に取得できて初めて、その先の複数アプリのオブジェクト再設計やHubSpot側のパイプライン設計といった、移行の本質的な価値に手が届くようになります。
アプリ数が少なく、選択肢の再設計や関連構造の復元が不要な小規模な移行であれば、CSVエクスポートによる簡易的な手順でも対応できます。一方、ドロップダウンの選択肢定義を正確に引き継ぎたい場合や、複数アプリをまたいだ関連構造をHubSpot側で再現したい場合は、REST APIでの取得が必須になります。移行するアプリの規模と、選択肢・関連構造をどこまで正確に引き継ぐ必要があるかで判断してください。
対象アプリが1〜2個程度であればアプリトークン(形式B)を発行して個別に扱うのがシンプルです。ただし対象アプリが多い場合や、アプリトークンの発行・承認が管理者側で滞留している場合は、閲覧権限を持つアカウントによるパスワード認証(形式C)に切り替えると、個別発行を待たずに全アプリへアクセスできます。ただしSSO専用アカウント・2段階認証有効・セキュアアクセス有効のいずれかに該当する環境では、パスワード認証は使えません。
kintoneのレコード取得APIはoffsetに10,000件のハード上限があります。この上限を超える場合は、offsetによるページングを続けるのではなく、直前に取得した最大の$idを使って$id > 直前のidという条件でクエリを組み立て直す、$id範囲分割方式に切り替えてください。この方式であれば件数の上限なく全件を取得できます。
kintoneの「関連レコード一覧」(REFERENCE_TABLE)は、画面上に別アプリのレコードを表示するための表示専用の設定であり、レコード自体が保持しているデータではないためです。CSVエクスポートにもレコード取得APIのレスポンスにも、この表示内容そのものは含まれません。同様の紐付けをHubSpot側で再現するには、両アプリに共通する実キー項目(数値IDなど)を使って関連付けを組み直す必要があります。
株式会社StartLinkは、事業推進に関わる「販売促進」「DXによる業務効率化(ERP/CRM/SFA/MAの導入)」などのご相談を受け付けております。 サービスのプランについてのご相談/お見積もり依頼や、ノウハウのお問い合わせについては、無料のお問い合わせページより、お気軽にご連絡くださいませ。
株式会社StartLink 代表取締役。累計150社以上のHubSpotプロジェクト支援実績を持ち、Claude CodeやHubSpotを軸にしたAI活用支援・経営基盤AXのコンサルティング事業を展開。
HubSpotのトップパートナー企業や大手人材グループにて、エンタープライズCRM戦略策定・AI戦略ディレクションを経験した後、StartLinkを創業。現在はCRM×AIエージェントによる経営管理支援を専門とする。