{ "kind": "open-flow-workflow", "version": 1, "name": "Todoist to Notion Sync", "content": { "modelVersion": 14, "document": { "bindings": {}, "graph": { "nodes": { "n_8a474b94bff17a44": { "name": "Check tasks every 30 seconds", "kind": "cron", "cronTimes": [ { "type": "cron", "expression": "*/30 * * * * *", "timezone": "UTC" } ] }, "n_9b13f61aa2c5c9f5": { "inputs": { "sourceLabel": { "kind": "value", "value": "send-to-notion" }, "batchLimit": { "kind": "value", "value": 50 } }, "name": "Read Todoist task batch", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sourceLabel" }, { "jsonSchema": { "type": "integer", "minimum": 1, "maximum": 500 }, "nullable": false, "handle": "batchLimit" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "tasks" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sourceLabel" } ], "name": "Read Todoist task batch", "moduleId": "n_8bb08ef13b0833b1", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "todoist.list_tasks" } ] } ] } }, "n_9ae79e564bb35672": { "inputs": { "tasks": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9b13f61aa2c5c9f5", "output": "tasks" } ] } }, "name": "Validate task titles and IDs", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "tasks" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "description": { "type": "string" }, "labels": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "content", "description", "labels" ], "additionalProperties": false } }, "nullable": false, "handle": "tasks" } ], "name": "Validate task titles and IDs", "moduleId": "n_9d7cfc4fde46f094", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_92f4c7fb2b38105e": { "inputs": {}, "name": "Has tasks to import", "kind": "condition", "matchMode": "first", "cases": [ { "output": "tasks", "groups": [ { "expressions": [ { "left": { "kind": "source", "source": { "kind": "node", "nodeId": "n_9b13f61aa2c5c9f5", "output": "count" } }, "operator": ">", "right": { "kind": "value", "value": 0 } } ] } ] } ] }, "n_ee07e6614d3523e2": { "inputs": { "dataSourceId": { "kind": "value", "value": "YOUR_NOTION_DATA_SOURCE_ID" } }, "name": "Read Notion table properties", "kind": "task", "task": { "inputs": [ { "description": "The data source ID to retrieve.", "jsonSchema": { "type": "string", "description": "The data source ID to retrieve." }, "nullable": false, "handle": "dataSourceId" } ], "outputs": [ { "description": "The full data source object returned by the API.", "jsonSchema": { "type": "object", "properties": { "object": { "const": "data_source", "description": "The Notion object type." }, "id": { "type": "string", "description": "The data source ID." }, "created_time": { "type": "string", "format": "date-time", "description": "The time when the data source was created." }, "last_edited_time": { "type": "string", "format": "date-time", "description": "The time when the data source was last edited." }, "created_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "last_edited_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "title": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "A Notion rich text object." }, "description": "The data source title rich text objects." }, "description": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "A Notion rich text object." }, "description": "The data source description rich text objects." }, "icon": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The data source icon object, or null when it has no icon." }, "properties": { "type": "object", "additionalProperties": { "description": "A Notion property value or property schema object." }, "description": "The Notion page, database, or data source properties keyed by property name." }, "parent": { "type": "object", "properties": { "type": { "type": "string", "description": "The parent type, such as workspace, page_id, data_source_id, database_id, or block_id." } }, "additionalProperties": true, "description": "The parent object that contains this Notion object." }, "url": { "type": "string", "format": "uri", "description": "The canonical Notion URL for the data source." }, "in_trash": { "type": "boolean", "description": "Whether the data source is in the trash." } }, "additionalProperties": true, "description": "The full data source object returned by the API." }, "nullable": false, "handle": "output" } ], "name": "Read Notion table properties", "executor": { "kind": "connector", "action": "notion.retrieve_data_source", "outputMode": "value" } } }, "n_de006cebf08e466a": { "inputs": { "tasks": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9ae79e564bb35672", "output": "tasks" } ] }, "schema": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_ee07e6614d3523e2", "output": "output" } ] }, "idProperty": { "kind": "value", "value": "Todoist ID" } }, "name": "Prepare Notion task rows", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "description": { "type": "string" }, "labels": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "content", "description", "labels" ], "additionalProperties": false } }, "nullable": false, "handle": "tasks" }, { "jsonSchema": { "type": "object", "properties": { "object": { "const": "data_source", "description": "The Notion object type." }, "id": { "type": "string", "description": "The data source ID." }, "created_time": { "type": "string", "format": "date-time", "description": "The time when the data source was created." }, "last_edited_time": { "type": "string", "format": "date-time", "description": "The time when the data source was last edited." }, "created_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "last_edited_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "title": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "A Notion rich text object." }, "description": "The data source title rich text objects." }, "description": { "type": "array", "items": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "A Notion rich text object." }, "description": "The data source description rich text objects." }, "icon": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The data source icon object, or null when it has no icon." }, "properties": { "type": "object", "additionalProperties": { "description": "A Notion property value or property schema object." }, "description": "The Notion page, database, or data source properties keyed by property name." }, "parent": { "type": "object", "properties": { "type": { "type": "string", "description": "The parent type, such as workspace, page_id, data_source_id, database_id, or block_id." } }, "additionalProperties": true, "description": "The parent object that contains this Notion object." }, "url": { "type": "string", "format": "uri", "description": "The canonical Notion URL for the data source." }, "in_trash": { "type": "boolean", "description": "Whether the data source is in the trash." } }, "additionalProperties": true, "description": "The full data source object returned by the API." }, "nullable": false, "handle": "schema" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "idProperty" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string" }, "parent": { "type": "object", "additionalProperties": { "description": "A Notion parent field value." }, "description": "The official Notion parent object payload. Use { page_id: \"...\" } for a child page under an existing page, { data_source_id: \"...\" } for a data source row, or { workspace: true } to create a workspace-level private page when the credential is an OAuth public integration. When parent is provided, do not use the top-level title field; set the title through properties.title instead. Internal integration secrets usually cannot create workspace-level private pages and should use a parent page or data source." }, "properties": { "type": "object", "additionalProperties": { "description": "A Notion page property value." }, "description": "The page properties." } }, "required": [ "taskId", "parent", "properties" ], "additionalProperties": false } }, "nullable": false, "handle": "rows" } ], "name": "Prepare Notion task rows", "moduleId": "n_f110cd47d21b80b1", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_fd2f2e6850368fab": { "inputs": { "rows": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_de006cebf08e466a", "output": "rows" } ] } }, "name": "Create Notion pages in order", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string" }, "parent": { "type": "object", "additionalProperties": { "description": "A Notion parent field value." }, "description": "The official Notion parent object payload. Use { page_id: \"...\" } for a child page under an existing page, { data_source_id: \"...\" } for a data source row, or { workspace: true } to create a workspace-level private page when the credential is an OAuth public integration. When parent is provided, do not use the top-level title field; set the title through properties.title instead. Internal integration secrets usually cannot create workspace-level private pages and should use a parent page or data source." }, "properties": { "type": "object", "additionalProperties": { "description": "A Notion page property value." }, "description": "The page properties." } }, "required": [ "taskId", "parent", "properties" ], "additionalProperties": false } }, "nullable": false, "handle": "rows" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string" }, "page": { "type": "object", "properties": { "object": { "const": "page", "description": "The Notion object type." }, "id": { "type": "string", "description": "The page ID." }, "created_time": { "type": "string", "format": "date-time", "description": "The time when the page was created." }, "last_edited_time": { "type": "string", "format": "date-time", "description": "The time when the page was last edited." }, "created_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "last_edited_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "cover": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The page cover object, or null when the page has no cover." }, "icon": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The page icon object, or null when the page has no icon." }, "parent": { "type": "object", "properties": { "type": { "type": "string", "description": "The parent type, such as workspace, page_id, data_source_id, database_id, or block_id." } }, "additionalProperties": true, "description": "The parent object that contains this Notion object." }, "is_archived": { "type": "boolean", "description": "Whether the page has been archived." }, "in_trash": { "type": "boolean", "description": "Whether the page is in the trash." }, "is_locked": { "type": "boolean", "description": "Whether the page is locked." }, "properties": { "type": "object", "additionalProperties": { "description": "A Notion property value or property schema object." }, "description": "The Notion page, database, or data source properties keyed by property name." }, "url": { "type": "string", "format": "uri", "description": "The canonical Notion URL for the page." }, "public_url": { "type": [ "string", "null" ], "format": "uri", "description": "The public Notion URL if the page is published to the web." } }, "additionalProperties": true, "description": "The created Notion page object returned by the API." } }, "required": [ "taskId", "page" ], "additionalProperties": false } }, "nullable": false, "handle": "created" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "name": "Create Notion pages in order", "moduleId": "n_23b0e329510a144a", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "notion.create_page" } ] } ] } }, "n_7cfbe18c0f305de6": { "inputs": { "created": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_fd2f2e6850368fab", "output": "created" } ] }, "tasks": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9ae79e564bb35672", "output": "tasks" } ] }, "sourceLabel": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_9b13f61aa2c5c9f5", "output": "sourceLabel" } ] }, "sentLabel": { "kind": "value", "value": "sent" } }, "name": "Prepare task label and link updates", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string" }, "page": { "type": "object", "properties": { "object": { "const": "page", "description": "The Notion object type." }, "id": { "type": "string", "description": "The page ID." }, "created_time": { "type": "string", "format": "date-time", "description": "The time when the page was created." }, "last_edited_time": { "type": "string", "format": "date-time", "description": "The time when the page was last edited." }, "created_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "last_edited_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "cover": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The page cover object, or null when the page has no cover." }, "icon": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The page icon object, or null when the page has no icon." }, "parent": { "type": "object", "properties": { "type": { "type": "string", "description": "The parent type, such as workspace, page_id, data_source_id, database_id, or block_id." } }, "additionalProperties": true, "description": "The parent object that contains this Notion object." }, "is_archived": { "type": "boolean", "description": "Whether the page has been archived." }, "in_trash": { "type": "boolean", "description": "Whether the page is in the trash." }, "is_locked": { "type": "boolean", "description": "Whether the page is locked." }, "properties": { "type": "object", "additionalProperties": { "description": "A Notion property value or property schema object." }, "description": "The Notion page, database, or data source properties keyed by property name." }, "url": { "type": "string", "format": "uri", "description": "The canonical Notion URL for the page." }, "public_url": { "type": [ "string", "null" ], "format": "uri", "description": "The public Notion URL if the page is published to the web." } }, "additionalProperties": true, "description": "The created Notion page object returned by the API." } }, "required": [ "taskId", "page" ], "additionalProperties": false } }, "nullable": false, "handle": "created" }, { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "content": { "type": "string" }, "description": { "type": "string" }, "labels": { "type": "array", "items": { "type": "string" } } }, "required": [ "id", "content", "description", "labels" ], "additionalProperties": false } }, "nullable": false, "handle": "tasks" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sourceLabel" }, { "jsonSchema": { "type": "string" }, "nullable": false, "handle": "sentLabel" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string", "minLength": 1, "description": "Todoist task ID." }, "labels": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "A Todoist string value." }, "minItems": 1, "description": "Updated Todoist label names." }, "description": { "type": "string", "description": "Updated task description." } }, "required": [ "taskId", "labels", "description" ], "additionalProperties": false } }, "nullable": false, "handle": "updates" } ], "name": "Prepare task label and link updates", "moduleId": "n_75894fdb35ca99c8", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [] } ] } }, "n_e5f5cdff72baa163": { "inputs": { "updates": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_7cfbe18c0f305de6", "output": "updates" } ] } }, "name": "Update Todoist tasks in order", "kind": "task", "task": { "inputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string", "minLength": 1, "description": "Todoist task ID." }, "labels": { "type": "array", "items": { "type": "string", "minLength": 1, "description": "A Todoist string value." }, "minItems": 1, "description": "Updated Todoist label names." }, "description": { "type": "string", "description": "Updated task description." } }, "required": [ "taskId", "labels", "description" ], "additionalProperties": false } }, "nullable": false, "handle": "updates" } ], "outputs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "updated" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "name": "Update Todoist tasks in order", "moduleId": "n_3e7714dda0a5bc68", "capabilities": [ { "kind": "connector", "mode": "independent", "actions": [ { "action": "todoist.update_task" } ] } ] } }, "n_a27386d311913caf": { "name": "Imported tasks and pages", "kind": "outputs", "outputDefs": [ { "jsonSchema": { "type": "array", "items": { "type": "object", "properties": { "taskId": { "type": "string" }, "page": { "type": "object", "properties": { "object": { "const": "page", "description": "The Notion object type." }, "id": { "type": "string", "description": "The page ID." }, "created_time": { "type": "string", "format": "date-time", "description": "The time when the page was created." }, "last_edited_time": { "type": "string", "format": "date-time", "description": "The time when the page was last edited." }, "created_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "last_edited_by": { "type": "object", "properties": { "object": { "const": "user", "description": "The Notion object type." }, "id": { "type": "string", "description": "The Notion user ID." }, "name": { "type": [ "string", "null" ], "description": "The user's display name, or null when unavailable." }, "avatar_url": { "type": [ "string", "null" ], "description": "The user's avatar URL, or null when unavailable." }, "type": { "type": "string", "enum": [ "person", "bot" ], "description": "The user type returned by Notion." }, "person": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "description": "The person's email address." } }, "additionalProperties": true, "description": "Details about a person user." }, "bot": { "type": "object", "additionalProperties": { "description": "A Notion API field value." }, "description": "Details about a bot user." } }, "additionalProperties": true, "description": "A Notion user reference." }, "cover": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The page cover object, or null when the page has no cover." }, "icon": { "type": [ "object", "null" ], "additionalProperties": { "description": "A Notion API field value." }, "description": "The page icon object, or null when the page has no icon." }, "parent": { "type": "object", "properties": { "type": { "type": "string", "description": "The parent type, such as workspace, page_id, data_source_id, database_id, or block_id." } }, "additionalProperties": true, "description": "The parent object that contains this Notion object." }, "is_archived": { "type": "boolean", "description": "Whether the page has been archived." }, "in_trash": { "type": "boolean", "description": "Whether the page is in the trash." }, "is_locked": { "type": "boolean", "description": "Whether the page is locked." }, "properties": { "type": "object", "additionalProperties": { "description": "A Notion property value or property schema object." }, "description": "The Notion page, database, or data source properties keyed by property name." }, "url": { "type": "string", "format": "uri", "description": "The canonical Notion URL for the page." }, "public_url": { "type": [ "string", "null" ], "format": "uri", "description": "The public Notion URL if the page is published to the web." } }, "additionalProperties": true, "description": "The created Notion page object returned by the API." } }, "required": [ "taskId", "page" ], "additionalProperties": false } }, "nullable": false, "handle": "created" }, { "jsonSchema": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "nullable": false, "handle": "updated" }, { "jsonSchema": { "type": "integer", "minimum": 0 }, "nullable": false, "handle": "count" } ], "outputMappings": { "created": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_fd2f2e6850368fab", "output": "created" } ] }, "updated": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_e5f5cdff72baa163", "output": "updated" } ] }, "count": { "kind": "sources", "sources": [ { "kind": "node", "nodeId": "n_e5f5cdff72baa163", "output": "count" } ] } } } }, "edges": [ { "source": "n_8a474b94bff17a44", "target": "n_9b13f61aa2c5c9f5" }, { "source": "n_9b13f61aa2c5c9f5", "target": "n_9ae79e564bb35672" }, { "source": "n_9ae79e564bb35672", "target": "n_92f4c7fb2b38105e" }, { "source": "n_92f4c7fb2b38105e", "target": "n_ee07e6614d3523e2", "sourceHandle": "tasks" }, { "source": "n_ee07e6614d3523e2", "target": "n_de006cebf08e466a" }, { "source": "n_de006cebf08e466a", "target": "n_fd2f2e6850368fab" }, { "source": "n_fd2f2e6850368fab", "target": "n_7cfbe18c0f305de6" }, { "source": "n_7cfbe18c0f305de6", "target": "n_e5f5cdff72baa163" }, { "source": "n_e5f5cdff72baa163", "target": "n_a27386d311913caf" } ] } }, "modules": { "n_8bb08ef13b0833b1": { "name": "Read Todoist task batch", "imports": [], "source": "export default async function readSyncTasks({ sourceLabel, batchLimit }, context) {\n const tasks = [], seen = new Set();\n const limit = Math.min(batchLimit, 200);\n let cursor;\n do {\n const page = await context.actions.todoist.list_tasks({ label: sourceLabel, limit, ...(cursor ? { cursor } : {}) });\n if (!Array.isArray(page.tasks)) throw new Error('Todoist returned no tasks array');\n tasks.push(...page.tasks.slice(0, batchLimit - tasks.length));\n if (tasks.length >= batchLimit) break;\n cursor = page.nextCursor;\n if (cursor != null && (typeof cursor !== 'string' || !cursor || seen.has(cursor))) throw new Error('Todoist returned an invalid or repeated cursor');\n if (cursor) seen.add(cursor);\n } while (cursor);\n return { tasks, count: tasks.length, sourceLabel };\n}\n" }, "n_9d7cfc4fde46f094": { "name": "Validate task titles and IDs", "imports": [], "source": "export default function validateSyncTasks({ tasks }) {\n return { tasks: tasks.map((task) => {\n if (typeof task.id !== 'string' || !task.id || task.id.length > 2000) throw new Error('A Todoist task has an invalid text ID');\n if (typeof task.content !== 'string' || !task.content || task.content.length > 2000) throw new Error('A Todoist task title cannot fit in a Notion title field');\n if (!Array.isArray(task.labels) || task.labels.some((label) => typeof label !== 'string' || !label)) throw new Error('Todoist did not return the task label names');\n if (task.description != null && typeof task.description !== 'string') throw new Error('A Todoist task has an invalid description');\n return { id: task.id, content: task.content, description: task.description ?? '', labels: task.labels };\n }) };\n}\n" }, "n_f110cd47d21b80b1": { "name": "Prepare Notion task rows", "imports": [], "source": "export default function notionTaskRows({ tasks, schema, idProperty }) {\n if (typeof schema.id !== 'string' || !schema.id) throw new Error('Notion returned no data source ID');\n const titles = Object.entries(schema.properties ?? {}).filter(([, property]) => property.type === 'title').map(([name]) => name);\n if (titles.length !== 1) throw new Error('The Notion data source must have exactly one title property');\n if (schema.properties?.[idProperty]?.type !== 'rich_text') throw new Error('Configure a Notion rich-text property for the Todoist ID');\n return { rows: tasks.map((task) => ({ taskId: task.id, parent: { type: 'data_source_id', data_source_id: schema.id }, properties: {\n [titles[0]]: { title: [{ type: 'text', text: { content: task.content } }] },\n [idProperty]: { rich_text: [{ type: 'text', text: { content: task.id } }] },\n } })) };\n}\n" }, "n_23b0e329510a144a": { "name": "Create Notion pages in order", "imports": [], "source": "export default async function createNotionTaskPages({ rows }, context) {\n const created = [];\n for (const { taskId, parent, properties } of rows) {\n const page = await context.actions.notion.create_page({ parent, properties });\n if (typeof page.url !== 'string' || !page.url) throw new Error('The created Notion page has no URL; inspect Notion before retrying');\n const url = new URL(page.url);\n if (!['http:', 'https:'].includes(url.protocol)) throw new Error('The created Notion page has an invalid URL');\n created.push({ taskId, page });\n }\n return { created, count: created.length };\n}\n" }, "n_75894fdb35ca99c8": { "name": "Prepare task label and link updates", "imports": [], "source": "export default function prepareSyncUpdates({ created, tasks, sourceLabel, sentLabel }) {\n if (typeof sentLabel !== 'string' || !sentLabel) throw new Error('Configure a completed-sync label');\n if (created.length !== tasks.length || created.some(({ taskId }, index) => taskId !== tasks[index].id)) throw new Error('Notion page results are not associated with their Todoist tasks');\n const updates = created.map(({ page }, index) => {\n const task = tasks[index];\n return {\n taskId: task.id,\n labels: [...new Set([...task.labels.filter((label) => label !== sourceLabel), sentLabel])],\n description: 'Notion Link: ' + page.url + '\\n\\n' + task.description,\n };\n });\n return { updates };\n}\n" }, "n_3e7714dda0a5bc68": { "name": "Update Todoist tasks in order", "imports": [], "source": "export default async function applySyncUpdates({ updates }, context) {\n const updated = [];\n for (const update of updates) updated.push((await context.actions.todoist.update_task(update)).task);\n return { updated, count: updated.length };\n}\n" } } }, "presentation": { "designer": { "version": 1, "flow": { "direction": "vertical" } } } }