← All posts

Vibeworker Webhook Quickstart: Real-Time Upwork Job Alerts

Vibeworker fires a POST request to any HTTPS URL you give it the moment a job matches your filter — before most people have opened their browser. This page is the reference for the full payload, how to set it up, and copy-paste receiver code for the most common destinations.


Setup

  1. Open your Vibeworker dashboard and open a filter
  2. Go to the filter's Alert settings → Webhook
  3. Enable the channel and paste your HTTPS endpoint URL
  4. Hit Preview alert

That's it. Preview alert sends a real sample payload immediately — you don't have to wait for a live job match to confirm your receiver is working.


The payload

Every webhook POST has this structure:

{
  "event": "job.matched",
  "filterName": "Next.js fixed-price",
  "match": {
    "scoreQuickWin": 7,
    "scoreScopeClarity": 8,
    "scoreRedFlags": 9,
    "effortEstimateHours": 20
  },
  "job": {
    "title": "Build a Next.js e-commerce site",
    "description": "We need a full e-commerce build using Next.js 14...",
    "url": "https://www.upwork.com/jobs/~...",
    "type": "fixed",
    "budget": { "min": 1200, "max": null, "currency": "USD", "display": "$1,200" },
    "skills": ["Next.js", "TypeScript"]
  },
  "client": {
    "totalSpent": 62000,
    "hireRate": 74,
    "paymentVerified": true,
    "location": "United States"
  }
}

Every request also carries the header X-Vibeworker-Event: job.matched.

Score fields:

Field What it means Range
scoreQuickWin Fixed price, clear deliverable, completable fast 0–10
scoreScopeClarity How precisely the deliverable is defined 0–10
scoreRedFlags Absence of bad signals — 10 means clean 0–10
effortEstimateHours AI estimate of hours to complete hours

scoreRedFlags is inverted — higher is better. A job with a 2 has serious red flags; a 9 is clean.


Security

Treat your webhook endpoint URL like a password. It's the only credential — there are no signature headers to verify. Anyone with the URL can POST to it.

Practical rules:

  • Don't log the URL or commit it to source control
  • Use a random-looking path (Cloudflare Workers generates one automatically)
  • Rotate it by disabling and re-enabling the webhook in filter settings if you suspect it's been shared

Receivers

n8n (no code)

Drop a Webhook node onto the canvas. Set the method to POST and copy the production URL. That's your endpoint. The full step-by-step with an importable template — including AI proposal generation — is in the n8n job alert guide.

Cloudflare Workers (minimal code, free)

export default {
  async fetch(request, env) {
    const body = await request.json();
    if (body.event !== 'job.matched') return new Response('ok');

    const { job, match, client } = body;

    // your logic here — POST to Slack, log to KV, call an API, etc.
    console.log(`New match: ${job.title} | QW ${match.scoreQuickWin} | ${job.budget.display}`);

    return new Response('ok');
  },
};

Deploy with wrangler deploy. The worker URL is your webhook endpoint. Set any secrets (Slack URLs, API keys) via wrangler secret put.

The Slack alert guide and Discord alert guide both use this pattern with complete relay code.

Zapier

Use the Catch Hook trigger. Zapier gives you a URL — paste it into Vibeworker, hit Preview alert, and Zapier picks up the sample immediately. From there, map job__title, match__scoreQuickWin, etc. to any Zapier action. Works well for Google Sheets logging or email.

Make (formerly Integromat)

Use the Custom Webhook trigger. Same flow as Zapier — paste the URL, send a preview, Make auto-detects the schema. The nested objects (job, match, client) are available as mappable fields throughout your scenario.

Raw curl (testing)

If you're building a custom receiver and want to test it locally before pointing Vibeworker at it:

curl -X POST https://your-endpoint.example.com/webhook \
  -H "Content-Type: application/json" \
  -H "X-Vibeworker-Event: job.matched" \
  -d '{
    "event": "job.matched",
    "filterName": "Test filter",
    "match": { "scoreQuickWin": 8, "scoreScopeClarity": 7, "scoreRedFlags": 9, "effortEstimateHours": 10 },
    "job": { "title": "Test job", "description": "Test description.", "url": "https://www.upwork.com/jobs/~test", "type": "fixed", "budget": { "min": 500, "max": null, "currency": "USD", "display": "$500" }, "skills": ["React"] },
    "client": { "totalSpent": 5000, "hireRate": 60, "paymentVerified": true, "location": "United States" }
  }'

Score gating

The most common customisation. Drop this check at the top of any receiver to ignore jobs below your bar before any downstream action runs:

const { match } = body;
if (match.scoreRedFlags < 7 || match.scoreQuickWin < 6) {
  return new Response('ok'); // silently discard
}

In n8n, this is an IF node between the Webhook and your action node — no code needed.


Multiple filters, multiple destinations

Each filter has its own webhook setting. Useful patterns:

  • Per-niche channels#leads-react and #leads-wordpress as separate filters pointing at separate Slack channels, each with its own score bar
  • Tiered alerts — one filter fires push notifications for high-confidence matches, a second fires a spreadsheet log for everything
  • Team routing — each team member has their own filter tuned to their skills, each pointing at a personal endpoint

The webhook channel is available on all paid plans. Get started →


Michael Watkins

Michael Watkins

Founder of Vibeworker. Helping freelancers win the Upwork game through speed and data.

Stop missing the jobs that matter

Vibeworker watches the Upwork feed and alerts you the moment a high-fit job appears — before the proposals pile up.

Start free trial →