Describe the problem/error/question
Hi everyone! I’m new to this community, so thank you in advanced for sharing your input. ![]()
I’m trying to create an n8n workflow that automates my tracking/recording of:
- todoist task created
- todoist task completed
then logs these as new rows in a Google Sheet every time an event is triggered. (similar to the IFTTT application of Sheets + Todoist).
I’ve set it up using the /sync webhook on Todoist, but it seems that my webhook is never triggering even if I create or complete a new event on todoist. Am I missing something in my setup? Would appreciate any advice. Thank you!
What is the error message (if any)?
No error message, the webhook doesn’t trigger so the flow isn’t able to start even if new events should hypothetically trigger the flow.
Please share your workflow
(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)
{
"nodes": [
{
"parameters": {
"jsCode": "const staticData = $getWorkflowStaticData('global');\n\nconst syncToken = staticData.sync_token || '*';\n\nreturn {\n json: {\n sync_token: syncToken\n }\n};"
},
"id": "c4101c65-7a08-4da1-8b96-8235bbaa07dc",
"name": "Get Sync Token",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-672,
96
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.todoist.com/sync/v9/sync",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "sync_token",
"value": "={{ $json.sync_token }}"
},
{
"name": "resource_types",
"value": "[\"items\"]"
}
]
},
"options": {}
},
"id": "3d0f465a-ed14-4a85-8c81-78e288503834",
"name": "Todoist Sync API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [
-448,
96
],
"credentials": {
"httpHeaderAuth": {
"id": "Me6UOmhM8SAuXUNt",
"name": "Authorization"
}
}
},
{
"parameters": {
"jsCode": "// Update Sync Token for next run\nconst staticData = $getWorkflowStaticData('global'); // Added $ here\nstaticData.sync_token = $input.first().json.sync_token;\n\n// Pass items forward with a 'source' tag to identify them later\nconst items = $input.first().json.items || [];\nreturn items.map(item => ({ \n json: { \n ...item, \n _source: 'todoist' \n } \n}));"
},
"id": "f00a3779-0797-43ea-9c2e-f91334ec9b25",
"name": "Update Token & Extract Items",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-256,
96
]
},
{
"parameters": {
"documentId": {
"__rl": true,
"value": "1uws4XaPlETx4O4JfNfyPR6EaoZIqeNWXVPwBHIFGwg4",
"mode": "list",
"cachedResultName": "todoist-n8n-webhook",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1uws4XaPlETx4O4JfNfyPR6EaoZIqeNWXVPwBHIFGwg4/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Sheet1",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1uws4XaPlETx4O4JfNfyPR6EaoZIqeNWXVPwBHIFGwg4/edit#gid=0"
},
"options": {}
},
"id": "0e81ac8c-7697-41d7-8b49-885a298fef41",
"name": "Get Existing Rows",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.3,
"position": [
-208,
-96
],
"credentials": {
"googleSheetsOAuth2Api": {
"id": "D04x7uKtze4p5m1w",
"name": "Amber Google Sheets"
}
},
"continueOnFail": true
},
{
"parameters": {
"jsCode": "// 1. Get all data from the previous Append node\nconst allData = $input.all().map(item => item.json);\n\n// 2. Separate the list back into two groups using the '_source' tag\nconst todoistItems = allData.filter(item => item._source === 'todoist');\nconst existingRows = allData.filter(item => item._source !== 'todoist');\n\nconst newRows = [];\n\n// Helper to check if this specific state (Created/Completed) is already in the sheet\nconst logExists = (id, isCompleted) => {\n // We check if a row exists with the same ID AND the same completion status\n // Note: Sheets might return 'TRUE'/'FALSE' strings or boolean values, so we compare loosely\n return existingRows.some(row => \n row['taskId'] == id && String(row['completed']).toLowerCase() == String(isCompleted).toLowerCase()\n );\n};\n\n// 3. Process the Todoist items\ntodoistItems.forEach(item => {\n // Skip deleted items\n if (item.is_deleted) return;\n\n const id = item.id;\n \n // Determine if this is a completion event or creation event\n const isCompleted = item.checked === true; \n\n // LOGIC:\n // If task is Active (checked=false) -> Log it if we haven't logged an active version yet.\n // If task is Done (checked=true) -> Log it if we haven't logged a done version yet.\n \n if (!logExists(id, isCompleted)) {\n newRows.push({\n json: {\n 'taskId': id,\n 'taskName': item.content,\n 'completed': isCompleted, // This will be FALSE for created, TRUE for completed\n 'due': item.due ? item.due.date : '',\n 'priority': item.priority,\n 'description': item.description,\n 'sectionId': item.section_id,\n 'parentTaskId': item.parent_id,\n 'assigneeId': item.responsible_uid,\n 'createdDate': item.added_at, \n 'labels': item.labels ? item.labels.join(\", \") : \"\"\n }\n });\n }\n});\n\nreturn newRows;"
},
"id": "ca3e6d92-d874-49fd-8c9a-181fa3651c95",
"name": "Prepare New Rows",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
240,
112
]
},
{
"parameters": {},
"id": "5dedd061-fac1-49e4-afa6-a63712d4e21e",
"name": "Merge Data",
"type": "n8n-nodes-base.merge",
"typeVersion": 2.1,
"position": [
16,
112
]
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "1uws4XaPlETx4O4JfNfyPR6EaoZIqeNWXVPwBHIFGwg4",
"mode": "list",
"cachedResultName": "todoist-n8n-webhook",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1uws4XaPlETx4O4JfNfyPR6EaoZIqeNWXVPwBHIFGwg4/edit?usp=drivesdk"
},
"sheetName": {
"__rl": true,
"value": "gid=0",
"mode": "list",
"cachedResultName": "Sheet1",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1uws4XaPlETx4O4JfNfyPR6EaoZIqeNWXVPwBHIFGwg4/edit#gid=0"
},
"columns": {
"mappingMode": "autoMapInputData",
"value": {},
"matchingColumns": [],
"schema": [
{
"id": "taskId",
"displayName": "taskId",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "taskName",
"displayName": "taskName",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "sectionId",
"displayName": "sectionId",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "parentTaskId",
"displayName": "parentTaskId",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "completed",
"displayName": "completed",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "due",
"displayName": "due",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "priority",
"displayName": "priority",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "description",
"displayName": "description",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "parentTask",
"displayName": "parentTask",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "section",
"displayName": "section",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "assignee",
"displayName": "assignee",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "createdDate",
"displayName": "createdDate",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
},
{
"id": "labels",
"displayName": "labels",
"required": false,
"defaultMatch": false,
"display": true,
"type": "string",
"canBeUsedToMatch": true,
"removed": false
}
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {}
},
"id": "4cf3a954-3e78-47c7-a87c-ee7de4904578",
"name": "Add to Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.3,
"position": [
496,
160
],
"credentials": {
"googleSheetsOAuth2Api": {
"id": "D04x7uKtze4p5m1w",
"name": "Amber Google Sheets"
}
}
},
{
"parameters": {
"httpMethod": "POST",
"path": "todoist-updates",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-944,
80
],
"id": "2bc8e2e4-5d75-46b2-ae43-005cf4f4f657",
"name": "Webhook",
"webhookId": "ff8da601-2cf2-4ab8-84f3-2c766f9e9a98"
}
],
"connections": {
"Get Sync Token": {
"main": [
[
{
"node": "Todoist Sync API",
"type": "main",
"index": 0
}
]
]
},
"Todoist Sync API": {
"main": [
[
{
"node": "Update Token & Extract Items",
"type": "main",
"index": 0
}
]
]
},
"Update Token & Extract Items": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 0
}
]
]
},
"Get Existing Rows": {
"main": [
[
{
"node": "Merge Data",
"type": "main",
"index": 1
}
]
]
},
"Prepare New Rows": {
"main": [
[
{
"node": "Add to Sheets",
"type": "main",
"index": 0
}
]
]
},
"Merge Data": {
"main": [
[
{
"node": "Prepare New Rows",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Get Sync Token",
"type": "main",
"index": 0
},
{
"node": "Get Existing Rows",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "1d94077dbadd478a3fa551e5be967685a64c130b7870a76243ce62b52e1c02e2"
}
}
Share the output returned by the last node
Expected output should be a new row here:
But getting no executions:
Information on your n8n setup
- n8n version: Version 2.2.4
- Database (default: SQLite):
- n8n EXECUTIONS_PROCESS setting (default: own, main):
- Running n8n via (Docker, npm, n8n cloud, desktop app): GCP
- Operating system: Mac


