{
  "name": "Add only compliant leads from Google Sheets to Smartlead with Precleared",
  "nodes": [
    {
      "parameters": {
        "content": "## Add only compliant leads from Google Sheets to Smartlead with Precleared\n\nChecks every new lead in your Google Sheet with [Precleared](https://precleared.dev) before it goes anywhere near Smartlead. Leads that are ok to cold email are added to your Smartlead campaign; the rest stay out, with the reason and the next step on their row. Covers UK PECR and GDPR, US CAN-SPAM, Canada's CASL, Germany's UWG and French rules.\n\n### Who's it for\nAgencies and founders who build lead lists in Google Sheets and send cold email from Smartlead.\n\n### How it works\n1. **Every morning** reads your sheet and keeps the rows that have no verdict yet.\n2. **Check with Precleared** asks whether a cold email to each address is allowed.\n3. **Cleared to email?** sends only `ok_to_email` leads on to **Add to Smartlead**, with the receipt id as the custom field `precleared_receipt`.\n4. **Write the result back** records the verdict, the rule, the next step, what the footer must include, the receipt id and whether the lead was added.\n\nA row Precleared couldn't answer (for example, once the day's checks are used) stays blank, with the reason in `note`, and is tried again on the next run. A row marked `error` (for example, an address that isn't valid) isn't retried: fix the row and clear its verdict.\n\n### How to set up\n1. Give your sheet these column headers: `email`, `first_name`, `last_name`, `company_name`, `address_source`, `company_number`, `recipient_country`, `verdict`, `rule`, `next_step`, `footer_requirement`, `receipt_id`, `checked_at`, `added_to_campaign`, `note`. In `address_source`, say where each address came from: published, bought, scraped, given or unknown (blank counts as unknown). `company_number` (a UK company number) and `recipient_country` (a two-letter code) are optional.\n2. Pick that sheet in **Read leads** and in **Write the result back**.\n3. Create a Header Auth credential for **Check with Precleared**: name `Authorization`, value `Bearer pc_live_...`. Get a free key at [precleared.dev/get-key](https://precleared.dev/get-key).\n4. Create a Query Auth credential for **Add to Smartlead**: name `api_key`, value your Smartlead API key.\n5. Fill in **Your settings**: your country (GB or US), what you offer and your Smartlead campaign id.\n6. Run it once, check the sheet and Smartlead, then switch it on.\n\n### Requirements\n- A Google account for Sheets and a Smartlead account with API access.\n- A Precleared key. A free key covers 25 checks a day; a £39 pack covers 2,000 and never expires.\n\n### How to customize\n- Run it when a row is added instead of every morning.\n- Set `max_checks_per_run` to how many leads you want checked each morning: up to 25 on a free key.\n- For a lead marked `unknown`, add its `company_number` or `recipient_country` and clear the verdict to check it again.\n- Make sure your Smartlead emails meet what `footer_requirement` describes, usually who you are, a postal address and a simple way to opt out. It describes the requirement; it isn't wording to paste.\n- The `settings` in **Add to Smartlead** keep Smartlead's block list, unsubscribe list and duplicate checks switched on. Leave them that way unless you have a reason.\n\nPrecleared is decision support with sources, not legal advice.",
        "height": 1080,
        "width": 600
      },
      "id": "33ea9ce7-7276-5fc0-93ae-d803777734fb",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1020,
        -560
      ]
    },
    {
      "parameters": {
        "content": "## 1. Read new leads\nEvery morning, read the sheet and keep the rows with no verdict yet.",
        "height": 420,
        "width": 880,
        "color": 7
      },
      "id": "18effc89-113a-5971-9fc2-cd107f2eac29",
      "name": "Section: read",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -380,
        -240
      ]
    },
    {
      "parameters": {
        "content": "## 2. Check each address\nUp to `max_checks_per_run` leads a run, one Precleared check each.",
        "height": 420,
        "width": 680,
        "color": 7
      },
      "id": "dfb52c51-8a0a-57f8-a130-736da7b8cdad",
      "name": "Section: check",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        540,
        -240
      ]
    },
    {
      "parameters": {
        "content": "## 3. Add cleared leads to Smartlead\nOnly `ok_to_email` leads go on. Everything else skips straight to the sheet.",
        "height": 620,
        "width": 700,
        "color": 7
      },
      "id": "1207e1ff-ad8d-5ac2-a9ac-5eb011bf5f04",
      "name": "Section: hand off",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1240,
        -440
      ]
    },
    {
      "parameters": {
        "content": "## 4. Write the result back\nVerdict, rule, next step, footer requirement, receipt id and whether the lead was added.",
        "height": 420,
        "width": 440,
        "color": 7
      },
      "id": "8c5e3a8b-1a87-5914-ae6f-e96b8b096513",
      "name": "Section: write back",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1980,
        -240
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "triggerAtHour": 9
            }
          ]
        }
      },
      "id": "8aaa8f81-3e87-572a-958f-fef47890f89d",
      "name": "Every morning",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -300,
        0
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "4c6978d7-3e39-56ed-976b-58a2b4ad492a",
              "name": "sender_country",
              "value": "GB",
              "type": "string"
            },
            {
              "id": "9ecc3b91-dc1c-5070-98cc-bb0959c84ee6",
              "name": "pitch",
              "value": "what you offer, in a few words",
              "type": "string"
            },
            {
              "id": "9aa681cc-7bac-568b-9da8-ea764dda9f0c",
              "name": "max_checks_per_run",
              "value": 25,
              "type": "number"
            },
            {
              "id": "5b7615c3-f24f-53cb-9dd1-034f3bd1d440",
              "name": "smartlead_campaign_id",
              "value": "paste your Smartlead campaign id",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "cbb01db9-8b19-58f2-9c0f-81777f432a5c",
      "name": "Your settings",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -80,
        0
      ]
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": ""
        },
        "sheetName": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": ""
        },
        "options": {}
      },
      "id": "670da134-b486-5d6f-820d-60ddab7ac9b0",
      "name": "Read leads",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        140,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "4bafc1ca-730e-535d-a1aa-0089d1446a7d",
              "leftValue": "={{ $json.email }}",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "rightValue": ""
            },
            {
              "id": "341e2f93-60a6-5353-97bf-b419dae723a1",
              "leftValue": "={{ $json.verdict }}",
              "operator": {
                "type": "string",
                "operation": "empty",
                "singleValue": true
              },
              "rightValue": ""
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "28fb997d-5808-5c1d-a211-c2addc1dc355",
      "name": "Not checked yet",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        360,
        0
      ]
    },
    {
      "parameters": {
        "maxItems": "={{ $('Your settings').first().json.max_checks_per_run }}"
      },
      "id": "9f71589b-30a1-5077-b2ad-782f066510a8",
      "name": "Stay within your allowance",
      "type": "n8n-nodes-base.limit",
      "typeVersion": 1,
      "position": [
        620,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://precleared.dev/api/v1/check",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ recipient_email: $json.email, address_source: $json.address_source || 'unknown', sender_country: $('Your settings').first().json.sender_country, pitch: $('Your settings').first().json.pitch, company_number: $json.company_number || undefined, recipient_country: $json.recipient_country || undefined }) }}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 5,
              "batchInterval": 1000
            }
          },
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "id": "4982fa73-cd28-508e-ae4f-b2e97f2a8ab1",
      "name": "Check with Precleared",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        840,
        0
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "bebde788-64d8-5bee-9350-bbbfde712f44",
              "name": "email",
              "value": "={{ $('Stay within your allowance').item.json.email }}",
              "type": "string"
            },
            {
              "id": "8de2d470-2215-5818-9fbf-41e21bc7ce0a",
              "name": "verdict",
              "value": "={{ $json.verdict || (['daily_limit', 'payment_required'].includes($json.error) || !$json.error ? '' : 'error') }}",
              "type": "string"
            },
            {
              "id": "58a1a18a-95ca-580f-8f68-f85878bbda2b",
              "name": "rule",
              "value": "={{ ($json.reasons && $json.reasons[0] && ($json.reasons[0].text || $json.reasons[0].note)) || '' }}",
              "type": "string"
            },
            {
              "id": "6e80295c-0234-56e9-8fe2-0742eb6551cf",
              "name": "next_step",
              "value": "={{ $json.next_step || '' }}",
              "type": "string"
            },
            {
              "id": "6ddcc711-5ebd-5d0e-bf88-65eadd158946",
              "name": "footer_requirement",
              "value": "={{ $json.footer_text || '' }}",
              "type": "string"
            },
            {
              "id": "880e5c6a-c7e0-55e7-8109-4ae48a461ae3",
              "name": "receipt_id",
              "value": "={{ $json.receipt ? $json.receipt.id : '' }}",
              "type": "string"
            },
            {
              "id": "9ae96f2c-5811-561d-9f08-b5b38b65a632",
              "name": "checked_at",
              "value": "={{ $json.verdict ? $now.toISO() : '' }}",
              "type": "string"
            },
            {
              "id": "db5b4f00-0dca-5639-bba4-d8f14bf7465c",
              "name": "added_to_campaign",
              "value": "={{ $json.verdict && $json.verdict !== 'ok_to_email' ? 'no: not cleared' : '' }}",
              "type": "string"
            },
            {
              "id": "5d918174-9fd5-5d33-857a-b100e0e2a038",
              "name": "note",
              "value": "={{ $json.verdict ? '' : [($json.message || (typeof $json.error === 'string' ? $json.error : '') || 'Precleared did not answer'), ($json.get_key_url ? 'Free key: ' + $json.get_key_url : ''), ($json.buy_url ? 'Packs: ' + $json.buy_url : '')].filter(Boolean).join(' ') }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "7787c9bb-0b3e-545c-8a81-df826cc53dc1",
      "name": "Prepare the update",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1060,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "c4ec82ea-880a-507c-91fb-3e75ad58fd07",
              "leftValue": "={{ $json.verdict }}",
              "rightValue": "ok_to_email",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "e1ca8d1f-87c5-563c-b948-637544566656",
      "name": "Cleared to email?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1300,
        0
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://server.smartlead.ai/api/v1/campaigns/{{ $('Your settings').first().json.smartlead_campaign_id }}/leads",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpQueryAuth",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ lead_list: [{ email: $json.email, first_name: $('Stay within your allowance').item.json.first_name || '', last_name: $('Stay within your allowance').item.json.last_name || '', company_name: $('Stay within your allowance').item.json.company_name || '', custom_fields: { precleared_receipt: $json.receipt_id } }], settings: { ignore_global_block_list: false, ignore_unsubscribe_list: false, ignore_duplicate_leads_in_other_campaign: false } }) }}",
        "options": {
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "id": "8a99d09d-e31d-5673-bb6f-192ee79b1d4e",
      "name": "Add to Smartlead",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1520,
        -200
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "c61abc38-e780-59b3-879e-8eecbe66652d",
              "name": "email",
              "value": "={{ $('Prepare the update').item.json.email }}",
              "type": "string"
            },
            {
              "id": "133e433f-2b71-5309-b2bf-d5a0440012da",
              "name": "verdict",
              "value": "={{ $('Prepare the update').item.json.verdict }}",
              "type": "string"
            },
            {
              "id": "8c3c3cbd-d834-5f7b-9b75-39fd1c3e6f80",
              "name": "rule",
              "value": "={{ $('Prepare the update').item.json.rule }}",
              "type": "string"
            },
            {
              "id": "af0f1ca9-7277-52e2-a53c-7351188baf1f",
              "name": "next_step",
              "value": "={{ $('Prepare the update').item.json.next_step }}",
              "type": "string"
            },
            {
              "id": "63f956ef-c1fe-50a7-93ca-a00322c49167",
              "name": "footer_requirement",
              "value": "={{ $('Prepare the update').item.json.footer_requirement }}",
              "type": "string"
            },
            {
              "id": "473fb59a-cc17-53ae-b28f-6551cfb4438f",
              "name": "receipt_id",
              "value": "={{ $('Prepare the update').item.json.receipt_id }}",
              "type": "string"
            },
            {
              "id": "57ee535f-73e9-5910-9061-d8a5babffc25",
              "name": "checked_at",
              "value": "={{ $('Prepare the update').item.json.checked_at }}",
              "type": "string"
            },
            {
              "id": "db5b4f00-0dca-5639-bba4-d8f14bf7465c",
              "name": "added_to_campaign",
              "value": "={{ $json.added_count > 0 ? 'added' : ($json.skipped_count > 0 ? 'skipped: ' + JSON.stringify($json.skipped_leads || []).slice(0, 200) : 'failed: ' + ($json.message || $json.error || 'no response from Smartlead')) }}",
              "type": "string"
            },
            {
              "id": "1ad106e6-fdb5-5889-b93b-83f810f896a2",
              "name": "note",
              "value": "={{ $('Prepare the update').item.json.note }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "1e38b870-3eac-5f5f-8423-2f3b0b0c21b4",
      "name": "Note the hand-off",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1740,
        -200
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": ""
        },
        "sheetName": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": ""
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "email": "={{ $json.email }}",
            "verdict": "={{ $json.verdict }}",
            "rule": "={{ $json.rule }}",
            "next_step": "={{ $json.next_step }}",
            "footer_requirement": "={{ $json.footer_requirement }}",
            "receipt_id": "={{ $json.receipt_id }}",
            "checked_at": "={{ $json.checked_at }}",
            "added_to_campaign": "={{ $json.added_to_campaign }}",
            "note": "={{ $json.note }}"
          },
          "matchingColumns": [
            "email"
          ],
          "schema": [
            {
              "id": "email",
              "displayName": "email",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "first_name",
              "displayName": "first_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "last_name",
              "displayName": "last_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "company_name",
              "displayName": "company_name",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "address_source",
              "displayName": "address_source",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "company_number",
              "displayName": "company_number",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "recipient_country",
              "displayName": "recipient_country",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": true
            },
            {
              "id": "verdict",
              "displayName": "verdict",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "rule",
              "displayName": "rule",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "next_step",
              "displayName": "next_step",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "footer_requirement",
              "displayName": "footer_requirement",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "receipt_id",
              "displayName": "receipt_id",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "checked_at",
              "displayName": "checked_at",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "added_to_campaign",
              "displayName": "added_to_campaign",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            },
            {
              "id": "note",
              "displayName": "note",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true,
              "removed": false
            }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "id": "7f70e4f3-63c1-526e-b1b9-d393b5b2c82d",
      "name": "Write the result back",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        2080,
        0
      ]
    }
  ],
  "pinData": {},
  "connections": {
    "Every morning": {
      "main": [
        [
          {
            "node": "Your settings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Your settings": {
      "main": [
        [
          {
            "node": "Read leads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read leads": {
      "main": [
        [
          {
            "node": "Not checked yet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Not checked yet": {
      "main": [
        [
          {
            "node": "Stay within your allowance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Stay within your allowance": {
      "main": [
        [
          {
            "node": "Check with Precleared",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check with Precleared": {
      "main": [
        [
          {
            "node": "Prepare the update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare the update": {
      "main": [
        [
          {
            "node": "Cleared to email?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Cleared to email?": {
      "main": [
        [
          {
            "node": "Add to Smartlead",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Write the result back",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Note the hand-off": {
      "main": [
        [
          {
            "node": "Write the result back",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add to Smartlead": {
      "main": [
        [
          {
            "node": "Note the hand-off",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}
