LINE予約「LUCA」の機能と料金はこちら

n8nのAPIでワークフローを更新する方法と、反映されない・止まらない原因

実務ノート 実務ノート 公開

n8n の API(外のプログラムから n8n を操作する入り口)を使うと、ワークフローの取得、更新、公開、停止をコマンドで行えます。ところが、API で書き換えたのに古い処理のまま動いたり、止めたはずのワークフローがまた動いたりします。この記事では、API の使い始め方とよく使う呼び先を短くまとめたあと、弊社の本番(n8n 2.19.2)で起きた「反映されない・止まらない」を、n8n 本体のソースで確かめた仕組みと合わせて説明します。n8n の中から外部の API を呼ぶ話ではなく、n8n 自身を外から操作する API の話です。

この記事の結論

  • API キーは Settings > n8n API で作り、ヘッダー X-N8N-API-KEY に入れて https://(n8n の URL)/api/v1 の下を呼びます。
  • n8n 2.19.2 では、編集中の版と公開中の版が別に保存されています。Webhook のワークフローは呼ばれるたびに公開中の版を読み、スケジュールのワークフローは有効にした(登録した)ときの公開中の版で動き続けます。
  • 更新したら、応答だけで済ませず、実行の記録に目印が出たかで確かめます。弊社では PUT のあとも古い中身で動いたことがあります。PUT がエラーを返したら、GET で activeVersionId を見ます。
  • 止めるときは POST /api/v1/workflows/{id}/deactivate を使います。PUT の本文に active を入れると弾かれます。データベースだけを書き換えても、動いている n8n の登録は外れず、再起動するまでスケジュールは動き続けます。

n8n の API の使い始め方

公式ドキュメントの手順では、API キーを次のように作ります。

  1. n8n にログインする
  2. Settings > n8n API を開く
  3. Create an API key を選ぶ
  4. Label(名前)と Expiration(有効期限)を決める
  5. 表示された My API Key を写し、API を呼ぶときに使う

キーはヘッダー X-N8N-API-KEY に入れて送ります。自分で動かしている n8n なら、呼び先は https://<your-instance-url>/api/v1 の形です。Enterprise 以外のプランのキーは、アカウントのすべての機能とデータを操作できます。他人に見られない場所に保管します。

# 有効なワークフローの一覧を取る
curl -s "https://XXXX/api/v1/workflows?active=true" \
  -H "X-N8N-API-KEY: XXXX" -o list.json

2.19.2 の API の定義(openapi.yml)を見ると、ワークフローのほかに、実行の記録、認証情報、タグ、変数、データテーブルなども扱えます。ワークフローと実行の記録でよく使う呼び先は次のとおりです。

呼び先 API の定義の説明
GET /workflows Retrieve all workflows
POST /workflows Create a workflow
GET /workflows/{id} Retrieve a workflow
PUT /workflows/{id} Update a workflow
DELETE /workflows/{id} Delete a workflow
POST /workflows/{id}/activate Publish a workflow
POST /workflows/{id}/deactivate Deactivate a workflow
GET /executions Retrieve all executions
GET /executions/{id} Retrieve an execution

ワークフローの一覧は既定で100件ずつ返ります。多いときは、応答の nextCursor で続きを取ります。この記事で深く扱うのは、ワークフローの更新と停止です。

実際に起きたこと

1つ目は「反映されない」です。弊社で動かしているワークフローの Code ノード(JavaScript を書くノード)を差し替えたのに、実行は古い仮の中身のままでした。記録には次の3つが残っています。

  • データベースの workflow_entity の nodes を直接書き換えて activate しても、古いままだった。
  • 公開 API の PUT で nodes を更新し、n8n の MCP サーバー(AI の道具から n8n を操作する入り口)の publish_workflow で公開しても、同じ versionId が返り、変わらなかった。
  • 効いたのは、MCP サーバーの update_workflow で更新し、publish_workflow で公開する手順だった。毎回 versionId が新しくなった。

