{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "28691ac2-6902-4428-ad78-c7d2d39c48e5",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -3392,
        1280
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Back up Hostinger Reach contacts and segments to Google Sheets daily\n\n### How it works\n\n1. A daily schedule trigger fires at 7am and initializes Google Sheets configuration (URLs and sheet names).\n2. The workflow fetches all Hostinger email contacts in paginated batches, looping through pages until all contacts are retrieved.\n3. Each contact is mapped to standard fields (uuid, email, name, surname) and upserted into a Google Sheet.\n4. In parallel, all Hostinger email segments are fetched, enriched with a sync timestamp, and upserted into a separate Google Sheet tab.\n\n### Setup steps\n\n- - [ ] Configure the Schedule Trigger node to set the desired daily run time (default: 7am).\n- - [ ] In 'Set - Config (Sheets)', provide the correct Google Sheet URL, contacts sheet name, and segments sheet name.\n- - [ ] Add valid Hostinger API credentials to the 'List Contacts Page' and 'List Segments' nodes.\n- - [ ] Add valid Google Sheets credentials to the 'Upsert Contacts to Sheet' and 'Upsert Segments to Sheet' nodes.\n- - [ ] Ensure the Google Sheets columns match the mapped fields: uuid, email, name, surname (contacts) and segment fields + last_synced_at (segments).\n\n### Customization\n\nYou can adjust the pagination logic in 'Set - Pagination Control' and 'More Pages?' to match the Hostinger API's pagination format. The sync timestamp field name in 'Set - Add Sync Timestamp' can be renamed to match your sheet schema."
      },
      "typeVersion": 1
    },
    {
      "id": "641501cc-d022-4994-a952-c0655e125313",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2832,
        1504
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 336,
        "content": "## Trigger and sheet config\n\nThe daily schedule trigger fires at 7am and immediately sets the Google Sheets configuration values (sheet URL, contacts sheet name, segments sheet name) used by downstream nodes."
      },
      "typeVersion": 1
    },
    {
      "id": "25684848-5a80-440c-8659-97a540a0f175",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2352,
        1392
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 320,
        "content": "## Initialize contact page fetch\n\nSets the initial page number and calls the Hostinger API to retrieve the first page of contacts, launching the paginated contact retrieval loop."
      },
      "typeVersion": 1
    },
    {
      "id": "e562043d-e962-485d-902e-e164e699d0d7",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1872,
        1280
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 320,
        "content": "## Process and save contacts\n\nSplits the contact list into individual records, maps each contact to standard fields (uuid, email, name, surname), and upserts them into the contacts Google Sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "bd047c68-2401-428f-80b0-3acb16f7dfdf",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1872,
        1632
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 384,
        "content": "## Paginate through contact pages\n\nChecks if more contact pages exist after each API call. If so, increments the page counter and loops back to fetch the next page until all contacts are retrieved."
      },
      "typeVersion": 1
    },
    {
      "id": "e256dfc0-81f8-4936-8b00-c7cc4f6d9873",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2352,
        2048
      ],
      "parameters": {
        "color": 7,
        "width": 912,
        "height": 304,
        "content": "## Fetch and save segments\n\nFetches all Hostinger email segments in a single call, splits them into individual records, adds a sync timestamp to each, and upserts them into the segments Google Sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "423721c8-8879-47e7-9465-57df04c68224",
      "name": "Every Day at 7am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -2784,
        1680
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 7
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "05c4a955-48a3-46e2-b96c-572c6a93d359",
      "name": "Set Sheet Config",
      "type": "n8n-nodes-base.set",
      "position": [
        -2544,
        1680
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg1",
              "name": "sheet_url",
              "type": "string",
              "value": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit"
            },
            {
              "id": "cfg2",
              "name": "contacts_sheet_name",
              "type": "string",
              "value": "Contacts"
            },
            {
              "id": "cfg3",
              "name": "segments_sheet_name",
              "type": "string",
              "value": "Segments"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "695ec9e1-1dde-4394-a744-c6fb7eb8874b",
      "name": "Initialize Page Number",
      "type": "n8n-nodes-base.set",
      "position": [
        -2304,
        1552
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "p1",
              "name": "page",
              "type": "number",
              "value": 1
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b81990f3-44d1-4b7c-97e1-c738f6e58960",
      "name": "Fetch Contacts Page",
      "type": "n8n-nodes-hostinger-api.hostingerApi",
      "position": [
        -2064,
        1552
      ],
      "parameters": {
        "page": "={{ $json.page }}",
        "resource": "reach"
      },
      "typeVersion": 1
    },
    {
      "id": "4cee998c-f5a2-455a-a0df-ecd988e62daf",
      "name": "Split Contact Records",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -1824,
        1440
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "response.data"
      },
      "typeVersion": 1
    },
    {
      "id": "865d4020-74af-4705-9641-fd6f6ba22dbb",
      "name": "Map Contact Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        -1584,
        1440
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "f1",
              "name": "uuid",
              "type": "string",
              "value": "={{ $json.uuid }}"
            },
            {
              "id": "f2",
              "name": "email",
              "type": "string",
              "value": "={{ $json.email }}"
            },
            {
              "id": "f3",
              "name": "name",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "f4",
              "name": "surname",
              "type": "string",
              "value": "={{ $json.surname }}"
            },
            {
              "id": "f5",
              "name": "subscription_status",
              "type": "string",
              "value": "={{ $json.subscription_status }}"
            },
            {
              "id": "f6",
              "name": "subscribed_at",
              "type": "string",
              "value": "={{ $json.subscribed_at }}"
            },
            {
              "id": "f7",
              "name": "source",
              "type": "string",
              "value": "={{ $json.source }}"
            },
            {
              "id": "f8",
              "name": "note",
              "type": "string",
              "value": "={{ $json.note }}"
            },
            {
              "id": "f9",
              "name": "last_synced_at",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4f8d5bd1-7e3f-4bd3-abe9-1784a94bc96f",
      "name": "Upsert Contacts in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1344,
        1440
      ],
      "parameters": {
        "columns": {
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "uuid"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Sheet Config').item.json.contacts_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $('Set Sheet Config').item.json.sheet_url }}"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "905111cc-2583-4bef-b160-497bb6fe24dc",
      "name": "Set Pagination State",
      "type": "n8n-nodes-base.set",
      "position": [
        -1824,
        1856
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "pc1",
              "name": "hasMore",
              "type": "boolean",
              "value": "={{ $json.response.meta.current_page < $json.response.meta.last_page }}"
            },
            {
              "id": "pc2",
              "name": "nextPage",
              "type": "number",
              "value": "={{ $json.response.meta.current_page + 1 }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "499be823-25c0-49aa-a55e-38db48787833",
      "name": "If More Pages Exist",
      "type": "n8n-nodes-base.if",
      "position": [
        -1584,
        1856
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c1",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.hasMore }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "7f6a5423-8d87-43e2-9000-4286daa79244",
      "name": "Advance to Next Page",
      "type": "n8n-nodes-base.set",
      "position": [
        -1344,
        1792
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "np1",
              "name": "page",
              "type": "number",
              "value": "={{ $json.nextPage }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d773b756-a65f-4370-b520-498a1f71486d",
      "name": "Fetch Segments",
      "type": "n8n-nodes-hostinger-api.hostingerApi",
      "position": [
        -2304,
        2176
      ],
      "parameters": {
        "resource": "reach",
        "operation": "listSegments"
      },
      "typeVersion": 1
    },
    {
      "id": "3c5e55b0-7556-4a9c-b81d-1fde77524fbd",
      "name": "Split Segment Records",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        -2064,
        2176
      ],
      "parameters": {
        "options": {},
        "fieldToSplitOut": "response.data"
      },
      "typeVersion": 1
    },
    {
      "id": "b718b7e0-d8b0-46f0-b703-1b69b11a9871",
      "name": "Add Sync Timestamp",
      "type": "n8n-nodes-base.set",
      "position": [
        -1824,
        2176
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "s1",
              "name": "last_synced_at",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "1c9a5168-eff8-4a6e-a77e-f82a81205f48",
      "name": "Upsert Segments in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -1584,
        2176
      ],
      "parameters": {
        "columns": {
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "uuid"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Sheet Config').item.json.segments_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $('Set Sheet Config').item.json.sheet_url }}"
        }
      },
      "typeVersion": 4.5
    }
  ],
  "connections": {
    "Fetch Segments": {
      "main": [
        [
          {
            "node": "Split Segment Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Day at 7am": {
      "main": [
        [
          {
            "node": "Set Sheet Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Sheet Config": {
      "main": [
        [
          {
            "node": "Initialize Page Number",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Segments",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add Sync Timestamp": {
      "main": [
        [
          {
            "node": "Upsert Segments in Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map Contact Fields": {
      "main": [
        [
          {
            "node": "Upsert Contacts in Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Contacts Page": {
      "main": [
        [
          {
            "node": "Split Contact Records",
            "type": "main",
            "index": 0
          },
          {
            "node": "Set Pagination State",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If More Pages Exist": {
      "main": [
        [
          {
            "node": "Advance to Next Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Advance to Next Page": {
      "main": [
        [
          {
            "node": "Fetch Contacts Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Pagination State": {
      "main": [
        [
          {
            "node": "If More Pages Exist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Contact Records": {
      "main": [
        [
          {
            "node": "Map Contact Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Split Segment Records": {
      "main": [
        [
          {
            "node": "Add Sync Timestamp",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Initialize Page Number": {
      "main": [
        [
          {
            "node": "Fetch Contacts Page",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}