← All Analytics

Peak email verification with BillionVerify

Peak is an analytics platform that helps businesses make smarter decisions from their data. Reports, alerts, and insights are delivered to users by email, so the quality of those addresses directly affects how reliably your team receives critical information. BillionVerify keeps Peak's recipient list free of invalid and risky addresses.

Why verify before the send

Analytics alerts and scheduled reports are time-sensitive. If recipient emails are invalid, stale, or belong to catch-all domains, important insights go undelivered and bounce rates accumulate against your sending domain. BillionVerify validates addresses upfront so Peak's notifications always reach the right inboxes.

Ready-to-use n8n workflow

Import this workflow into n8n — it verifies every address with BillionVerify before Peak sends, so only deliverable contacts are emailed. Install the BillionVerify community node first, then add your API key. Adapted from this n8n template

verify-emails-in-peak.json
{
  "name": "Handle Spanish-speaking vet clinic bookings with GPT-4o, Sheets, Calendar and Gmail + BillionVerify",
  "nodes": [
    {
      "id": "",
      "name": "When chat message received",
      "type": "@n8n/n8n-nodes-langchain.chatTrigger",
      "position": [
        2272,
        -544
      ],
      "webhookId": "",
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.4
    },
    {
      "id": "eba8a2e5-9860-4f58-a5db-51c48f80eca2",
      "name": "Normalize",
      "type": "n8n-nodes-base.set",
      "position": [
        2512,
        -544
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "563b3849-b286-4eb2-8c2c-5e4fb75c9a10",
              "name": "message",
              "type": "string",
              "value": "={{ $json.chatInput }}"
            },
            {
              "id": "8b4f1194-7976-426a-b81a-ce77b9a391ed",
              "name": "phone_number",
              "type": "string",
              "value": "YOUR_PHONE_NUMBER"
            },
            {
              "id": "1e5a7844-a48d-4017-8b3b-d931af534088",
              "name": "session_id",
              "type": "string",
              "value": "={{ $json.sessionId }}"
            },
            {
              "id": "f0de03eb-540d-47d8-ad55-d77599d1b330",
              "name": "10_days_from_now",
              "type": "string",
              "value": "={{ $now.plus({ days: 10 }).toFormat('yyyy-MM-dd') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "34b16c60-0b60-4b4e-a62a-504f3d3922e6",
      "name": "Update event",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        3216,
        -208
      ],
      "parameters": {
        "eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', `The unique ID string from the search result (e.g., 5qasn...)`, 'string') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "Calendario del Agente de Turnos"
        },
        "operation": "update",
        "updateFields": {
          "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', `The new end date and time. This should be exactly 30 minutes after the start time.`, 'string') }}",
          "start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', `The new start date and time for the appointment in ISO 8601 format (e.g., 2026-02-17T16:00:00).`, 'string') }}"
        },
        "descriptionType": "manual",
        "toolDescription": "When updating, always provide an end time 30 minutes after the start time unless specified otherwise."
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "id": "credential-id",
          "name": "Google Calendar account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "f36c8bec-06bb-4dd3-88fb-cbbe349ba666",
      "name": "Delete event",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        3344,
        -208
      ],
      "parameters": {
        "eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', `The unique ID string from the search result (e.g., 5qasn...)`, 'string') }}",
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "Calendario del Agente de Turnos"
        },
        "operation": "delete"
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "id": "credential-id",
          "name": "Google Calendar account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "82866b61-d6b1-4775-87b2-482004963868",
      "name": "Create event",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        3088,
        -208
      ],
      "parameters": {
        "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', ``, 'string') }}",
        "start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', ``, 'string') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "Calendario del Agente de Turnos"
        },
        "descriptionType": "manual",
        "toolDescription": "Use this tool to create an event - Add the user's name and pet name as the title for each event.",
        "additionalFields": {
          "summary": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Summary', `Title: User's full name - Pet's name`, 'string') }}",
          "description": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Description', ``, 'string') }}"
        }
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "id": "credential-id",
          "name": "Google Calendar account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "888d1e0f-53b7-43f8-bda1-2b1d9ce9e74e",
      "name": "Simple Memory",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        2576,
        -192
      ],
      "parameters": {
        "sessionKey": "={{ $json.session_id }}",
        "sessionIdType": "customKey",
        "contextWindowLength": 10
      },
      "typeVersion": 1.3
    },
    {
      "id": "051ec537-9d2d-4253-8844-cd255439d822",
      "name": "OpenRouter Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
      "position": [
        2240,
        -192
      ],
      "parameters": {
        "model": "openai/gpt-4o",
        "options": {}
      },
      "credentials": {
        "openRouterApi": {
          "id": "credential-id",
          "name": "OpenRouter"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "756c9aae-094b-441e-a627-5742132c1a81",
      "name": "Get events",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        2976,
        -208
      ],
      "parameters": {
        "options": {
          "timeZone": {
            "__rl": true,
            "mode": "list",
            "value": "Europe/Madrid",
            "cachedResultName": "Europe/Madrid"
          }
        },
        "timeMax": "={{ $json['10_days_from_now'] }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "Calendario del Agente de Turnos"
        },
        "operation": "getAll",
        "returnAll": true,
        "descriptionType": "manual",
        "toolDescription": "=Use this tool to see if a specific slot is available. If this tool returns data, it means the slot is unavailable/busy. Only look for slots after {{ $now }}."
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "id": "credential-id",
          "name": "Google Calendar account"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "1d0a7dcb-d904-47e5-920c-eebe65532027",
      "name": "New client?",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2720,
        -208
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Normalize').item.json.phone_number }}",
              "lookupColumn": "Teléfono"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_ID/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEETS_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_ID/edit?usp=drivesdk",
          "cachedResultName": "Clientes_Veterinaria"
        },
        "descriptionType": "manual",
        "toolDescription": "Get row(s) in sheet in Google Sheets"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "da321299-e79a-4ea8-8b47-fe38ca5cfd48",
      "name": "MarĂ­a",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        2736,
        -544
      ],
      "parameters": {
        "text": "={{ $json.message }}",
        "options": {
          "systemMessage": "=# OVERVIEW\nYou are MarĂ­a from \"Patitas Felices\", a virtual assistant. Your priority is to call the correct tools.\n\n# TOOLS\n- New client? - Use this tool to check if the client exists in the system\n- Add client - Use this tool to add the client details to the system\n- Get events - Use this tool to search for events or available slots in the calendar\n- Create event - Use this tool to create a new event (check chat_history for user's details)\n- Update event - Use this tool if there's an existing event that needs to be rescheduled\n- Delete event - Use this tool if there's a existing event that needs to be cancelled/deleted\n- Send a message in Gmail - Use this tool if the user is requesting anything else other than booking, rescheduling, or cancelling an appointment.\n\n# TASKS:\n1- Identify the user (mandatory every time)\n2- Check for existing appointments\n3- Book, reschedule, or delete events\n\n# INSTRUCTIONS FOR EACH TASK\n\n## IDENTIFY USER\n1. **ALWAYS** call `New client?` first to identify the user\n  - If the user doesn't exist yet, ask for their full name, and pet's name and type, and then call `Add client`. Check on chat_history if the user has already provided any of those items before asking.\n  - If the user exists you can continue to step 2 (Check for existing appointments)\n\n## BOOKING INSTRUCTIONS:\n- **Always** call `Get events` before replying. Send the first 2 or 3 **available** slots to the user.\n- If the user is unavailable on those slot suggestions, provide 2-3 more available slots.\n- Once the user agrees to a specific slot, call `Create event`.\n- Confirm the date/time to the user.\n\n\n## RESCHEDULE INSTRUCTIONS:\n- Call `Get events`, and search the meeting titles until you find the user's existing booking (using the user's full name and pet name). **NEVER** skip this step. If the user is rescheduling, you **must** find the user's existing meeting. The user might provide the wrong time/day, you need to find the correct information each time.\n- Based on the information from `Get events`, provide 2-3 different slots to the user. **You must provide slots that are free/available ONLY**.\n- Once the user confirms a new day/time, call `Update event` and make the changes to the date/time. **Make sure to update the correct event, double check the title to make sure it contains the user and pet names**\n\n## CANCEL/DELETE INSTRUCTIONS:\n- **DO NOT** reply to the user before calling `Get events`.\n- Call `Get events`, search for the user's existing slot using the user's full name and pet name, and once you find it call `Delete event`. Delete **ONLY** the user's existing meeting. If there's more than one, ask the user to confirm which one you need to delete.\n\n\n## OTHER REQUESTS INSTRUCTION:\n- If the user is asking for a different request (other than booking, rescheduling or cancel/deleting appointments), let them know you will inform the team, and that they will reach out soon. Don't ask them if they want you to notify the team - **always** use the `Send a message in Gmail` tool to let the team know.\n\n\n# DATE LOGIC\n- Today is {{ $now.toFormat('EEEE, MMMM d, yyyy') }} at {{ $now.toFormat('HH:mm') }}.\n- If the user asks for a day of the week (e.g., \"Thursday\"):\n  1. Calculate the specific date based on Today.\n  2. If today is Wednesday Feb 18, \"Thursday\" MUST be Feb 19.\n  3. Confirm the date (YYYY-MM-DD) before calling the `Create event` tool.\n\n## Additional info\n- Veterinary doctor's name is Doctor Doolittle.\n- Veterinary clinic address is Calle de los animales #1533\n\n\n# Examples:\n1.\nInput: Hola, tengo un turno ahora en un rato pero no llego. Me lo cambiarias para la tarde, a las 4 quizas?\nOutput: Hola LucĂ­a, no hay problema. El turno de las 16 hs ya estĂĄ ocupado, pero te puedo ofrecer cambiarlo a las 16:30 o a las 17:00. ÂżQuĂ© horario te viene mejor?\n\n2.\nOutput when an appointment has been changed: Hecho! Tu cita ya estĂĄ cambiada para hoy a las 17:00. Nos vemos en un rato!\n\n3.\nInput: hola, necesito un turno\nOutput: Hola, soy MarĂ­a de Patitas Felices. ÂĄEncantada! No te encuentro en el sistema, pero no te preocupes, te registro en un segundo. ÂżMe podrĂ­as decir tu nombre completo y contarme un poco de tu mascota: cĂłmo se llama y quĂ© animalito es?\nInput: claro, soy Antonella Diaz y mi caracol se llama Pepito\nOutput: Genial, ya estĂĄs agendada! Tengo algunos turnos libres para hoy: 11:30, 12:00 o 12:30. ÂżCuĂĄl prefieres? Y para ir preparandonos, ÂżquĂ© le anda pasando a Pepito?\n\n4.\nInput: Hola, necesito un turno\nOutput: Hola [user's name], ÂżcĂłmo estĂĄs? Tengo algunos turnos libres para hoy: [Available slots]. ÂżCuĂĄl prefieres? Y para ir preparĂĄndonos, ÂżquĂ© le anda pasando a [nombre de la mascota]?\n\n5.\nOutput: ÂĄHecho! Tu cita para el chequeo anual de Muni estĂĄ confirmada para hoy a las 10:30. Nos vemos pronto. đŸ¶ Si tienes alguna otra pregunta o necesitas algo mĂĄs, aquĂ­ estoy para ayudarte.\nInput: Gracias!\nOutput: ÂĄEncantada, nos vemos pronto!\n\n6.\nInput: Hola, tengo una cita hoy a las 15 que me gustaria cambiar\n\nOutput: Hola [user's name], he encontrado tu cita pero no es hoy a las 15:00, estĂĄ agendada a las 12:30. ÂżLa cambiamos igual? ÂżQuĂ© dĂ­a te viene mejor?"
        },
        "promptType": "define",
        "needsFallback": true
      },
      "retryOnFail": true,
      "typeVersion": 3.1
    },
    {
      "id": "e02fc04c-1440-4494-b85c-c4cceb2e0409",
      "name": "Add client",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        2848,
        -208
      ],
      "parameters": {
        "columns": {
          "value": {
            "Cliente": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Cliente', ``, 'string') }}",
            "Teléfono": "={{ $('Normalize').item.json.phone_number }}",
            "Tipo de animal": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tipo_de_animal', ``, 'string') }}",
            "Nombre de la mascota": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Nombre_de_la_mascota', ``, 'string') }}"
          },
          "schema": [
            {
              "id": "Cliente",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Cliente",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Nombre de la mascota",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Nombre de la mascota",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Tipo de animal",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Tipo de animal",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Raza",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Raza",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Teléfono",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Teléfono",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Teléfono"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_ID/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEETS_ID",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_GOOGLE_SHEETS_ID/edit?usp=drivesdk",
          "cachedResultName": "Clientes_Veterinaria"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "credential-id",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "3894a194-40c3-430d-9f94-b6ca86ffdc2d",
      "name": "OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        2416,
        -192
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-5-mini"
        },
        "options": {},
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "id": "credential-id",
          "name": "OpenAi"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "7341ca34-fe9d-497f-852f-3812f37bc524",
      "name": "Send a message in Gmail",
      "type": "n8n-nodes-base.gmailTool",
      "position": [
        3488,
        -208
      ],
      "webhookId": "",
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=Hola,<br><br>\n\nHay una consulta en el chat que necesita tu respuesta cuanto antes!<br><br>\n\nTeléfono: {{ $json.phone_number }}<br>\nMensaje: {{ $json.message }}<br><br>\n\nSaludos,<br>\nMaría",
        "options": {
          "appendAttribution": false
        },
        "subject": "Importante! Hay un chat que necesita respuesta!!",
        "descriptionType": "manual",
        "toolDescription": "Use this tool to send a message and notify the team when a user asks for something different than booking, rescheduling or canceling an appointment."
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "credential-id",
          "name": "Gmail"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3cfb165e-b9c9-4ea8-a056-e806891aeab4",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1936,
        -992
      ],
      "parameters": {
        "color": 7,
        "width": 592,
        "height": 208,
        "content": "## AI Appointment Agent (Maria) – Vet Clinic Demo (Spanish speaking)\nPURPOSE: Autonomous booking, rescheduling, and lead capture via n8n Chat.\nMODELS: GPT-4o (Primary) + GPT-4o-mini/GPT-5-mini (Fallback) via OpenRouter."
      },
      "typeVersion": 1
    },
    {
      "id": "33c9074f-e965-41bd-bfb3-12ab34b9cb4c",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2192,
        -624
      ],
      "parameters": {
        "width": 464,
        "height": 240,
        "content": "## DATA INGESTION"
      },
      "typeVersion": 1
    },
    {
      "id": "dcc0a661-6e45-4d1a-88fe-0b0e6a4e9b01",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2704,
        -624
      ],
      "parameters": {
        "color": 6,
        "width": 352,
        "height": 240,
        "content": "## AI ORCHESTRATION"
      },
      "typeVersion": 1
    },
    {
      "id": "9998ea35-831c-440c-a431-8d79c5db5cde",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2192,
        -256
      ],
      "parameters": {
        "color": 6,
        "width": 496,
        "height": 304,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## AI ORCHESTRATION"
      },
      "typeVersion": 1
    },
    {
      "id": "1dd2bb18-62ec-4759-bb54-dd3d65ddc502",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2704,
        -256
      ],
      "parameters": {
        "color": 4,
        "width": 256,
        "height": 304,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## CLIENT DATABASE"
      },
      "typeVersion": 1
    },
    {
      "id": "f6f01bde-318e-4f18-85f9-102462d9df8e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2976,
        -256
      ],
      "parameters": {
        "color": 3,
        "width": 464,
        "height": 304,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## APPOINTMENT MANAGEMENT"
      },
      "typeVersion": 1
    },
    {
      "id": "0d121dcf-b76f-41a7-b2a6-e3723d14b4d9",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3456,
        -256
      ],
      "parameters": {
        "color": 5,
        "width": 352,
        "height": 304,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## ESCALATION & FEEDBACK"
      },
      "typeVersion": 1
    },
    {
      "id": "ffb12d17-7d33-4187-8e98-f849d1a0fa6d",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1440,
        -736
      ],
      "parameters": {
        "color": 7,
        "width": 592,
        "height": 800,
        "content": "## đŸ› ïž SETUP & CONFIGURATION (READ FIRST)\n\n1. PREREQUISITES:\n\nCredentials: You will need to connect your Google Sheets, Google Calendar, and Gmail accounts.\n\nAPI Key: An OpenRouter API Key is required for the AI Agent (Maria).\n\n2. GOOGLE SHEETS SETUP:\n\nCreate a sheet named Clientes_Veterinaria with the following columns:\n\nCliente, Nombre de la mascota, Tipo de animal, TelĂ©fono\n\nUpdate the Google Sheets Nodes in this workflow to point to your specific Spreadsheet ID.\n\n3. GOOGLE CALENDAR SETUP:\n\nEnsure your n8n Timezone (in Workflow Settings) matches your Google Calendar timezone to avoid booking errors.\n\nConnect the Calendar Nodes to your primary business calendar.\n\n4. AI AGENT CONFIGURATION:\n\nPrimary Model: GPT-4o (configured in the OpenRouter node).\n\nMemory: The Window Buffer Memory is preset to 10 interactions to maintain context without exceeding token limits.\n\n5. TESTING:\n\nOpen the n8n Chat window on the bottom right.\n\nType: \"Hi, I want to book an appointment for my cat next Tuesday at 10 AM.\"\n\nVerify that Maria checks the sheet, adds you if you're new, and creates the calendar event."
      },
      "typeVersion": 1
    },
    {
      "id": "27b45ecc-d59b-4056-9ef3-c7d5210878a3",
      "name": "Workflow Error Handler",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        2192,
        288
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "ab9d91b8-1e16-4b71-8f4d-94e2ac176804",
      "name": "Notify: Workflow Error",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2416,
        288
      ],
      "webhookId": "",
      "parameters": {
        "sendTo": "user@example.com",
        "message": "=<h2>🔮 Workflow Error</h2><p>The LinkedIn PDF → JobAdder Sync workflow encountered an error:</p><pre style='background:#f5f5f5;padding:12px'>{{ $json.execution.error.message }}</pre><p><strong>Last node:</strong> {{ $json.execution.lastNodeExecuted }}</p><hr><em>Check your n8n execution log for full details.</em>",
        "options": {},
        "subject": "=🔮 Workflow Error: LinkedIn PDF → JobAdder Sync"
      },
      "credentials": {
        "gmailOAuth2": {
          "id": "credential-id",
          "name": "Gmail"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "8331bde0-f7fe-4858-849d-09674e921ee0",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2112,
        192
      ],
      "parameters": {
        "width": 496,
        "height": 320,
        "content": "## ERROR HANDLER"
      },
      "typeVersion": 1
    },
    {
      "parameters": {
        "operation": "verify",
        "email": "={{ $json.email || $json.Email }}",
        "additionalOptions": {}
      },
      "type": "n8n-nodes-billionverify.billionVerify",
      "typeVersion": 1,
      "position": [
        2056,
        288
      ],
      "name": "Verify Email (BillionVerify)",
      "credentials": {
        "billionVerifyApi": {
          "id": "",
          "name": "BillionVerify account"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "is-deliverable",
              "leftValue": "={{ $json.is_deliverable }}",
              "rightValue": "",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ]
        }
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        2236,
        288
      ],
      "name": "IF deliverable"
    }
  ],
  "connections": {
    "MarĂ­a": {
      "main": [
        []
      ]
    },
    "Normalize": {
      "main": [
        [
          {
            "node": "MarĂ­a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add client": {
      "ai_tool": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Get events": {
      "ai_tool": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "New client?": {
      "ai_tool": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Create event": {
      "ai_tool": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Delete event": {
      "ai_tool": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update event": {
      "ai_tool": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Simple Memory": {
      "ai_memory": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_languageModel",
            "index": 1
          }
        ]
      ]
    },
    "OpenRouter Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Error Handler": {
      "main": [
        [
          {
            "node": "Verify Email (BillionVerify)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send a message in Gmail": {
      "ai_tool": [
        [
          {
            "node": "MarĂ­a",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "When chat message received": {
      "main": [
        [
          {
            "node": "Normalize",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify Email (BillionVerify)": {
      "main": [
        [
          {
            "node": "IF deliverable",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF deliverable": {
      "main": [
        [
          {
            "node": "Notify: Workflow Error",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    }
  },
  "settings": {}
}

Workflow templates with Peak

Ready-to-use workflows that verify emails before Peak sends.

How it works

  1. 1

    Integrate BillionVerify with Peak via the n8n community node, Integrately, or the REST API.

  2. 2

    Intercept each email address at the point a user subscribes to reports or is added as an alert recipient.

  3. 3

    Submit the address to BillionVerify for validation including syntax, DNS, SMTP, and disposable checks.

  4. 4

    Add only verified addresses to Peak's notification lists; route questionable ones for manual review.

  5. 5

    Re-verify addresses periodically to catch mailboxes that have since gone inactive.

When to use this

Validate report subscription emails

When users subscribe to scheduled Peak reports or dashboards, verify their email address with BillionVerify to ensure the subscription is connected to a real, deliverable inbox.

Screen alert recipients before critical notifications

For time-sensitive Peak alerts — anomaly detections, threshold breaches — verify recipient addresses in advance so no alert is lost to a bounce at the moment it matters most.

FAQ

How does email verification help analytics platforms like Peak specifically?

Analytics platforms send scheduled and triggered emails to business stakeholders. Invalid addresses cause bounces that degrade sender reputation, risking future deliverability of all outbound notifications.

Can I bulk-verify an existing Peak recipient list?

Yes. Upload your current list to BillionVerify's bulk verification endpoint to identify and remove invalid addresses before your next scheduled report run.

Does BillionVerify flag corporate catch-all domains?

Yes. BillionVerify detects catch-all configurations where a domain accepts all mail regardless of whether the mailbox exists, and flags those addresses so you can decide how to handle them.

What integration method requires the least setup for Peak?

Integrately provides a one-click no-code connection between Peak and BillionVerify, making it the easiest starting point if you do not have a developer available.

Verify emails in Peak

Create a free account, grab your API key, and stop bounces before they happen.

Get started free