なぜ PUT で変わらなかったのかは、記録からは分かりません。PUT の前にデータベースを書き換えていたかなど、操作の順番も残っていません。

実行用の版だけを直したときは、実行は新しいコードなのに、画面で開くと古いコードが出ました。弊社の点検の仕組みは編集中の版を見ていたので、直したあとも警告が鳴り続けました。

2つ目は「止まらない」です。データベースでは無効なのに、実行が続いているワークフローがありました。n8n を再起動した後、その実行は0件になりました。記録には「DBは無効」とだけあり、active と activeVersionId のどちらだったのかは残っていません。

原因

ここから先は、n8n 2.19.2 のソースと公式ドキュメントで確かめた仕組みです。弊社の本番で一つずつ試したものではありません。

編集中の版と公開中の版は別に保存されている

公式ドキュメントは「Production executions will use this published version, not your latest edits.」と書いています。本番の実行は公開した版を使い、最新の編集は使いません。

ソースでは、ワークフローの本体(workflow_entity)に versionId(最新の保存の版)と activeVersionId(公開中の版)があります。公開中の版の中身は、workflow_history の行を versionId でつないで読みます。

(0, typeorm_1.JoinColumn)({ name: 'activeVersionId', referencedColumnName: 'versionId' }),

本体の nodes 列は、画面で見える編集中の中身です。ここを書き換えても、公開中の版の行は変わりません。

実行はどこから中身を読むか

Webhook(外から URL を呼ばれて動く形)のワークフローは、呼ばれるたびにデータベースから公開中の版を読んで実行します。

スケジュールやポーリング(定期的に相手を見に行く形)のワークフローは、有効にしたときに公開中の版を読み込み、その中身を持ったままトリガーを登録します。以後の実行は、そのとき持った中身で走ります。

const { nodes, connections } = dbWorkflow.activeVersion;
dbWorkflow.nodes = nodes;
dbWorkflow.connections = connections;
// …
const getTriggerFunctions = this.getExecuteTriggerFunctions(dbWorkflow, additionalData, executionMode, activationMode);

このため、データベースだけを書き換えても、スケジュールのワークフローは古い中身で動き続けます。登録を入れ替えるのは、主に公開と停止の処理と、n8n の起動です。

起動したときに登録されるもの

n8n は起動のとき、activeVersionId が空でないワークフローだけを登録します。active 列は見ていません。

