AutomationFlowsData & Sheets › Sync State

Sync State

sync-state. Uses airtable. Webhook trigger; 28 nodes.

Webhook trigger★★★★☆ complexity28 nodesAirtable
Data & Sheets Trigger: Webhook Nodes: 28 Complexity: ★★★★☆ Added:

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 →

Download .json
{
  "name": "sync-state",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "sync-state",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "a1000000-0000-0000-0000-000000000001",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        240,
        480
      ]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "id": "c1",
                    "leftValue": "={{ ($json.body && $json.body.action) || $json.action || '' }}",
                    "rightValue": "getAll",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "getAll"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "id": "c2",
                    "leftValue": "={{ ($json.body && $json.body.action) || $json.action || '' }}",
                    "rightValue": "createStudent",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "createStudent"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "id": "c3",
                    "leftValue": "={{ ($json.body && $json.body.action) || $json.action || '' }}",
                    "rightValue": "deleteStudent",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "deleteStudent"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "id": "c4",
                    "leftValue": "={{ ($json.body && $json.body.action) || $json.action || '' }}",
                    "rightValue": "saveLibraryItem",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "saveLibraryItem"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "loose"
                },
                "conditions": [
                  {
                    "id": "c5",
                    "leftValue": "={{ ($json.body && $json.body.action) || $json.action || '' }}",
                    "rightValue": "saveAttempt",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "saveAttempt"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "ignoreCase": true
        }
      },
      "id": "a2000000-0000-0000-0000-000000000002",
      "name": "Action Switch",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.2,
      "position": [
        460,
        480
      ]
    },
    {
      "parameters": {
        "operation": "search",
        "base": {
          "__rl": true,
          "value": "appZQ5D66jzxmfwOm",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tblJ01dBWOiV1cnT6",
          "mode": "id"
        },
        "options": {}
      },
      "id": "a3000000-0000-0000-0000-000000000003",
      "name": "Students List",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 2.1,
      "position": [
        700,
        100
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const items = $input.all();\nconst students = (items || []).map(it => {\n  const j = (it && it.json) || {};\n  const f = j.fields || j || {};\n  const grade = Number(f.grade);\n  return {\n    id: j.id || j.recordId || '',\n    name: f.name || '',\n    grade: Number.isFinite(grade) && grade > 0 ? grade : 1,\n    country: f.country || 'UK',\n    subject: f.subject || '',\n    parentEmail: f.parent_email || undefined,\n    avatarColor: f.avatar_color || '#B6F2D7',\n  };\n});\nreturn [{ json: { _students: students } }];"
      },
      "id": "a3100000-0000-0000-0000-000000000031",
      "name": "Stash students",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        880,
        100
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "search",
        "base": {
          "__rl": true,
          "value": "appZQ5D66jzxmfwOm",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tblibktOQqFLFfwot",
          "mode": "id"
        },
        "options": {}
      },
      "id": "a4000000-0000-0000-0000-000000000004",
      "name": "LibraryItems List",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 2.1,
      "position": [
        1060,
        100
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const items = $input.all();\nconst safeParse = (s, fb) => { if (s === null || s === undefined || s === '') return fb; if (typeof s !== 'string') return s; try { return JSON.parse(s); } catch { return fb; } };\nconst libraryItems = (items || []).map(it => {\n  const j = (it && it.json) || {};\n  const f = j.fields || j || {};\n  return {\n    id: j.id || j.recordId || '',\n    type: f.type || 'diagnostic',\n    title: f.title || '',\n    studentId: (Array.isArray(f.student) ? f.student[0] : f.student) || '',\n    payload: safeParse(f.payload, {}),\n    createdAt: f.created_at || j.createdTime || new Date().toISOString(),\n  };\n});\nlet prev = {};\ntry { prev = $('Stash students').first().json || {}; } catch {}\nreturn [{ json: { _students: prev._students || [], _libraryItems: libraryItems } }];"
      },
      "id": "a4100000-0000-0000-0000-000000000041",
      "name": "Stash library",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1240,
        100
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "search",
        "base": {
          "__rl": true,
          "value": "appZQ5D66jzxmfwOm",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tbl83UCCmYxy7r7Ey",
          "mode": "id"
        },
        "options": {}
      },
      "id": "a5000000-0000-0000-0000-000000000005",
      "name": "QuizAttempts List",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 2.1,
      "position": [
        1420,
        100
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const items = $input.all();\nconst safeParse = (s, fb) => { if (s === null || s === undefined || s === '') return fb; if (typeof s !== 'string') return s; try { return JSON.parse(s); } catch { return fb; } };\nconst attempts = (items || []).map(it => {\n  const j = (it && it.json) || {};\n  const f = j.fields || j || {};\n  return {\n    id: j.id || j.recordId || '',\n    studentId: (Array.isArray(f.student) ? f.student[0] : f.student) || '',\n    libraryItemId: (Array.isArray(f.library_item) ? f.library_item[0] : f.library_item) || '',\n    score: Number.isFinite(Number(f.score)) ? Number(f.score) : 0,\n    skills: safeParse(f.skills_json, {}),\n    strengths: safeParse(f.strengths, []),\n    weaknesses: safeParse(f.weaknesses, []),\n    recommendations: safeParse(f.recommendations, []),\n    analysisText: f.analysis_text || '',\n    createdAt: f.created_at || j.createdTime || new Date().toISOString(),\n  };\n});\nlet prev = {};\ntry { prev = $('Stash library').first().json || {}; } catch {}\nreturn [{ json: { students: prev._students || [], libraryItems: prev._libraryItems || [], attempts } }];"
      },
      "id": "a6000000-0000-0000-0000-000000000006",
      "name": "Map getAll",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1600,
        100
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "a7000000-0000-0000-0000-000000000007",
      "name": "Respond getAll",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1800,
        100
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const p = (($json && $json.body && $json.body.payload) || ($json && $json.payload)) || {};\nif (!p || typeof p !== 'object') throw new Error('createStudent: missing payload');\nif (!p.name || !String(p.name).trim()) throw new Error('createStudent: name is required');\nconst grade = Number(p.grade);\nconst fields = {\n  name: String(p.name).trim(),\n  grade: Number.isFinite(grade) && grade > 0 ? grade : 1,\n  country: p.country || 'UK',\n  subject: p.subject || '',\n  avatar_color: p.avatarColor || '#B6F2D7',\n};\nif (p.parentEmail) fields.parent_email = String(p.parentEmail).trim();\nreturn [{ json: fields }];"
      },
      "id": "b1000000-0000-0000-0000-000000000001",
      "name": "Build student fields",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        460
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "create",
        "base": {
          "__rl": true,
          "value": "appZQ5D66jzxmfwOm",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tblJ01dBWOiV1cnT6",
          "mode": "id"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "name": "={{ $json.name }}",
            "grade": "={{ $json.grade }}",
            "country": "={{ $json.country }}",
            "subject": "={{ $json.subject }}",
            "parent_email": "={{ $json.parent_email }}",
            "avatar_color": "={{ $json.avatar_color }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "name",
              "displayName": "name",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "grade",
              "displayName": "grade",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "number",
              "display": true,
              "removed": false
            },
            {
              "id": "country",
              "displayName": "country",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "subject",
              "displayName": "subject",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "parent_email",
              "displayName": "parent_email",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "avatar_color",
              "displayName": "avatar_color",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            }
          ]
        },
        "options": {
          "typecast": true
        }
      },
      "id": "b2000000-0000-0000-0000-000000000002",
      "name": "Create Student",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 2.1,
      "position": [
        940,
        460
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const it = $input.first();\nconst j = (it && it.json) || {};\nconst f = j.fields || j || {};\nconst grade = Number(f.grade);\nreturn [{\n  json: {\n    id: j.id || j.recordId || '',\n    name: f.name || '',\n    grade: Number.isFinite(grade) && grade > 0 ? grade : 1,\n    country: f.country || 'UK',\n    subject: f.subject || '',\n    parentEmail: f.parent_email || undefined,\n    avatarColor: f.avatar_color || '#B6F2D7',\n  },\n}];"
      },
      "id": "b3000000-0000-0000-0000-000000000003",
      "name": "Map student response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1180,
        460
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "b4000000-0000-0000-0000-000000000004",
      "name": "Respond createStudent",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1420,
        460
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const id = (($json && $json.body && $json.body.payload) || ($json && $json.payload)) || '';\nif (!id || typeof id !== 'string') throw new Error('deleteStudent: payload must be a record id string');\nreturn [{ json: { id } }];"
      },
      "id": "c0500000-0000-0000-0000-000000000005",
      "name": "Build delete id",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        500,
        620
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "delete",
        "base": {
          "__rl": true,
          "value": "appZQ5D66jzxmfwOm",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tblJ01dBWOiV1cnT6",
          "mode": "id"
        },
        "id": "={{ $json.id }}"
      },
      "id": "c1000000-0000-0000-0000-000000000001",
      "name": "Delete Student",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 2.1,
      "position": [
        700,
        620
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ { \"success\": true } }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "c2000000-0000-0000-0000-000000000002",
      "name": "Respond deleteStudent",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        940,
        620
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const p = (($json && $json.body && $json.body.payload) || ($json && $json.payload)) || {};\nif (!p || typeof p !== 'object') throw new Error('saveLibraryItem: missing payload');\nif (!p.title || !String(p.title).trim()) throw new Error('saveLibraryItem: title is required');\nif (!p.type) throw new Error('saveLibraryItem: type is required');\nconst payloadStr = typeof p.payload === 'string' ? p.payload : JSON.stringify(p.payload || {});\nreturn [{\n  json: {\n    type: p.type,\n    title: String(p.title).trim(),\n    student: p.studentId ? [p.studentId] : [],\n    payload: payloadStr,\n  },\n}];"
      },
      "id": "d1000000-0000-0000-0000-000000000001",
      "name": "Build library fields",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        780
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "create",
        "base": {
          "__rl": true,
          "value": "appZQ5D66jzxmfwOm",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tblibktOQqFLFfwot",
          "mode": "id"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "type": "={{ $json.type }}",
            "title": "={{ $json.title }}",
            "student": "={{ $json.student }}",
            "payload": "={{ $json.payload }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "type",
              "displayName": "type",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "title",
              "displayName": "title",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "student",
              "displayName": "student",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "array",
              "display": true,
              "removed": false
            },
            {
              "id": "payload",
              "displayName": "payload",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            }
          ]
        },
        "options": {
          "typecast": true
        }
      },
      "id": "d2000000-0000-0000-0000-000000000002",
      "name": "Create LibraryItem",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 2.1,
      "position": [
        940,
        780
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const it = $input.first();\nconst j = (it && it.json) || {};\nconst f = j.fields || j || {};\nconst safeParse = (s, fb) => { if (s === null || s === undefined || s === '') return fb; if (typeof s !== 'string') return s; try { return JSON.parse(s); } catch { return fb; } };\nreturn [{\n  json: {\n    id: j.id || j.recordId || '',\n    type: f.type || 'diagnostic',\n    title: f.title || '',\n    studentId: (Array.isArray(f.student) ? f.student[0] : f.student) || '',\n    payload: safeParse(f.payload, {}),\n    createdAt: f.created_at || j.createdTime || new Date().toISOString(),\n  },\n}];"
      },
      "id": "d3000000-0000-0000-0000-000000000003",
      "name": "Map library response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1180,
        780
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "d4000000-0000-0000-0000-000000000004",
      "name": "Respond saveLibraryItem",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1420,
        780
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const p = (($json && $json.body && $json.body.payload) || ($json && $json.payload)) || {};\nif (!p || typeof p !== 'object') throw new Error('saveAttempt: missing payload');\nconst score = Number(p.score);\nreturn [{\n  json: {\n    student: p.studentId ? [p.studentId] : [],\n    library_item: p.libraryItemId ? [p.libraryItemId] : [],\n    score: Number.isFinite(score) ? score : 0,\n    skills_json: JSON.stringify(p.skills || {}),\n    strengths: JSON.stringify(p.strengths || []),\n    weaknesses: JSON.stringify(p.weaknesses || []),\n    recommendations: JSON.stringify(p.recommendations || []),\n    analysis_text: p.analysisText || '',\n  },\n}];"
      },
      "id": "e1000000-0000-0000-0000-000000000001",
      "name": "Build attempt fields",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        940
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "create",
        "base": {
          "__rl": true,
          "value": "appZQ5D66jzxmfwOm",
          "mode": "id"
        },
        "table": {
          "__rl": true,
          "value": "tbl83UCCmYxy7r7Ey",
          "mode": "id"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "student": "={{ $json.student }}",
            "library_item": "={{ $json.library_item }}",
            "score": "={{ $json.score }}",
            "skills_json": "={{ $json.skills_json }}",
            "strengths": "={{ $json.strengths }}",
            "weaknesses": "={{ $json.weaknesses }}",
            "recommendations": "={{ $json.recommendations }}",
            "analysis_text": "={{ $json.analysis_text }}"
          },
          "matchingColumns": [],
          "schema": [
            {
              "id": "student",
              "displayName": "student",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "array",
              "display": true,
              "removed": false
            },
            {
              "id": "library_item",
              "displayName": "library_item",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "array",
              "display": true,
              "removed": false
            },
            {
              "id": "score",
              "displayName": "score",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "number",
              "display": true,
              "removed": false
            },
            {
              "id": "skills_json",
              "displayName": "skills_json",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "strengths",
              "displayName": "strengths",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "weaknesses",
              "displayName": "weaknesses",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "recommendations",
              "displayName": "recommendations",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            },
            {
              "id": "analysis_text",
              "displayName": "analysis_text",
              "required": false,
              "defaultMatch": false,
              "canBeUsedToMatch": true,
              "type": "string",
              "display": true,
              "removed": false
            }
          ]
        },
        "options": {
          "typecast": true
        }
      },
      "id": "e2000000-0000-0000-0000-000000000002",
      "name": "Create QuizAttempt",
      "type": "n8n-nodes-base.airtable",
      "typeVersion": 2.1,
      "position": [
        940,
        940
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const it = $input.first();\nconst j = (it && it.json) || {};\nconst f = j.fields || j || {};\nconst safeParse = (s, fb) => { if (s === null || s === undefined || s === '') return fb; if (typeof s !== 'string') return s; try { return JSON.parse(s); } catch { return fb; } };\nconst score = Number(f.score);\nreturn [{\n  json: {\n    id: j.id || j.recordId || '',\n    studentId: (Array.isArray(f.student) ? f.student[0] : f.student) || '',\n    libraryItemId: (Array.isArray(f.library_item) ? f.library_item[0] : f.library_item) || '',\n    score: Number.isFinite(score) ? score : 0,\n    skills: safeParse(f.skills_json, {}),\n    strengths: safeParse(f.strengths, []),\n    weaknesses: safeParse(f.weaknesses, []),\n    recommendations: safeParse(f.recommendations, []),\n    analysisText: f.analysis_text || '',\n    createdAt: f.created_at || j.createdTime || new Date().toISOString(),\n  },\n}];"
      },
      "id": "e3000000-0000-0000-0000-000000000003",
      "name": "Map attempt response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1180,
        940
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "e4000000-0000-0000-0000-000000000004",
      "name": "Respond saveAttempt",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1420,
        940
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const data = $json || {};\nlet msg = 'sync-state: server error';\nif (data && data.error) {\n  if (typeof data.error === 'string') msg = data.error;\n  else if (data.error.message) msg = data.error.message;\n  else if (data.error.description) msg = data.error.description;\n  else msg = JSON.stringify(data.error).slice(0, 400);\n} else if (data && data.message) {\n  msg = data.message;\n}\nreturn [{ json: { error: msg } }];"
      },
      "id": "f1000000-0000-0000-0000-000000000001",
      "name": "Build Error Common",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1600,
        1140
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 500
        }
      },
      "id": "f2000000-0000-0000-0000-000000000002",
      "name": "Respond Error",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        1800,
        1140
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "const action = ($json && $json.body && $json.body.action) || ($json && $json.action) || '';\nreturn [{ json: { error: 'Unknown action: ' + (action ? JSON.stringify(action) : '(empty body)') + '. Expected one of: getAll, createStudent, deleteStudent, saveLibraryItem, saveAttempt.' } }];"
      },
      "id": "f3000000-0000-0000-0000-000000000003",
      "name": "Build Unknown Action Error",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        1300
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {
          "responseCode": 400
        }
      },
      "id": "f4000000-0000-0000-0000-000000000004",
      "name": "Respond Unknown Action",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        940,
        1300
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Action Switch",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Action Switch": {
      "main": [
        [
          {
            "node": "Students List",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build student fields",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build delete id",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build library fields",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build attempt fields",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Unknown Action Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Students List": {
      "main": [
        [
          {
            "node": "Stash students",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Stash students": {
      "main": [
        [
          {
            "node": "LibraryItems List",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LibraryItems List": {
      "main": [
        [
          {
            "node": "Stash library",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Stash library": {
      "main": [
        [
          {
            "node": "QuizAttempts List",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "QuizAttempts List": {
      "main": [
        [
          {
            "node": "Map getAll",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map getAll": {
      "main": [
        [
          {
            "node": "Respond getAll",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build student fields": {
      "main": [
        [
          {
            "node": "Create Student",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Student": {
      "main": [
        [
          {
            "node": "Map student response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map student response": {
      "main": [
        [
          {
            "node": "Respond createStudent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build delete id": {
      "main": [
        [
          {
            "node": "Delete Student",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Delete Student": {
      "main": [
        [
          {
            "node": "Respond deleteStudent",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build library fields": {
      "main": [
        [
          {
            "node": "Create LibraryItem",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create LibraryItem": {
      "main": [
        [
          {
            "node": "Map library response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map library response": {
      "main": [
        [
          {
            "node": "Respond saveLibraryItem",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build attempt fields": {
      "main": [
        [
          {
            "node": "Create QuizAttempt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create QuizAttempt": {
      "main": [
        [
          {
            "node": "Map attempt response",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map attempt response": {
      "main": [
        [
          {
            "node": "Respond saveAttempt",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Common",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Error Common": {
      "main": [
        [
          {
            "node": "Respond Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Unknown Action Error": {
      "main": [
        [
          {
            "node": "Respond Unknown Action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": []
}
Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

sync-state. Uses airtable. Webhook trigger; 28 nodes.

Source: https://github.com/kailasnath2255/sheldon-library/blob/715eca7e90828ed74e4d6e61faaa8d1b6bc837d5/n8n/workflows/sync-state.json — original creator credit. Request a take-down →

More Data & Sheets workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Data & Sheets

PURPOSE: Automatically send professional appointment reminders via email and SMS to reduce no-shows and improve patient experience.

Google Sheets, Airtable, Email Send +2
Data & Sheets

Buildnbloom - Typeform to Tier 1 Call. Uses supabase, airtable, httpRequest. Webhook trigger; 17 nodes.

Supabase, Airtable, HTTP Request
Data & Sheets

zaad9_teams_dane. Uses emailSend, airtable, slack, microsoftTeams. Webhook trigger; 7 nodes.

Email Send, Airtable, Slack +2
Data & Sheets

Convert Airtable Rich Text Markdown Field To Html. Uses airtable, markdown, stickyNote. Webhook trigger; 9 nodes.

Airtable
Data & Sheets

BP_check. Uses googleSheets, @n-octo-n/n8n-nodes-json-database, httpRequest, itemLists. Webhook trigger; 99 nodes.

Google Sheets, @N Octo N/N8N Nodes Json Database, HTTP Request +2