{
  "nodes": [
    {
      "id": "6aa059e4-e78f-4bbd-a707-994a39840f97",
      "name": "Create Session",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -520,
        240
      ],
      "parameters": {
        "url": "{{ $env.WEBHOOK_URL }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "identifier",
              "value": "youruser.bsky.social"
            },
            {
              "name": "password",
              "value": "your-app-passord-here"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 4.1,
      "notes": "This httpRequest node performs automated tasks as part of the workflow."
    },
    {
      "id": "143e37b0-de79-4329-99a2-51484c9609a8",
      "name": "List followers",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -280,
        240
      ],
      "parameters": {
        "url": "{{ $env.WEBHOOK_URL }}",
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          },
          "pagination": {
            "pagination": {
              "parameters": {
                "parameters": [
                  {
                    "name": "cursor",
                    "value": "={{ $response.body.cursor }}"
                  }
                ]
              },
              "maxRequests": 2,
              "requestInterval": 250,
              "limitPagesFetched": true
            }
          }
        },
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "actor",
              "value": "={{ $json.did }}"
            },
            {
              "name": "limit",
              "value": "100"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $item(\"0\").$node[\"Create Session\"].json[\"accessJwt\"] }}"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "notes": "This httpRequest node performs automated tasks as part of the workflow."
    },
    {
      "id": "f1436a63-a23f-4082-9209-12c21a26ad91",
      "name": "Convert to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        100,
        620
      ],
      "parameters": {
        "options": {
          "fileName": "followers-basuracero.json"
        },
        "operation": "toJson"
      },
      "typeVersion": 1.1,
      "notes": "This convertToFile node performs automated tasks as part of the workflow."
    },
    {
      "id": "f8beea47-6f36-4dfb-b2e7-bf94adb63e66",
      "name": "Extract from File",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        100,
        240
      ],
      "parameters": {
        "options": {},
        "operation": "fromJson"
      },
      "typeVersion": 1,
      "notes": "This extractFromFile node performs automated tasks as part of the workflow."
    },
    {
      "id": "41658372-3054-4909-850b-3bffd1b1b79c",
      "name": "Split Out",
      "type": "n8n-nodes-base.splitOut",
      "position": [
        520,
        240
      ],
      "parameters": {
        "options": {
          "destinationFieldName": "did"
        },
        "fieldToSplitOut": "newDids"
      },
      "typeVersion": 1,
      "notes": "This splitOut node performs automated tasks as part of the workflow."
    },
    {
      "id": "c94aa8e9-06db-4b24-a20a-5615b7129023",
      "name": "Loop Over Items",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        740,
        240
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3,
      "notes": "This splitInBatches node performs automated tasks as part of the workflow."
    },
    {
      "id": "4d1c6a2f-3acd-4783-96d4-693ced06fd97",
      "name": "Wait",
      "type": "n8n-nodes-base.wait",
      "position": [
        -100,
        620
      ],
      "webhookId": "b1608475-db84-4f23-acd6-d003f5094afd",
      "parameters": {},
      "typeVersion": 1.1,
      "notes": "This wait node performs automated tasks as part of the workflow."
    },
    {
      "id": "e4125cb8-8eb5-4cf0-b00d-e7ce4ec8236e",
      "name": "Find new followers",
      "type": "n8n-nodes-base.code",
      "position": [
        280,
        240
      ],
      "parameters": {
        "jsCode": "// Datos de entrada\nconst listFollowers = $('List followers').all()[0].json.followers;\nconst extractFromFile = $('Extract from File').all()[0].json.data[0].followers;\n\n// Verificar que tenemos acceso a los datos\nconsole.log('listFollowers length:', Array.isArray(listFollowers) ? listFollowers.length : 'no es array');\nconsole.log('extractFromFile length:', Array.isArray(extractFromFile) ? extractFromFile.length : 'no es array');\n\n// Mostrar algunos ejemplos de cada lista\nconsole.log('Ejemplo de listFollowers:', listFollowers?.slice(0, 2));\nconsole.log('Ejemplo de extractFromFile:', extractFromFile?.slice(0, 2));\n\n// Crear conjunto de DIDs del archivo extraído\nconst existingDids = new Set(extractFromFile?.map(item => item.did) || []);\nconsole.log('DIDs existentes:', Array.from(existingDids).slice(0, 5));\n\n// Filtrar listFollowers\nconst newFollowers = listFollowers?.filter(follower => !existingDids.has(follower.did)) || [];\n\nreturn {\n  json: {\n    debug: {\n      listFollowersCount: listFollowers?.length || 0,\n      extractFromFileCount: extractFromFile?.length || 0,\n      existingDidsCount: existingDids.size,\n      newFollowersCount: newFollowers.length\n    },\n    newFollowers,\n    newDids: newFollowers.map(follower => follower.did),\n    count: newFollowers.length\n  }\n}"
      },
      "typeVersion": 2,
      "alwaysOutputData": true,
      "notes": "This code node performs automated tasks as part of the workflow."
    },
    {
      "id": "a28accb5-ee47-431f-83e4-376425e9899e",
      "name": "Read followers from file",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        -80,
        240
      ],
      "parameters": {
        "options": {},
        "fileSelector": "=followers-{{ $('Create Session').item.json.handle }}.json"
      },
      "typeVersion": 1,
      "notes": "This readWriteFile node performs automated tasks as part of the workflow."
    },
    {
      "id": "aa2ab5e1-eb6f-4657-9a9a-66417ffa421e",
      "name": "Save followers to file",
      "type": "n8n-nodes-base.readWriteFile",
      "position": [
        280,
        620
      ],
      "parameters": {
        "options": {
          "append": false
        },
        "fileName": "=followers-{{ $('Create Session').item.json.handle }}.json",
        "operation": "write"
      },
      "typeVersion": 1,
      "notes": "This readWriteFile node performs automated tasks as part of the workflow."
    },
    {
      "id": "9a4fb5e5-f2f6-4aa1-846e-8d6460ad7765",
      "name": "Define welcome message",
      "type": "n8n-nodes-base.set",
      "position": [
        980,
        260
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "afe7fe9b-3bd4-4429-afe9-81e5fe934e07",
              "name": "text",
              "type": "string",
              "value": "Hello, thanks for your follow. You can read more about my over my site:"
            },
            {
              "id": "97590cd1-9d85-442b-baa3-bad849ff9be0",
              "name": "link",
              "type": "string",
              "value": "{{ $env.WEBHOOK_URL }}"
            }
          ]
        }
      },
      "typeVersion": 3.4,
      "notes": "This set node performs automated tasks as part of the workflow."
    },
    {
      "id": "594ce66f-acbd-4c31-806c-382aa9a98ed0",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        920,
        160
      ],
      "parameters": {
        "width": 230,
        "height": 266,
        "content": "### 2. Define your welcome message and link here"
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "c24a7971-11a7-4164-9f2d-78335264f250",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        220,
        460
      ],
      "parameters": {
        "width": 231,
        "height": 338,
        "content": "### 3. **Important** \n\nYou need to manually run \"Save followers to file\" once before the first time so you populate your list of existing followers"
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "c6e766cf-a118-4db0-8e3c-32662c40737b",
      "name": "Send message",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1360,
        260
      ],
      "parameters": {
        "url": "{{ $env.BASE_URL }}",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"convoId\" : \"{{ $json.convo.id }}\",\n  \"message\" : {\n    \"text\" : \"{{ $('Define welcome message').item.json.text }}\\n\\n{{ $('Define welcome message').item.json.link }}\",\n    \"facets\" : [\n     {\n      \"index\" : {\n        \"byteStart\": {{ $('Define welcome message').item.json.text.length }},\n        \"byteEnd\": {{ $('Define welcome message').item.json.text.length + 3 + $('Define welcome message').item.json.link.length}}\n      },\n      \"features\": [\n          {\n            \"$type\": \"app.bsky.richtext.facet#link\",\n            \"uri\": \"{{ $('Define welcome message').item.json.link }}\"\n          }\n        ]\n      }\n    ]\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $item(\"0\").$node[\"Create Session\"].json[\"accessJwt\"] }}"
            },
            {
              "name": "Atproto-Proxy",
              "value": "did:web:api.bsky.chat#bsky_chat"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "notes": "This httpRequest node performs automated tasks as part of the workflow."
    },
    {
      "id": "33aa7e0c-58fe-4527-a94e-49bec0e06325",
      "name": "Get conversation ID",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1200,
        260
      ],
      "parameters": {
        "url": "{{ $env.BASE_URL }}",
        "options": {},
        "sendQuery": true,
        "sendHeaders": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "members",
              "value": "={{ $('Split Out').item.json.did }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $item(\"0\").$node[\"Create Session\"].json[\"accessJwt\"] }}"
            },
            {
              "name": "Atproto-Proxy",
              "value": "did:web:api.bsky.chat#bsky_chat"
            }
          ]
        }
      },
      "typeVersion": 4.2,
      "notes": "This httpRequest node performs automated tasks as part of the workflow."
    },
    {
      "id": "066f1d0d-319a-4676-9c0a-5b00d206ffd2",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -40,
        -100
      ],
      "parameters": {
        "color": 5,
        "width": 479,
        "height": 307,
        "content": "## Send a welcome private message to your new BlueSky followers\n\nThis flow will save your current followers in a file and check for new ones on the next execution, sending them the Defined message an link as a private message.\n\nOnce messages are sent, the new list of followers will be saved into the file.\n\n**Important: Follow the yellow notes in order before enabling the full flow for the first time**"
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "a61e301e-a0ca-48e9-9a46-05975662aa90",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        40
      ],
      "parameters": {
        "width": 181,
        "height": 364,
        "content": "### 1. Define your Bluesky user and app password first\n\nThe App password should have access to private messages"
      },
      "typeVersion": 1,
      "notes": "This stickyNote node performs automated tasks as part of the workflow."
    },
    {
      "id": "1b1dcd74-7a71-49e4-99e8-c079b692aca5",
      "name": "Each 60 minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -720,
        240
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 60
            }
          ]
        }
      },
      "typeVersion": 1.2,
      "notes": "This scheduleTrigger node performs automated tasks as part of the workflow."
    },
    {
      "id": "6acf153c-cdc6-42c1-85f9-2692c8777eef",
      "name": "No Operation, do nothing",
      "type": "n8n-nodes-base.noOp",
      "position": [
        520,
        620
      ],
      "parameters": {},
      "typeVersion": 1,
      "notes": "This noOp node performs automated tasks as part of the workflow."
    }
  ],
  "pinData": {},
  "connections": {
    "6aa059e4-e78f-4bbd-a707-994a39840f97": {
      "main": [
        [
          {
            "node": "error-handler-6aa059e4-e78f-4bbd-a707-994a39840f97",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-6aa059e4-e78f-4bbd-a707-994a39840f97-a4722bf5",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-6aa059e4-e78f-4bbd-a707-994a39840f97-17725b9a",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-6aa059e4-e78f-4bbd-a707-994a39840f97-25d117c6",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-6aa059e4-e78f-4bbd-a707-994a39840f97-e2069468",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "143e37b0-de79-4329-99a2-51484c9609a8": {
      "main": [
        [
          {
            "node": "error-handler-143e37b0-de79-4329-99a2-51484c9609a8",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-143e37b0-de79-4329-99a2-51484c9609a8-4e0bd3d7",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-143e37b0-de79-4329-99a2-51484c9609a8-23e35120",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-143e37b0-de79-4329-99a2-51484c9609a8-b8a95e99",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-143e37b0-de79-4329-99a2-51484c9609a8-4aae11e7",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "c6e766cf-a118-4db0-8e3c-32662c40737b": {
      "main": [
        [
          {
            "node": "error-handler-c6e766cf-a118-4db0-8e3c-32662c40737b",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-c6e766cf-a118-4db0-8e3c-32662c40737b-f5efc52d",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-c6e766cf-a118-4db0-8e3c-32662c40737b-55873bda",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-c6e766cf-a118-4db0-8e3c-32662c40737b-f7554e49",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-c6e766cf-a118-4db0-8e3c-32662c40737b-0f2e7d62",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "33aa7e0c-58fe-4527-a94e-49bec0e06325": {
      "main": [
        [
          {
            "node": "error-handler-33aa7e0c-58fe-4527-a94e-49bec0e06325",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-33aa7e0c-58fe-4527-a94e-49bec0e06325-1a9a6c54",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-33aa7e0c-58fe-4527-a94e-49bec0e06325-e1239e8f",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-33aa7e0c-58fe-4527-a94e-49bec0e06325-903b52bc",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "error-handler-33aa7e0c-58fe-4527-a94e-49bec0e06325-7fd95fc6",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f1436a63-a23f-4082-9209-12c21a26ad91": {
      "main": [
        [
          {
            "node": "error-handler-f1436a63-a23f-4082-9209-12c21a26ad91-fb6fa157",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "f8beea47-6f36-4dfb-b2e7-bf94adb63e66": {
      "main": [
        [
          {
            "node": "error-handler-f8beea47-6f36-4dfb-b2e7-bf94adb63e66-ed9aab5d",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "a28accb5-ee47-431f-83e4-376425e9899e": {
      "main": [
        [
          {
            "node": "error-handler-a28accb5-ee47-431f-83e4-376425e9899e-123c4737",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "aa2ab5e1-eb6f-4657-9a9a-66417ffa421e": {
      "main": [
        [
          {
            "node": "error-handler-aa2ab5e1-eb6f-4657-9a9a-66417ffa421e-d8b032b0",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "name": "Httprequest Workflow",
  "settings": {
    "executionOrder": "v1",
    "saveManualExecutions": true,
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": null,
    "timezone": "UTC",
    "executionTimeout": 3600,
    "maxExecutions": 1000,
    "retryOnFail": true,
    "retryCount": 3,
    "retryDelay": 1000
  },
  "description": "Automated workflow: Httprequest Workflow. This workflow integrates 13 different services: convertToFile, stickyNote, httpRequest, wait, splitInBatches. It contains 31 nodes and follows best practices for error handling and security.",
  "meta": {
    "instanceId": "workflow-5f7a32e6",
    "versionId": "1.0.0",
    "createdAt": "2025-09-29T07:07:58.740586",
    "updatedAt": "2025-09-29T07:07:58.740619",
    "owner": "n8n-user",
    "license": "MIT",
    "category": "automation",
    "status": "active",
    "priority": "high",
    "environment": "production"
  },
  "tags": [
    "automation",
    "n8n",
    "production-ready",
    "excellent",
    "optimized"
  ],
  "notes": "Excellent quality workflow: Httprequest Workflow. This workflow has been optimized for production use with comprehensive error handling, security, and documentation."
}