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": "Claude Config Sync Webhook",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "github-app-installation",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-node",
"name": "GitHub App Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
3264,
752
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 1
},
"conditions": [
{
"id": "installation-event",
"leftValue": "={{ $json.headers['x-github-event'] }}",
"rightValue": "installation",
"operator": {
"type": "string",
"operation": "equals"
}
},
{
"id": "installation-repositories-event",
"leftValue": "={{ $json.headers['x-github-event'] }}",
"rightValue": "installation_repositories",
"operator": {
"type": "string",
"operation": "equals"
}
},
{
"id": "issues-event",
"leftValue": "={{ $json.headers['x-github-event'] }}",
"rightValue": "issues",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "or"
},
"options": {}
},
"id": "filter-events",
"name": "Filter Events",
"type": "n8n-nodes-base.filter",
"typeVersion": 2,
"position": [
4160,
656
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "action-created",
"leftValue": "={{ $json.body.action }}",
"rightValue": "created",
"operator": {
"type": "string",
"operation": "equals"
}
},
{
"id": "action-added",
"leftValue": "={{ $json.body.action }}",
"rightValue": "added",
"operator": {
"type": "string",
"operation": "equals"
}
},
{
"id": "action-edited-dashboard",
"leftValue": "={{ $json.body.action === 'edited' && ($json.body.issue?.title || '').includes('Claude Config Sync Dashboard') && ($json.body.issue?.body || '').includes('[x] **Request sync now**') }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "or"
},
"options": {}
},
"id": "filter-actions",
"name": "Filter Actions",
"type": "n8n-nodes-base.filter",
"typeVersion": 2,
"position": [
4384,
656
]
},
{
"parameters": {
"jsCode": "// Extract target repos based on event type\nconst event = $input.first().json.headers['x-github-event'];\nconst body = $input.first().json.body;\nlet target_repos = '';\n\nif (event === 'installation' && body.action === 'created') {\n // New installation - repos in body.repositories\n const repos = body.repositories || [];\n target_repos = repos.map(r => r.full_name).join(',');\n} else if (event === 'installation_repositories' && body.action === 'added') {\n // Repos added to installation - repos in body.repositories_added\n const repos = body.repositories_added || [];\n target_repos = repos.map(r => r.full_name).join(',');\n} else if (event === 'issues' && body.action === 'edited') {\n // Dashboard sync request - single repo\n target_repos = body.repository.full_name;\n}\n\nreturn [{ json: { target_repos, headers: $input.first().json.headers, body } }];"
},
"id": "extract-target-repos",
"name": "Extract Target Repos",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
4608,
656
]
},
{
"parameters": {
"authentication": "oAuth2",
"resource": "workflow",
"owner": {
"__rl": true,
"value": "YOUR_GITHUB_USERNAME",
"mode": "name"
},
"repository": {
"__rl": true,
"value": "claude-config",
"mode": "name"
},
"workflowId": {
"__rl": true,
"mode": "filename",
"value": "sync-to-repos.yaml"
},
"ref": {
"__rl": true,
"value": "main",
"mode": "name"
},
"inputs": "={{ JSON.stringify({ target_repos: $json.target_repos }) }}"
},
"id": "trigger-workflow",
"name": "Trigger Workflow Dispatch",
"type": "n8n-nodes-base.github",
"typeVersion": 1.1,
"position": [
4832,
656
],
"credentials": {
"githubOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "noData",
"options": {
"responseCode": 200
}
},
"id": "respond-200",
"name": "Respond 200 OK",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3936,
656
],
"typeVersion": 1.4
},
{
"parameters": {
"respondWith": "noData",
"options": {
"responseCode": 401
}
},
"id": "respond-401",
"name": "Respond 401 Unauthorized",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3936,
848
],
"typeVersion": 1.4
},
{
"parameters": {
"action": "hmac",
"type": "SHA256",
"value": "={{ JSON.stringify($json.body) }}",
"dataPropertyName": "=signature-256",
"secret": "YOUR_GITHUB_WEBHOOK_SECRET"
},
"id": "compute-hmac",
"name": "Compute HMAC256",
"type": "n8n-nodes-base.crypto",
"position": [
3488,
752
],
"typeVersion": 1
},
{
"parameters": {
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "validate-signature",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json['signature-256'] }}",
"rightValue": "={{ $json.headers['x-hub-signature-256'].split('=').pop() }}"
}
]
},
"options": {}
},
"id": "validate-hmac",
"name": "Validate HMAC256",
"type": "n8n-nodes-base.if",
"position": [
3712,
752
],
"typeVersion": 2.2
},
{
"parameters": {
"errorMessage": "HMAC256 signature doesn't match provided signature. Make sure that the GitHub webhook secret is identical to the secret stored in the 'Compute HMAC256' node."
},
"id": "stop-error",
"name": "Stop and Error",
"type": "n8n-nodes-base.stopAndError",
"position": [
4160,
848
],
"typeVersion": 1
}
],
"connections": {
"GitHub App Webhook": {
"main": [
[
{
"node": "Compute HMAC256",
"type": "main",
"index": 0
}
]
]
},
"Filter Events": {
"main": [
[
{
"node": "Filter Actions",
"type": "main",
"index": 0
}
]
]
},
"Filter Actions": {
"main": [
[
{
"node": "Extract Target Repos",
"type": "main",
"index": 0
}
]
]
},
"Extract Target Repos": {
"main": [
[
{
"node": "Trigger Workflow Dispatch",
"type": "main",
"index": 0
}
]
]
},
"Trigger Workflow Dispatch": {
"main": [
[]
]
},
"Respond 200 OK": {
"main": [
[
{
"node": "Filter Events",
"type": "main",
"index": 0
}
]
]
},
"Compute HMAC256": {
"main": [
[
{
"node": "Validate HMAC256",
"type": "main",
"index": 0
}
]
]
},
"Validate HMAC256": {
"main": [
[
{
"node": "Respond 200 OK",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond 401 Unauthorized",
"type": "main",
"index": 0
}
]
]
},
"Respond 401 Unauthorized": {
"main": [
[
{
"node": "Stop and Error",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
githubOAuth2Api
About this workflow
Claude Config Sync Webhook. Uses github, respondToWebhook, crypto, stopAndError. Webhook trigger; 10 nodes.
Source: https://github.com/anthony-spruyt/claude-config/blob/1bc9e3fb701a848fc5c983ebc1987aeaf9b99100/.n8n/github-app-webhook-to-workflow-dispatch.json — original creator credit. Request a take-down →