async getAllActiveIds() {
    const result = await this.find({
        select: { id: true },
        where: { activeVersionId: (0, typeorm_1.Not)((0, typeorm_1.IsNull)()) },
    });

トリガーか Webhook を登録できたワークフローごとに、ログへ次の1行を出します。

Activated workflow "ワークフロー名" (ID: XXXX)

動いている間にデータベースだけが変わっても、メモリの登録は外れません。再起動で登録を作り直したとき、activeVersionId が空のものが外れます。弊社で再起動によって止まったものが activeVersionId まで空だったなら、これで説明がつきます。active 列だけが無効だったなら、再起動で登録し直されるはずで、説明に合いません。どちらだったかは記録に無いので、断定しません。

PUT が新しい版を作る条件

公開 API の PUT は、WorkflowService.update を publishIfActive: true で呼びます。update は、送られた nodes と connections を、データベースの本体のものと比べます。

const nodesChanged = hasNodesKey && !(0, isEqual_1.default)(workflowUpdateData.nodes, workflow.nodes);
const connectionsChanged = hasConnectionsKey && !(0, isEqual_1.default)(workflowUpdateData.connections, workflow.connections);
const saveNewVersion = nodesChanged || connectionsChanged;

違えば新しい versionId を振り、workflow_history に保存します。同じなら versionId はそのままです。

公開中なら、activeVersionId を今回の versionId に書き換えて保存し、そのあと公開の処理(activateWorkflow)で古い登録を外して新しい版で登録し直します。2.19.2 の API の定義にも「If the workflow is published, the updated version will be automatically re-published.」とあります。弊社の記録の「PUT のあとも古いまま」とどうつながるのかは、確かめていません。

PUT の途中で公開に失敗したとき

公開の処理を呼ぶ時点で、activeVersionId はもう新しい版を指しています。公開 API は、エラーの種類が NotFoundError なら 404(Not Found)を、それ以外なら 400 と理由の message を返します。残る状態は、失敗した場所で違います。

  • 古い登録を外す前の検査(Webhook のパスの衝突、ノードの検査など)で弾かれたとき。登録は外れず、スケジュールのものは古い中身で動き続けます。データベースは新しい版を指したままで、Webhook のものは新しい中身で動きます。
  • 古い登録を外したあと、新しい登録に失敗したとき。n8n は active を false、activeVersionId を空に戻します。ワークフローは止まったままです。
const rollbackPayload = {
    active: false,
    activeVersionId: null,
    activeVersion: null,
};

止める操作は deactivate だけ

API の定義では、ワークフローの active は読み取り専用です。2.19.2 の公開 API は本文をこの定義で検査するので、PUT に active を入れると、何も変わる前に 400 で弾かれます。ソースから組み立てると、応答は次の形です。

{"message":"request/body/active is read-only"}

deactivate は、先にメモリの登録を外し、それからデータベースの active を false に、activeVersionId を空にします。

await this.activeWorkflowManager.remove(workflowId);
await this.workflowRepository.update(workflowId, {
    active: false,
    activeVersionId: null,

直し方

1. PUT の前に今の状態を控える

GET で今の中身を取り、ファイルに残します。あとで PUT の結果と比べるためです。

GET の nodes は編集中の版です。画面で直して公開していない変更があると、それも PUT で本番へ出ます(公開中なら自動で公開し直されるため)。activate を本文なしで呼んだときも、最新の保存の版が公開されます。先に、編集中の版と公開中の版(activeVersion.nodes)が同じかを見ます。

curl -s "https://XXXX/api/v1/workflows/XXXX" \
  -H "X-N8N-API-KEY: XXXX" -o before.json
jq '{versionId, activeVersionId}' before.json

# 編集中の版と公開中の版が同じなら true
jq '.nodes == .activeVersion.nodes' before.json

false なら、違いが自分の知っている変更だけかを確かめてから進みます。

2. 送ってよい項目だけで PUT する

# 送ってよい項目だけにする(settings は空でよい)
jq '{name, nodes, connections, settings: {}}' before.json > body.json

# body.json の nodes を直したら送る
curl -s -X PUT "https://XXXX/api/v1/workflows/XXXX" \
  -H "X-N8N-API-KEY: XXXX" -H "Content-Type: application/json" \
  -d @body.json -o put.json

API の定義では、name、nodes、connections、settings の4つが必須です。GET の応答をそのまま送ると、id や active、versionId のような読み取り専用の項目で弾かれます。

settings は決まった項目以外を許しません(additionalProperties: false)。n8n 本体の設定には binaryMode、timeSavedMode、credentialResolverId、redactionPolicy のように、API の定義に無い項目があり、入ったまま送ると次のように弾かれます。

{"message":"request/body/settings must NOT have additional properties"}

空の {} を送っても、update が今の settings に重ねて保存するので、ほかの設定は消えません。staticData(実行の合間に覚えておく値)は送ったときだけ書き換わるので、変えないなら送りません。

API の定義では、ノード1つずつの形(node)にも additionalProperties: false が付いています。GET の nodes に定義に無い項目が入っていると、この手順どおりでも同じ形の 400 で弾かれることがあります。弊社では、実際にそうなるかは確かめていません。弾かれたときは、message に出た項目の場所を見ます。

3. 応答を見て、実行の記録まで確かめる

jq '{versionId, activeVersionId}' put.json

ソースの上では、公開中なら PUT だけで公開し直しまで進み、versionId と activeVersionId が同じ新しい値になります。versionId が PUT の前と同じなら、送った nodes と connections がデータベースと同じだったということです。

ただし、PUT で公開し直される動きは、弊社の本番では確かめていません。弊社の記録には、PUT のあとも古いまま動いた例があります。後の「直ったかを確かめる」のとおり、実行の記録に目印が出たかまで見ます。

4. PUT がエラーを返したら、GET で状態を見る

400 なら、応答の message に弾かれた理由が入ります。そのうえで GET し、activeVersionId を before.json と比べます。

GET の activeVersionId 起きていること(ソースから読めること) 次の一手
空(null) 新しい登録に失敗し、止まっている 原因を直して activate を呼ぶ
before.json と違う値 データベースは新しい版。スケジュールのものは古い登録のまま動いている 原因を直して activate を呼び直す
before.json と同じ値 公開中の版は変わっていない 原因を直して PUT し直す

5. 動かすときは activate、止めるときは deactivate

止めているワークフローへの PUT は、新しい版を保存するだけで公開しません。動かすときは activate を呼びます。2.19.2 の API の定義では、activate の説明は「Publish a workflow. In n8n v1, this action was termed activating a workflow.」です。止めるときは deactivate を呼びます。

curl -s -X POST "https://XXXX/api/v1/workflows/XXXX/deactivate" \
  -H "X-N8N-API-KEY: XXXX" -o deact.json

エンドポイント(API の呼び先)の名前は版で変わっています。最新の公式ドキュメントでは、activate に「Deprecated: use POST /workflows/{id}/publish instead.」、deactivate に「Deprecated: use POST /workflows/{id}/unpublish instead.」とあり、PUT の説明にも「unless publishIfActive is set to false」が足されています。2.19.2 では activate と deactivate です。使っている n8n の API の定義で名前を確かめてください。

直ったかを確かめる

公開中の版に新しい中身が入ったか

GET の応答には、公開中の版の中身(activeVersion)も入っています。変えた Code ノードに目印の文字列があるかを数えます。

curl -s "https://XXXX/api/v1/workflows/XXXX" \
  -H "X-N8N-API-KEY: XXXX" -o now.json
jq '{versionId, activeVersionId}' now.json
jq -r '.activeVersion.nodes[] | select(.name=="XXXX") | .parameters.jsCode' now.json | grep -c "目印の文字列"

実行が新しい中身で走ったか

いちばん確かなのは実行の記録です。実行一覧の API に includeData=true を付けると、その実行で使われたワークフローの中身(workflowData)と、各ノードの出力が返ります。

curl -s "https://XXXX/api/v1/executions?workflowId=XXXX&includeData=true&limit=1" \
  -H "X-N8N-API-KEY: XXXX" -o ex.json
jq '.data[0] | {id, mode, status, startedAt}' ex.json
jq -r '.data[0].workflowData.nodes[] | select(.name=="XXXX") | .parameters.jsCode' ex.json | grep -c "目印の文字列"
jq '.data[0].data.resultData.runData["XXXX"][0].data.main[0][0].json' ex.json

2.19.2 の API の定義には、新しく実行を始めるエンドポイントがありません。Webhook で呼ぶか、次の予定時刻を待ちます。失敗した実行をやり直す POST /api/v1/executions/{id}/retry はあり、本文の loadWorkflow を true にすると最新の版でやり直すと説明されています。

確かめたいことは console.log でなく、Code ノードの戻り値の JSON に載せます。弊社の 2.19 系では、Code ノードの console.log は n8n のログファイルに一切出ませんでした。

止まったか

もう一度 GET して、active が false になったかに加えて、activeVersionId が空になったかを見ます。起動のときに見られるのは activeVersionId だからです。有効なものの一覧(?active=true)も activeVersionId で絞り込んでいます。

curl -s "https://XXXX/api/v1/workflows/XXXX" \
  -H "X-N8N-API-KEY: XXXX" -o after.json
jq '{active, activeVersionId}' after.json

そのうえで、次の予定時刻を過ぎても実行が増えないことを見ます。

再起動したとき

起動ログの「Activated workflow」の行を数え、有効なワークフローの数と比べます。弊社が再起動したときは144行で、データベースの有効144本と一致しました。トリガーも Webhook も登録されなかったものはこの行を出さないので、数が合わないときはまずそこを見ます。

それでも直らないとき

弊社で効いた手順:MCP で更新して公開する

弊社の記録で Code ノードの差し替えが反映されたのは、MCP サーバーの update_workflow で更新し、publish_workflow で公開する手順でした。MCP サーバーは弊社の 2.19.2 で使っている機能で、設定の画面で「Enable MCP access」を ON にし、ワークフローごとに「Available in MCP」を ON にして使います。つなぎ方はn8nのMCPサーバーをClaude Codeにつなぐ方法と本番の注意点にまとめています。

別の n8n や n8n の外で動いていないか

弊社は n8n を別のマシンへ移したとき、移す前のマシンの同じ名前のワークフローを、二重に動かないように止めました。止め忘れがあると、こちらを止めても向こうで動きます。手元の記録と実際の有効・無効が違っていたこともあるので、API で実際の状態を取って確かめます。また、毎日のお知らせの公開が n8n ではなくサーバーの crontab(決まった時刻にコマンドを動かす仕組み)で動いていたこともあります。

データベースを直接書き換えて反映させた例

弊社では別の件で、Code ノードの差し替えを反映するために、編集中の版(workflow_entity の nodes)と公開中の版(workflow_history の同じ versionId の行)を両方書き換え、n8n を再起動しました。そのあと起動ログの「Activated workflow」を確かめ、本番の経路で実行して結果を見ています。その環境では workflow_published_version の表が0行でした。

弊社の記録には、workflow_history に各ワークフロー1行しか残っていないことがあり、その場合は n8n の上で前の版に戻せない、とあります。直接書き換える前には、nodes をファイルへ退避します。再起動のあと「access to env vars denied」が出る場合は、n8nのCodeノードで「access to env vars denied」が出る原因と直し方にまとめています。

決めた時刻と違う時刻に動いている

弊社では、タイムゾーンの設定が無かったために、スケジュールが意図より13時間ずれて動いていました。n8nのスケジュールが13時間ずれる原因と直し方に書いています。

実行の記録が消えていて確かめられない

弊社では、実行の記録が約3.5日で消えていました。保存期間の上限(EXECUTIONS_DATA_MAX_AGE、既定は336時間)より先に、件数の上限(EXECUTIONS_DATA_PRUNE_MAX_COUNT、既定は10000件)に当たっていたためです。弊社は件数の上限を60000に上げました。

まとめ

  • API キーは Settings > n8n API で作り、ヘッダー X-N8N-API-KEY に入れて /api/v1 の下を呼びます。
  • GET の nodes は編集中の版です。スケジュールのワークフローは、登録したときの公開中の版で動き続けます。
  • PUT のあとは、応答に加えて実行の記録の目印で確かめます。PUT で公開し直される動きは、弊社の本番では確かめていません。
  • PUT がエラーを返したら、GET で activeVersionId を見ます。空なら止まっていて、前と違う値ならスケジュールが古い中身で動いていることがあります。
  • 止めるのは deactivate です。active だけでなく activeVersionId が空になったかも見ます。

参考にした公式ドキュメント

n8nの点検と構築のご相談

「APIで直したのに反映されない」「止めたはずのワークフローが動いている」といったn8nの不具合の点検や、業務の自動化の仕組みづくりをお引き受けしています。

お問い合わせはこちら

この記事を書いた人

貫名 孝夫(マルタマーケティング株式会社 代表取締役)。n8nで140本を超えるワークフローを本番で動かしながら、実際に起きた不具合と直し方を記録しています。会社概要