How to Build Automated Job Alerts with n8n - Jobven API Tutorial

Manually checking job boards every day gets old fast. Whether you're job hunting, tracking competitors, or monitoring the market, you end up refreshing the same pages hoping something new appeared.
What if new jobs just showed up in your inbox instead?
In this tutorial, I'll show you how to build an automated job alert system using n8n (a workflow automation tool) and a job API. Once set up, you'll get email notifications whenever new jobs matching your criteria are posted.
The whole thing takes about 20 minutes to build.
What We're Building
Here's the workflow:
- Schedule trigger - Runs every hour (or however often you want)
- Fetch jobs - Calls a job API to get recent postings
- Filter - Keeps only jobs matching your criteria
- Send email - Notifies you about matching jobs
By the end, you'll have a working job alert system that runs automatically.
Prerequisites
You'll need:
- n8n account - Sign up for n8n Cloud (free tier available) or self-host
- Jobven API key - Sign up here (free tier includes 300 requests/month)
- Email - We'll use n8n's built-in email node, or you can use Gmail/Outlook
Step 1: Create a New Workflow
Open n8n and create a new workflow. Name it something like "Job Alerts".
You'll start with an empty canvas. Let's add nodes.
Step 2: Add the Schedule Trigger
Click the + button and search for "Schedule Trigger". Add it to your workflow.
Configure it to run every hour:
- Trigger Interval: Hours
- Hours Between Triggers: 1
You can adjust this based on how often you want alerts. For job hunting, hourly is usually enough. For competitive intelligence, you might want every 15 minutes.
Step 3: Fetch Jobs from the API
Add an HTTP Request node and connect it to the Schedule Trigger.
Configure it:
| Setting | Value |
|---|---|
| Method | GET |
| URL | https://api.jobven.com/v1/public/jobs |
| Authentication | Header Auth |
| Header Name | X-API-Key |
| Header Value | Your Jobven API key |
Add Query Parameters
Click "Add Parameter" to filter jobs. Here's an example setup for remote software engineering jobs posted in the last hour:
| Parameter | Value |
|---|---|
q | software engineer |
remoteType[] | remote |
postedAfter | ={{ $now.minus(1, 'hour').toSeconds().round() }} |
limit | 10 |
Note: remoteType[] uses array syntax because the API accepts multiple values (e.g., remote, hybrid). The postedAfter parameter uses n8n expressions to calculate the Unix timestamp for 1 hour ago. The .round() ensures it's a whole number.
Tip: When testing, try a longer time window like $now.minus(1, 'week') or $now.minus(1, 'day'). Companies rarely post jobs on weekends or holidays, so a 1-hour window might return no results. Once you've verified the workflow works, adjust the interval to match your schedule trigger.
Available Filters
You can customize the query with these parameters:
q- Search query (searches title, summary, description)remoteType-remote,hybrid,onsite, orflexibleexperienceLevel-entry,mid,senior,lead, orexecutiveemploymentType-full_time,part_time,contract, etc.skills- Filter by required skills (e.g.,react,typescript)location- City, state, or countryminSalary/maxSalary- Salary range filterpostedAfter- Unix timestamp (seconds) for freshness
Step 4: Handle the Response
The API returns jobs in this format:
{
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"title": "Senior Software Engineer",
"summary": "Build scalable systems for a growing fintech company",
"description": "<p>We're looking for a Senior Software Engineer...</p>",
"companies": [{ "name": "Acme Corp", "website": "https://acme.com" }],
"locations": [{
"addressLocality": "San Francisco",
"addressRegion": "California",
"addressCountry": "US",
"workLocation": "remote"
}],
"remoteType": "remote",
"salary": { "min": 150000, "max": 200000, "currency": "USD", "period": "annual" },
"skills": { "primary_skills": ["Python", "AWS", "PostgreSQL"] },
"experienceLevel": "senior",
"employmentType": "full_time",
"applyUrl": "https://acme.com/careers/123",
"postedAt": 1735344000,
"status": "active"
}
],
"meta": {
"total": 150,
"count": 1,
"hasMore": true,
"nextCursor": "eyJpZCI6ImFiYzEyMyJ9"
}
}
Add a Code node to extract and format all jobs into a single digest:
const response = $input.first().json;
const jobs = response.data;
if (!jobs || jobs.length === 0) {
return []; // No jobs found, workflow stops here
}
// Build HTML for each job
const jobsHtml = jobs.map(job => {
const company = job.companies?.[0]?.name || 'Unknown';
const location = job.locations?.[0]?.addressLocality || 'Remote';
const country = job.locations?.[0]?.addressCountry || '';
const salary = job.salary
? `${job.salary.currency || 'USD'} ${job.salary.min?.toLocaleString() || '?'} - ${job.salary.max?.toLocaleString() || '?'}`
: 'Not disclosed';
const skills = job.skills?.primary_skills?.slice(0, 5).join(', ') || 'Not specified';
const postedAt = job.postedAt
? new Date(job.postedAt * 1000).toLocaleDateString()
: 'Unknown';
return `
<div style="border: 1px solid #e5e7eb; border-radius: 8px; padding: 16px; margin-bottom: 16px;">
<h3 style="margin: 0 0 8px 0;">${job.title}</h3>
<p style="margin: 4px 0; color: #6b7280;"><strong>${company}</strong> · ${location}${country ? ` (${country})` : ''} · ${job.remoteType || 'Not specified'}</p>
<p style="margin: 4px 0;"><strong>Salary:</strong> ${salary}</p>
<p style="margin: 4px 0;"><strong>Skills:</strong> ${skills}</p>
<p style="margin: 4px 0; font-size: 12px; color: #9ca3af;">Posted: ${postedAt}</p>
<a href="${job.applyUrl}" style="display: inline-block; margin-top: 8px; background: #2563eb; color: white; padding: 8px 16px; text-decoration: none; border-radius: 4px;">Apply Now</a>
</div>
`;
}).join('');
// Return single item with digest
return [{
json: {
jobCount: jobs.length,
subject: `Job Alert: ${jobs.length} new job${jobs.length > 1 ? 's' : ''} found`,
htmlContent: `
<h2>New Job Alerts</h2>
<p>Found ${jobs.length} new job${jobs.length > 1 ? 's' : ''} matching your criteria:</p>
${jobsHtml}
<hr style="margin-top: 24px; border: none; border-top: 1px solid #e5e7eb;" />
<p style="font-size: 12px; color: #9ca3af;">Powered by <a href="https://jobven.com">Jobven</a></p>
`
}
}];
This creates a single digest email with all matching jobs, instead of one email per job.
Step 5: Additional Filtering (Optional)
The API supports many filters, but if you need custom logic, add it in the Code node before building the digest.
For example, to only include jobs with salary info, modify the Code node:
// After getting jobs from response.data
const filteredJobs = jobs.filter(job => job.salary && job.salary.min);
// Then use filteredJobs instead of jobs for the rest
Or filter by specific companies:
const filteredJobs = jobs.filter(job =>
job.companies?.[0]?.name?.toLowerCase().includes('stripe')
);
Step 6: Send Email Notifications
Add a Send Email node (or Gmail/Outlook node if you prefer).
Since the Code node already built the HTML content, configuration is simple:
| Setting | Value |
|---|---|
| To | Your email address |
| Subject | ={{ $json.subject }} |
| HTML | ={{ $json.htmlContent }} |
The = prefix tells n8n to evaluate the expression. The subject and HTML content are already formatted by the Code node, so you just reference them directly.
Alternative: Slack Notifications
If you prefer Slack over email:
- Add a Slack node instead
- Connect to your Slack workspace
- Choose a channel
- Use a similar message format
Step 7: Test Your Workflow
Before activating:
- Click Test Workflow to run it manually
- Check if jobs are fetched correctly
- Verify the email/Slack message looks right
If no jobs appear, try removing the postedAfter parameter temporarily to test with existing jobs.
Step 8: Activate
Once everything works, click Activate in the top right.
Your workflow will now run automatically on schedule. Every hour (or whatever interval you set), it will:
- Check for new jobs
- Filter by your criteria
- Send you notifications
The Complete Workflow
Here's what the finished workflow looks like:

Download the Workflow
Want to skip the setup? Download the complete workflow JSON and import it into n8n.
After importing, just add your Jobven API key and email settings.
Customization Ideas
Once you have the basic workflow running, try these variations:
Multiple searches - Duplicate the HTTP Request node with different filters, then merge results before sending
Daily digest - Instead of instant alerts, collect jobs throughout the day and send one summary email
Save to spreadsheet - Add a Google Sheets node to track all jobs you've been alerted about
Deduplication - Use n8n's storage or a Google Sheet to track job IDs and avoid duplicate alerts
Wrapping Up
You now have an automated job alert system that:
- Runs on a schedule
- Fetches fresh job postings from employer career pages
- Filters by your criteria
- Sends notifications automatically
No more manual checking. Jobs come to you.
Need job data for your project? Jobven provides fresh job postings scraped directly from employer career pages. Get your free API key →
What is a Job Posting API?
A developer's guide to job posting APIs - what they are, how they work, and why I built one after struggling with job data myself.
Webhooks Launch
Subscribe to job lifecycle events and react in real time instead of polling. HMAC-signed, retried on failure, gated on a verified test event.