{
  "name": "Validate API keys and quotas daily with Datasource Pulse and Gmail alerts",
  "nodes": [
    {
      "parameters": {
        "content": "## Validate API keys and quotas daily with Datasource Pulse and Gmail alerts\n\n**Who's it for**\nAnyone whose product quietly depends on OpenAI, Stripe, SerpAPI, GitHub, or other vendor keys, where a revoked key or blown quota only surfaces when production breaks.\n\n**How it works**\nEvery morning Datasource Pulse validates each key against the vendor's live API and checks usage against your own budget caps. Dead credentials, rate limits, and quota warnings arrive as email verdicts with a stable failure_class.\n\n**How to set up (5 min)**\n1. Install the **Apify** community node (n8n Cloud: search \"Apify\" in the nodes panel and install) and connect your Apify account.\n2. Open **Initiate Datasource Pulse** and edit *Input JSON*: paste your real keys. 35+ vendors come pre-wired (OpenAI, Anthropic, Stripe, GitHub, SerpAPI and more, see the actor README for per-vendor fields), plus generic_http for any endpoint you add.\n3. `quotaSoftCap` is YOUR budget line in the vendor's native unit (searches for SerpAPI, USD for Apify).\n4. Set your address in **Send Gmail Alert**, connect Gmail, run once.\n\n**Requirements**\nApify account ($0.02 per key per run), the Apify community node (verified on n8n Cloud; self-hosted installs @apify/n8n-nodes-apify), a Gmail connection, the API keys you want watched.\n\n**How to customize**\nThe pre-wired list is a head start, not a limit: any other authenticated HTTP endpoint can be watched with a generic_http check. Tune quotaWarningPct (default 80) and the schedule. Cost: 3 keys at 1 run/day is about $1.83/month.\n\nDocs: https://datasourcepulse.com/integrations/n8n",
        "height": 1140,
        "width": 520
      },
      "id": "sticky-setup",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -700,
        -420
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "daysInterval": 1,
              "triggerAtHour": 8,
              "triggerAtMinute": 0
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "When Every Morning at 8",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -80,
        40
      ]
    },
    {
      "parameters": {
        "resource": "Actors",
        "operation": "Run actor and get dataset",
        "actorId": {
          "__rl": true,
          "value": "UEt39k7v1DkIYp8Gh",
          "mode": "list",
          "cachedResultName": "Datasource Pulse (growth_wizard/datasource-pulse)",
          "cachedResultUrl": "https://console.apify.com/actors/UEt39k7v1DkIYp8Gh/input"
        },
        "customBody": "{\n  \"checks\": [\n    {\n      \"type\": \"credential\",\n      \"id\": \"openai-prod\",\n      \"label\": \"OpenAI · production key\",\n      \"vendor\": \"openai\",\n      \"apiKey\": \"PASTE_OPENAI_API_KEY\",\n      \"impact\": \"LLM features fail when this key dies\"\n    },\n    {\n      \"type\": \"credential\",\n      \"id\": \"serpapi-main\",\n      \"label\": \"SerpAPI · search quota\",\n      \"vendor\": \"serpapi\",\n      \"apiKey\": \"PASTE_SERPAPI_KEY\",\n      \"quotaSoftCap\": 4500,\n      \"impact\": \"Search enrichment stops at quota\"\n    },\n    {\n      \"type\": \"credential\",\n      \"id\": \"apify-account\",\n      \"label\": \"Apify · monthly spend cap\",\n      \"vendor\": \"apify\",\n      \"apiKey\": \"PASTE_APIFY_TOKEN\",\n      \"quotaSoftCap\": 40,\n      \"impact\": \"Scrapers stop when platform credits run out\"\n    }\n  ],\n  \"quotaWarningPct\": 80\n}",
        "actorSource": "recentlyUsed"
      },
      "id": "run-datasource-pulse",
      "name": "Initiate Datasource Pulse",
      "type": "@apify/n8n-nodes-apify.apify",
      "typeVersion": 1,
      "position": [
        160,
        40
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "state-not-healthy",
              "leftValue": "={{ $json.state }}",
              "rightValue": "healthy",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-unhealthy",
      "name": "If State Unhealthy",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        400,
        40
      ]
    },
    {
      "parameters": {
        "sendTo": "you@example.com",
        "subject": "=🚨 {{ $json.connector_label }} · {{ $json.state }} (Datasource Pulse)",
        "emailType": "text",
        "message": "={{ $json.message }}\n\nConnector: {{ $json.connector_id }}\nState: {{ $json.state }}\nFailure class: {{ $json.failure_class }}\nChecked at: {{ $json.run_at }}",
        "options": {}
      },
      "id": "gmail-alert",
      "name": "Send Gmail Alert",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        640,
        20
      ]
    },
    {
      "parameters": {
        "content": "### 1 · Schedule\nTune the cadence here. Cost scales with runs per day.",
        "height": 150,
        "width": 220,
        "color": 7
      },
      "id": "sticky-step-1",
      "name": "Sticky Note (sticky-step-1)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -110,
        -140
      ]
    },
    {
      "parameters": {
        "content": "### 2 · Run the checks\nDatasource Pulse runs every check in *Input JSON* and returns one verdict per check, each with a stable failure_class.",
        "height": 190,
        "width": 230,
        "color": 7
      },
      "id": "sticky-step-2",
      "name": "Sticky Note (sticky-step-2)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        130,
        -180
      ]
    },
    {
      "parameters": {
        "content": "### 3 · Alert on anything not healthy\nhealthy verdicts stop at the filter; dead keys, rate limits, and quota warnings land in your inbox.",
        "height": 150,
        "width": 430,
        "color": 7
      },
      "id": "sticky-step-3",
      "name": "Sticky Note (sticky-step-3)",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        380,
        -140
      ]
    }
  ],
  "connections": {
    "When Every Morning at 8": {
      "main": [
        [
          {
            "node": "Initiate Datasource Pulse",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Initiate Datasource Pulse": {
      "main": [
        [
          {
            "node": "If State Unhealthy",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If State Unhealthy": {
      "main": [
        [
          {
            "node": "Send Gmail Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
