Een nieuwe vacature schrijven kost een recruiter gemiddeld 3 tot 4 uur: functiebeschrijving opstellen, tone of voice bewaken, formatteren voor verschillende platforms, publiceren. Met n8n en Claude automatiseer je het hele proces. Van functiebeschrijving in Notion tot gepubliceerde vacature op LinkedIn. Wat overblijft is het beoordelen van kandidaten.
Stap 1: Voorbereiding
Je hebt vier dingen nodig: een n8n instance (self-hosted of n8n.cloud), een LinkedIn Developer App met de juiste permissies, een Claude API key en een Notion database voor functiebeschrijvingen.
LinkedIn Developer App aanmaken: Ga naar developers.linkedin.com, maak een nieuwe app aan. Vraag de volgende OAuth scopes aan: r_organization_social, w_member_social, r_liteprofile. Na goedkeuring (1-3 werkdagen) krijg je een client ID en client secret.
# n8n omgevingsvariabelen (.env)
CLAUDE_API_KEY=sk-ant-your_key_here
LINKEDIN_CLIENT_ID=your_client_id
LINKEDIN_CLIENT_SECRET=your_client_secret
LINKEDIN_ORG_URN=urn:li:organization:YOUR_ORG_ID
NOTION_API_KEY=secret_your_notion_key
NOTION_DATABASE_ID=your_database_id
HR_EMAIL=hr@jouwbedrijf.nl
Stap 2: Notion database structuur
Maak een Notion database aan met de volgende eigenschappen (properties). De juiste structuur maakt het verschil tussen een werkend systeem en een bron van fouten.
Verplichte properties: Functietitel (Title), Afdeling (Select), Niveau (Select: Junior/Medior/Senior), Vereisten (Text), Startdatum (Date), Status (Select: Concept/Gereed/Gepubliceerd/Gearchiveerd), Vestiging (Select), Uren per week (Number).
// Notion database schema (API formaat)
{
"Functietitel": {"title": {}},
"Afdeling": {"select": {
"options": [
{"name": "Marketing", "color": "blue"},
{"name": "Sales", "color": "green"},
{"name": "Tech", "color": "purple"},
{"name": "Operations", "color": "orange"}
]
}},
"Niveau": {"select": {
"options": [
{"name": "Junior"}, {"name": "Medior"}, {"name": "Senior"}
]
}},
"Status": {"select": {
"options": [
{"name": "Concept"}, {"name": "Gereed"},
{"name": "Gepubliceerd"}, {"name": "Gearchiveerd"}
]
}},
"Startdatum": {"date": {}},
"Vereisten": {"rich_text": {}},
"Uren per week": {"number": {}}
}
Stap 3: n8n Notion-trigger instellen
De n8n workflow start automatisch wanneer iemand de Status van een vacature in Notion wijzigt naar 'Gereed'. Dit is de trigger voor het publicatieproces.
Voeg een Notion Trigger node toe. Kies 'Page updated' als event en filter op de database ID. Voeg een IF node toe die controleert of de Status property gelijk is aan 'Gereed'. Zo triggert de workflow alleen bij de juiste statuswijziging.
// n8n Notion Trigger configuratie (JSON export)
{
"nodes": [{
"name": "Notion Trigger",
"type": "n8n-nodes-base.notionTrigger",
"parameters": {
"resource": "page",
"databaseId": "={{$env.NOTION_DATABASE_ID}}",
"event": "pageUpdated"
}
}, {
"name": "Check Status",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"string": [{
"value1": "={{$json.properties.Status.select.name}}",
"operation": "equal",
"value2": "Gereed"
}]
}
}
}]
}
Stap 4: Data ophalen en structureren
Na de trigger haal je de volledige vacaturedata op via een Notion node (Get Page). Vervolgens structureer je de data in een Set node zodat volgende nodes eenvoudig met de variabelen kunnen werken.
// Set node - data structureren
{
"functietitel": "={{$json.properties.Functietitel.title[0].plain_text}}",
"afdeling": "={{$json.properties.Afdeling.select.name}}",
"niveau": "={{$json.properties.Niveau.select.name}}",
"vereisten": "={{$json.properties.Vereisten.rich_text[0].plain_text}}",
"startdatum": "={{$json.properties.Startdatum.date.start}}",
"uren": "={{$json.properties['Uren per week'].number}}",
"vestiging": "={{$json.properties.Vestiging.select.name}}",
"notion_page_id": "={{$json.id}}"
}
Stap 5: Claude vacaturetekst laten schrijven
Hier gebeurt de magie. Je stuurt de gestructureerde vacaturedata naar Claude met een gedetailleerde system prompt die de bedrijfstoon vastlegt. Claude returnt de vacaturetekst als JSON voor eenvoudige verdere verwerking.
// Claude HTTP Request node configuratie
URL: https://api.anthropic.com/v1/messages
Method: POST
Headers:
anthropic-version: 2023-06-01
x-api-key: {{$env.CLAUDE_API_KEY}}
Body:
{
"model": "claude-opus-4-5",
"max_tokens": 1500,
"system": "Je bent een ervaren recruitment copywriter voor [Bedrijfsnaam]. Schrijf vacatureteksten in een professionele maar menselijke toon. Gebruik 'jij' en 'je' (geen 'u'). Vermijd cliches zoals 'no-nonsense', 'hands-on' en 'resultaatgericht'. Focus op wat de kandidaat gaat doen en leren, niet op een endloze lijst eisen. Retourneer ALTIJD een JSON object met keys: linkedin_post (max 700 tekens voor LinkedIn), volledige_vacature (600-800 woorden), en samenvatting (max 200 tekens).",
"messages": [{
"role": "user",
"content": "Schrijf een vacaturetekst voor:\nFunctie: {{functietitel}}\nAfdeling: {{afdeling}}\nNiveau: {{niveau}}\nVereisten: {{vereisten}}\nStartdatum: {{startdatum}}\nUren: {{uren}} uur per week\nVestiging: {{vestiging}}"
}]
}
Stap 6: Claude output parsen en valideren
Claude retourneert de tekst als JSON-string binnen een message. Gebruik een Code node in n8n om de JSON te parsen en valideren voordat je doorgaat.
// n8n Code node - Claude output parsen
const claudeResponse = items[0].json.content[0].text;
// Parse JSON van Claude
let vacatureData;
try {
// Claude omringt JSON soms met markdown
const jsonMatch = claudeResponse.match(/\{[\s\S]*\}/);
if (jsonMatch) {
vacatureData = JSON.parse(jsonMatch[0]);
} else {
throw new Error('Geen JSON gevonden in Claude response');
}
} catch (e) {
throw new Error(`JSON parse fout: ${e.message}\nResponse: ${claudeResponse}`);
}
// Valideer verplichte keys
const required = ['linkedin_post', 'volledige_vacature', 'samenvatting'];
for (const key of required) {
if (!vacatureData[key]) {
throw new Error(`Ontbrekende key in Claude output: ${key}`);
}
}
// Valideer LinkedIn tekst lengte
if (vacatureData.linkedin_post.length > 700) {
vacatureData.linkedin_post = vacatureData.linkedin_post.substring(0, 697) + '...';
}
return [{ json: vacatureData }];
Stap 7: LinkedIn API aanroepen
De LinkedIn UGC Posts API publiceert de vacature als organisch bericht op de bedrijfspagina. Zorg dat je de organisatie-URN bij de hand hebt (te vinden in LinkedIn Company Admin).
// LinkedIn UGC Posts API - HTTP Request node
URL: https://api.linkedin.com/v2/ugcPosts
Method: POST
Headers:
Authorization: Bearer {{LinkedIn Access Token}}
Content-Type: application/json
X-Restli-Protocol-Version: 2.0.0
Body:
{
"author": "{{$env.LINKEDIN_ORG_URN}}",
"lifecycleState": "PUBLISHED",
"specificContent": {
"com.linkedin.ugc.ShareContent": {
"shareCommentary": {
"text": "{{linkedin_post}}\n\n#vacature #{{afdeling}} #{{niveau}} #werkenbij[Bedrijfsnaam]"
},
"shareMediaCategory": "NONE"
}
},
"visibility": {
"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"
}
}
Stap 8: Bevestiging terugschrijven naar Notion en Gmail-notificatie
Schrijf de resultaten terug naar Notion (status naar 'Gepubliceerd', sla de LinkedIn post-ID op) en stuur een bevestigingsmail naar HR.
// Notion Update Page node
Page ID: {{notion_page_id}}
Properties:
Status: {
"select": {"name": "Gepubliceerd"}
}
LinkedIn Post ID: {
"rich_text": [{"text": {"content": "{{linkedin_post_id}}"}}]
}
Gepubliceerd op: {
"date": {"start": "{{$now}}"}
}
// Gmail Send Email node
To: {{$env.HR_EMAIL}}
Subject: Vacature gepubliceerd: {{functietitel}}
Body:
De vacature voor {{functietitel}} ({{afdeling}}, {{niveau}}) is succesvol
gepubliceerd op LinkedIn.
LinkedIn post ID: {{linkedin_post_id}}
Bekijk de post: https://www.linkedin.com/feed/update/{{linkedin_post_id}}
De volledige vacaturetekst is beschikbaar in Notion.
Troubleshooting
LinkedIn API rate limits: LinkedIn beperkt UGC Posts tot 100 per dag per app. Voor normale recruitment volumes is dit ruim voldoende. Bij hoge volumes (50+ vacatures per dag): gebruik de LinkedIn Marketing API met een enterprise account.
Token expiry: LinkedIn OAuth tokens verlopen na 60 dagen. Implementeer token refresh logic in n8n: voeg een HTTP Request node toe die het token refresht met de refresh_token voor elke workflow run. Sla het nieuwe access token op in n8n credentials.
Notion webhook delays: De Notion API heeft soms vertraging van 1-5 minuten bij trigger events. Dit is normaal en geen fout. Als je directere triggers nodig hebt, gebruik dan een polling-workflow (elke 5 minuten checken op Status='Gereed') in plaats van een webhook trigger.
Uitbreidingen
Indeed en Glassdoor: Beide platforms bieden API's voor vacatureplaatsing. Indeed heeft een XML feed-systeem; Glassdoor werkt via een partner API. Voeg extra HTTP Request nodes toe na de LinkedIn-publicatie voor gelijktijdig plaatsen.
ATS-koppeling: Koppel het systeem aan een Applicant Tracking System zoals Teamtailor, Recruitee of Homerun. De meeste ATS-tools hebben een REST API. Maak automatisch een vacature aan in het ATS zodra LinkedIn-publicatie succesvol is.
Automatisch reageren op sollicitaties: Bouw een tweede n8n workflow die nieuwe LinkedIn sollicitaties ophaalt (LinkedIn Applications API), een eerste bevestigingsmail stuurt via Claude (gepersonaliseerd op basis van het CV) en de sollicitant toevoegt aan je ATS.