{
  "nodes": [
    {
      "id": "84ecf4b5-8ee0-4dfa-84ab-e2dd605743a5",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        -224
      ],
      "parameters": {
        "width": 480,
        "height": 1232,
        "content": "## Auto-Approve Skool Members with AI Screening\n\n**Who's this for?**\nCommunity managers on Skool who want to approve new members 24/7 without losing quality control. Ideal for founders running course communities, SaaS support groups, or niche paid circles.\n\n### How it works\n\n1. **Triggers every 6 hours** to check for pending members (configurable to any interval).\n2. **Retrieves Skool credentials** and performs login via the Skool All-in-One API Apify actor to get session cookies.\n3. **Fetches pending members** with their application answers.\n4. **GPT-4o-mini screens** each applicant against criteria you define in the prompt.\n5. **Branches the decision**: approved members get accepted automatically; rejected members stay pending for your manual review.\n\n### Requirements\n\n- Apify account + API token (free tier works to start)\n- OpenAI API key (~$0.0001 per applicant with GPT-4o-mini)\n- Skool community where you have admin rights\n\n### Setup steps\n\n- [ ] Create Apify and OpenAI credentials in n8n (Settings \u2192 Credentials).\n- [ ] In the **Config** node, set your Skool `email`, `password` and `groupSlug` (from `skool.com/{slug}`).\n- [ ] Attach your OpenAI credential to the **AI Screen Applicant** node.\n- [ ] Test first with the **Approve Member** node disconnected \u2014 run it manually and review the AI decisions on real pending members.\n- [ ] Customize the AI prompt in **AI Screen Applicant** to match your community's criteria.\n- [ ] Reconnect **Approve Member** and activate the workflow.\n\n### Customization\n\n- Adjust the schedule from every 6 hours to your preferred interval depending on application volume.\n- Swap GPT-4o-mini for Claude, Gemini, or a local model via the corresponding nodes.\n- Extend the Approve path with a welcome DM, Slack notification, or CRM entry.\n- Extend the Reject path with a Slack alert for manual review instead of just logging.\n\n### Actor\n[Skool All-in-One API on Apify](https://apify.com/cristiantala/skool-all-in-one-api) \u2014 full read/write access to Skool communities."
      },
      "typeVersion": 1
    },
    {
      "id": "78cc9b06-585e-4f4a-99f3-bfab7453d857",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 464,
        "content": "## Scheduled trigger + Config\n\n**Every 6 Hours** triggers the workflow on a cron schedule. Adjust to your application volume.\n\n**Config** centralizes all your credentials \u2014 `email`, `password`, and `groupSlug`. Every downstream node references these values, so you only change them here.\n\n**Security tip:** for production, move these to n8n environment variables."
      },
      "typeVersion": 1
    },
    {
      "id": "ff6b8aea-36f1-4700-b3c6-f5509d3732b2",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        640,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 464,
        "content": "## Login and authentication\n\n**Skool Login** runs the Skool All-in-One API actor on Apify with `action: auth:login`. **Get Login Cookies** extracts the cookies string from the actor's dataset.\n\nThe cookies are valid ~3.5 days and reused by every downstream actor call, skipping Playwright re-login (runs in ~2s instead of ~10s per call)."
      },
      "typeVersion": 1
    },
    {
      "id": "a4442c06-1e14-4a2b-822d-4ffe728459f9",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        256
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 464,
        "content": "## Fetch pending members\n\nCalls the actor with `action: members:pending` to fetch every member awaiting approval.\n\nEach result includes the applicant's `memberId`, name, avatar, and **answers to the community application questions** \u2014 which is the material the AI uses to decide.\n\nIf the pending list is empty the workflow does nothing this cycle."
      },
      "typeVersion": 1
    },
    {
      "id": "efb81414-c4a9-4f3a-b185-1a9724b143cd",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        32
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 688,
        "content": "## AI screening and decision\n\n**GPT-4o-mini** evaluates each applicant and returns structured JSON: `{ memberId, decision: \"approve\" | \"reject\", reason }`. The **IF** node routes on `decision === \"approve\"`.\n\n### Customize the prompt for your community\n\n- Describe what a \"good fit\" looks like (industry, role, stage).\n- Set strictness \u2014 \"be lenient\" for growth, \"be strict\" for exclusive.\n- Require specific answers (LinkedIn URL, email, detailed reasoning).\n- Ask for reasoning so you can audit decisions later.\n\n### Tips\n\n- Keep temperature at 0.1 for consistency.\n- Set maxTokens to 200 (enough for JSON + reason).\n- Test with 5-10 real applications before activating.\n- Alternatives: GPT-4o (stricter), Claude 3.5 Haiku, Gemini 2.0 Flash, Llama 3 via Ollama."
      },
      "typeVersion": 1
    },
    {
      "id": "78c4689a-5d4c-416d-bdf0-b0942e8f91d7",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2112,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 1072,
        "content": "## Outcome handling\n\n### \u2705 Approve path (top)\n\n**Prepare Approve** extracts the `memberId` from the AI output. **Approve Member** calls the actor with `action: members:approve`.\n\n\u26a0\ufe0f **Safety first:** test with this node disconnected and review AI decisions before going live.\n\n**Ideas for next steps after approval:**\n- Send a welcome DM via the actor (`posts:createComment`)\n- Notify your team on Slack or Discord\n- Log approved members to Google Sheets\n- Trigger an onboarding email sequence\n\n### \u274c Reject path (bottom)\n\n**Log Rejection** writes the memberId + reason to the execution log. **Rejected members are NOT auto-declined** \u2014 they stay pending so you can review AI reasoning and override mistakes.\n\n**Enhance this branch:**\n- Slack/email notification for manual review\n- Log rejections to Google Sheets with AI reasoning\n- Auto-decline after X days with no manual override"
      },
      "typeVersion": 1
    },
    {
      "id": "bd0695b4-32a1-4af2-94e1-8c32c6f607ce",
      "name": "Every 6 Hours",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        240,
        544
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "6cca66af-061d-4720-b282-2223f20b908c",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "position": [
        464,
        544
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "email",
              "name": "email",
              "type": "string",
              "value": "user@example.com"
            },
            {
              "id": "password",
              "name": "password",
              "type": "string",
              "value": "your-skool-password"
            },
            {
              "id": "groupSlug",
              "name": "groupSlug",
              "type": "string",
              "value": "your-community-slug"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "43e923ed-2ab1-410b-a64c-2fb9a3990819",
      "name": "Skool Login",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        688,
        544
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "g2VGrINIS7pb8t2bs",
          "cachedResultUrl": "https://console.apify.com/actors/g2VGrINIS7pb8t2bs/input",
          "cachedResultName": "Skool All-in-One API"
        },
        "customBody": "={{ JSON.stringify({ action: \"auth:login\", email: $(\"Config\").first().json.email, password: $(\"Config\").first().json.password, groupSlug: $(\"Config\").first().json.groupSlug }) }}"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "6eec071b-aeee-425a-a2cd-96278b67e681",
      "name": "Get Login Cookies",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        912,
        544
      ],
      "parameters": {
        "options": {},
        "resource": "Datasets",
        "datasetId": "={{ $json.defaultDatasetId }}"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "6abfcebe-db7a-4693-aae8-19ed06676200",
      "name": "Get Pending Members",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        1136,
        544
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "g2VGrINIS7pb8t2bs",
          "cachedResultUrl": "https://console.apify.com/actors/g2VGrINIS7pb8t2bs/input",
          "cachedResultName": "Skool All-in-One API"
        },
        "customBody": "={{ JSON.stringify({ action: \"members:pending\", cookies: $json.cookies, groupSlug: $(\"Config\").first().json.groupSlug }) }}"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "dd959c22-8b83-457b-9641-f51d4f930180",
      "name": "Get Pending Results",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        1360,
        544
      ],
      "parameters": {
        "options": {},
        "resource": "Datasets",
        "datasetId": "={{ $json.defaultDatasetId }}"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "5c4995de-36fc-4e81-bd80-8eff9dd2fab6",
      "name": "AI Screen Applicant",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1584,
        544
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "GPT-4O-MINI"
        },
        "options": {
          "maxTokens": 200,
          "temperature": 0.1
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a community gatekeeper for \"Cagala, Aprende, Repite\". Evaluate the membership application and respond with a JSON object:\n\n{\"decision\": \"approve\" or \"reject\", \"reason\": \"brief explanation in Spanish\", \"memberId\": \"<MEMBER_ID>\"}\n\nApproval criteria:\n- Has a real LinkedIn profile URL (not \"no tengo\" or empty)\n- Gave a specific, thoughtful answer about their biggest challenge (not generic)\n- Provided a valid email\n\nIMPORTANT: Include the memberId from the application in your response."
            },
            {
              "content": "=memberId: {{ $json.memberId }}\nApplicant: {{ $json.firstName }} {{ $json.lastName }}\nLocation: {{ $json.requestLocation }}\nSource: {{ $json.source }} \nBio: {{ $json.bio }}\n\nApplication answers:\n{{ $json.answers ? $json.answers.map(a => \"Q: \" + a.question.substring(0, 80) + \"\\nA: \" + a.answer).join(\"\\n\\n\") : \"No answers available\" }}"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {},
      "typeVersion": 1.4
    },
    {
      "id": "bb386dd3-bafd-4baa-9ecc-5c3f8688f8c0",
      "name": "Approve or Reject?",
      "type": "n8n-nodes-base.if",
      "position": [
        1936,
        544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "is-approve",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.message.content.decision }}",
              "rightValue": "approve"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "f7a7950b-d557-46cf-b035-9fec9e91c847",
      "name": "Approve Member",
      "type": "@apify/n8n-nodes-apify.apify",
      "position": [
        2400,
        448
      ],
      "parameters": {
        "actorId": {
          "__rl": true,
          "mode": "list",
          "value": "g2VGrINIS7pb8t2bs",
          "cachedResultUrl": "https://console.apify.com/actors/g2VGrINIS7pb8t2bs/input",
          "cachedResultName": "Skool All-in-One API"
        },
        "customBody": "={{ JSON.stringify({ action: \"members:approve\", cookies: $json.cookies, groupSlug: $json.groupSlug, params: { memberId: $json.memberId } }) }}"
      },
      "credentials": {},
      "typeVersion": 1
    },
    {
      "id": "3e354c25-723b-4d6b-bb70-e59aa5e968be",
      "name": "Log Rejection",
      "type": "n8n-nodes-base.code",
      "position": [
        2160,
        672
      ],
      "parameters": {
        "jsCode": "// Rejected members stay pending \u2014 no action needed\n// Log the rejection for review\nconst items = $input.all();\nreturn items.map(item => ({\n  json: {\n    status: 'rejected',\n    memberId: item.json.memberId,\n    reason: item.json.reason\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "0304f621-8928-4df1-8bb1-e0315d62a2b5",
      "name": "Prepare Approve",
      "type": "n8n-nodes-base.set",
      "position": [
        2160,
        448
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "memberId",
              "name": "memberId",
              "type": "string",
              "value": "={{ $(\"Get Pending Results\").item.json.memberId }}"
            },
            {
              "id": "firstName",
              "name": "firstName",
              "type": "string",
              "value": "={{ $(\"Get Pending Results\").item.json.firstName }}"
            },
            {
              "id": "lastName",
              "name": "lastName",
              "type": "string",
              "value": "={{ $(\"Get Pending Results\").item.json.lastName }}"
            },
            {
              "id": "decision",
              "name": "decision",
              "type": "string",
              "value": "={{ $json.message.content.decision }}"
            },
            {
              "id": "reason",
              "name": "reason",
              "type": "string",
              "value": "={{ $json.message.content.reason }}"
            },
            {
              "id": "cookies",
              "name": "cookies",
              "type": "string",
              "value": "={{ $(\"Get Login Cookies\").first().json.cookies }}"
            },
            {
              "id": "groupSlug",
              "name": "groupSlug",
              "type": "string",
              "value": "={{ $(\"Config\").first().json.groupSlug }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "connections": {
    "Config": {
      "main": [
        [
          {
            "node": "Skool Login",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skool Login": {
      "main": [
        [
          {
            "node": "Get Login Cookies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every 6 Hours": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Approve": {
      "main": [
        [
          {
            "node": "Approve Member",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Login Cookies": {
      "main": [
        [
          {
            "node": "Get Pending Members",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approve or Reject?": {
      "main": [
        [
          {
            "node": "Prepare Approve",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log Rejection",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Screen Applicant": {
      "main": [
        [
          {
            "node": "Approve or Reject?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Pending Members": {
      "main": [
        [
          {
            "node": "Get Pending Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Pending Results": {
      "main": [
        [
          {
            "node": "AI Screen Applicant",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}