This workflow corresponds to n8n.io template #omniproject-openproject — we link there as the canonical source.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "OmniProject \u2014 OpenProject",
"meta": {
"templateId": "omniproject-openproject",
"description": "Generated OmniProject contract workflow for OpenProject. Set env: OPENPROJECT_INSTANCE_URL."
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "omniproject",
"responseMode": "responseNode",
"options": {}
},
"id": "aaaaaaaa-0000-4000-8000-000000000000",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-520,
320
],
"notes": "POST body { action, payload, source, origin, idempotencyKey }."
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.verify }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
},
"options": {}
},
"id": "aaaaaaaa-0000-4000-8000-000000000001",
"name": "Verify probe?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-320,
320
],
"notes": "When the gateway's workflow verifier sends { verify: true }, short-circuit with a no-op acknowledgement so verification never touches the backend."
},
{
"parameters": {
"jsCode": "// No-op acknowledgement for the OmniProject workflow verifier.\nconst body = $('Webhook').first().json.body;\nconst caps = {\"issues\":true,\"scheduling\":true,\"portfolio\":true,\"resources\":false,\"financials\":false,\"baseline\":true,\"blockers\":false,\"history\":true,\"raid\":false};\nreturn [{ json: { success: true, data: { action: body.action, verified: true, backend: \"openproject\", capabilities: caps }, message: 'verify ok' } }];"
},
"id": "aaaaaaaa-0000-4000-8000-000000000002",
"name": "Verify ACK",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-120,
140
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.origin }}",
"rightValue": "={{ $json.body.payload && $json.body.payload.lastUpdatedBy }}",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
]
},
"options": {}
},
"id": "aaaaaaaa-0000-4000-8000-000000000003",
"name": "Drop loop?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-120,
460
],
"notes": "Loop guard: drop echoes where origin === payload.lastUpdatedBy (best-effort; the gateway idempotency key is the primary dedupe)."
},
{
"parameters": {
"jsCode": "return [{ json: { success: true, data: { dropped: true }, message: 'Loop mutation dropped' } }];"
},
"id": "aaaaaaaa-0000-4000-8000-000000000004",
"name": "Drop (loop)",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
120,
620
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.action }}",
"rightValue": "list_projects",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "list_projects"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.action }}",
"rightValue": "list_issues",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "list_issues"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.action }}",
"rightValue": "create_issue",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "create_issue"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.action }}",
"rightValue": "update_issue",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "update_issue"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.action }}",
"rightValue": "delete_issue",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "delete_issue"
},
{
"conditions": {
"options": {
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"leftValue": "={{ $json.body.action }}",
"rightValue": "get_capabilities",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"renameOutput": true,
"outputKey": "get_capabilities"
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"id": "aaaaaaaa-0000-4000-8000-000000000005",
"name": "Route Action",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
120,
320
]
},
{
"parameters": {
"jsCode": "// Normalize the backend response to { success, data, message }.\nconst action = $('Webhook').first().json.body.action;\nconst rows = items.map((i) => i.json);\nconst data = rows.length === 1 ? rows[0] : rows;\nreturn [{ json: { success: true, data, message: action + ' ok' } }];"
},
"id": "aaaaaaaa-0000-4000-8000-000000000006",
"name": "Normalize \u2192 N8nActionResult",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
620,
320
]
},
{
"parameters": {
"jsCode": "const action = $('Webhook').first().json.body.action;\nreturn [{ json: { success: false, data: {}, message: 'Unsupported action: ' + action } }];"
},
"id": "aaaaaaaa-0000-4000-8000-000000000007",
"name": "Unsupported Action",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
620,
560
]
},
{
"parameters": {
"respondWith": "firstIncomingItem",
"options": {}
},
"id": "aaaaaaaa-0000-4000-8000-000000000008",
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
880,
320
]
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.OPENPROJECT_INSTANCE_URL }}/api/v3/projects",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.body.payload.userContext.token }}"
}
]
},
"options": {}
},
"id": "aaaaaaaa-0000-4000-8000-000000000009",
"name": "List Projects",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
380,
80
]
},
{
"parameters": {
"method": "GET",
"url": "={{ $env.OPENPROJECT_INSTANCE_URL }}/api/v3/projects/{{ $json.body.payload.projectId }}/work_packages",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.body.payload.userContext.token }}"
}
]
},
"options": {}
},
"id": "aaaaaaaa-0000-4000-8000-00000000000a",
"name": "List Issues",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
380,
260
]
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.OPENPROJECT_INSTANCE_URL }}/api/v3/work_packages",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.body.payload.userContext.token }}"
},
{
"name": "X-OmniProject-Idempotency-Key",
"value": "={{ $json.body.idempotencyKey }}"
}
]
},
"options": {},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ subject: $json.body.payload.title, description: { raw: $json.body.payload.description }, _links: { project: { href: '/api/v3/projects/' + $json.body.payload.projectId } } }) }}"
},
"id": "aaaaaaaa-0000-4000-8000-00000000000b",
"name": "Create Issue",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
380,
440
]
},
{
"parameters": {
"method": "PATCH",
"url": "={{ $env.OPENPROJECT_INSTANCE_URL }}/api/v3/work_packages/{{ $json.body.payload.issueId }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.body.payload.userContext.token }}"
},
{
"name": "X-OmniProject-Idempotency-Key",
"value": "={{ $json.body.idempotencyKey }}"
}
]
},
"options": {},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ lockVersion: $json.body.payload.expectedVersion, subject: $json.body.payload.title }) }}"
},
"id": "aaaaaaaa-0000-4000-8000-00000000000c",
"name": "Update Issue",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
380,
620
],
"notes": "OpenProject enforces optimistic concurrency via lockVersion \u2014 pass expectedVersion through as lockVersion."
},
{
"parameters": {
"method": "DELETE",
"url": "={{ $env.OPENPROJECT_INSTANCE_URL }}/api/v3/work_packages/{{ $json.body.payload.issueId }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "=Bearer {{ $json.body.payload.userContext.token }}"
},
{
"name": "X-OmniProject-Idempotency-Key",
"value": "={{ $json.body.idempotencyKey }}"
}
]
},
"options": {}
},
"id": "aaaaaaaa-0000-4000-8000-00000000000d",
"name": "Delete Issue",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
380,
800
]
},
{
"parameters": {
"jsCode": "// Declare which domains your wired backend(s) can populate. Edit to match.\nreturn [{ json: { success: true, data: {\"issues\":true,\"scheduling\":true,\"portfolio\":true,\"resources\":false,\"financials\":false,\"baseline\":true,\"blockers\":false,\"history\":true,\"raid\":false} } }];"
},
"id": "aaaaaaaa-0000-4000-8000-00000000000e",
"name": "Capabilities",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
380,
980
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Verify probe?",
"type": "main",
"index": 0
}
]
]
},
"Verify probe?": {
"main": [
[
{
"node": "Verify ACK",
"type": "main",
"index": 0
}
],
[
{
"node": "Drop loop?",
"type": "main",
"index": 0
}
]
]
},
"Verify ACK": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
},
"Drop loop?": {
"main": [
[
{
"node": "Route Action",
"type": "main",
"index": 0
}
],
[
{
"node": "Drop (loop)",
"type": "main",
"index": 0
}
]
]
},
"Drop (loop)": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
},
"Normalize \u2192 N8nActionResult": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
},
"Unsupported Action": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
},
"Route Action": {
"main": [
[
{
"node": "List Projects",
"type": "main",
"index": 0
}
],
[
{
"node": "List Issues",
"type": "main",
"index": 0
}
],
[
{
"node": "Create Issue",
"type": "main",
"index": 0
}
],
[
{
"node": "Update Issue",
"type": "main",
"index": 0
}
],
[
{
"node": "Delete Issue",
"type": "main",
"index": 0
}
],
[
{
"node": "Capabilities",
"type": "main",
"index": 0
}
],
[
{
"node": "Unsupported Action",
"type": "main",
"index": 0
}
]
]
},
"List Projects": {
"main": [
[
{
"node": "Normalize \u2192 N8nActionResult",
"type": "main",
"index": 0
}
]
]
},
"List Issues": {
"main": [
[
{
"node": "Normalize \u2192 N8nActionResult",
"type": "main",
"index": 0
}
]
]
},
"Create Issue": {
"main": [
[
{
"node": "Normalize \u2192 N8nActionResult",
"type": "main",
"index": 0
}
]
]
},
"Update Issue": {
"main": [
[
{
"node": "Normalize \u2192 N8nActionResult",
"type": "main",
"index": 0
}
]
]
},
"Delete Issue": {
"main": [
[
{
"node": "Normalize \u2192 N8nActionResult",
"type": "main",
"index": 0
}
]
]
},
"Capabilities": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
OmniProject — OpenProject. Uses httpRequest. Webhook trigger; 15 nodes.
Source: https://github.com/walshd1/Omniproject/blob/main/artifacts/n8n-blueprints/generated/omniproject-openproject.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n template provides enterprise-level version control for your workflows using GitHub integration. Stop losing hours to broken workflows and manual exports – get proper commit history, visual di
This flow creates dummy files for every item added in your *Arrs (Radarr/Sonarr) with the tag .
eek-Go v2 (Batch-Then-Review). Uses httpRequest. Webhook trigger; 75 nodes.
This workflow receives webhook requests from a content calendar and uses the X API v2 to publish text posts, threads, image/video posts, and polls, as well as delete existing posts and run a credentia
This workflow acts as a central API gateway for all technical indicator agents in the Binance Spot Market Quant AI system. It listens for incoming webhook requests and dynamically routes them to the c