Announcement·

Webhooks: Stream Jobven Jobs Into Your Stack

Subscribe to job lifecycle events and react in real time instead of polling. HMAC-signed, retried on failure, gated on a verified test event.

If you're a Jobven customer today, you're probably running a cron that hits GET /v1/public/jobs?postedAfter={lastSync} every few minutes. It works, and for batch refresh it's fine, but it has two failure modes you keep paying for:

  1. Latency-vs-load tradeoff. Poll every minute, you waste budget. Poll every hour, you miss a third of the day's listings.
  2. Empty-poll tax. Most of those requests come back unchanged. You're paying quota for "no, still nothing new since 14:32."

Webhooks are now live. Subscribe to job.created, job.updated, job.closed, and job.deleted, and we POST the event to your HTTPS endpoint when it happens. No more empty polls, no more "did we miss any during the maintenance window?" anxiety.

Available on Starter, Growth, Professional, and Custom plans. The full reference is at Webhooks documentation. This post covers the why and the watch-outs.

How it works in 60 seconds

You create a subscription in the dashboard with a URL, a list of event types, and an optional filter (any subset of the Pull API filter shape: country, employment type, salary range, and so on). We hand you a signing secret exactly once. When a matching event fires, we POST a JSON envelope to your endpoint with Jobven-Signature and Jobven-Event-Id headers.

{
  "id": "8e3f5c44-1cd1-4a40-bb4f-9d4f95c54c1d",
  "type": "job.created",
  "createdAt": 1715520000,
  "subscriptionId": "7c2f8f7a-d8ab-4d4a-9a09-71b4e6dffb8a",
  "deliveryAttempt": 1,
  "data": {
    "job": { "id": "...", "title": "Senior Backend Engineer", "company": { "...": "..." } }
  }
}

Verify the signature with the secret, dedupe on Jobven-Event-Id, and you're done. Here's the TypeScript verifier (the docs carry Python and Go too):

import crypto from 'node:crypto'

export function verifyJobvenWebhook(rawBody: string, header: string, secret: string) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')))
  const t = Number(parts.t)
  if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false

  const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
  const a = Buffer.from(expected, 'hex')
  const b = Buffer.from(parts.v1, 'hex')
  return a.length === b.length && crypto.timingSafeEqual(a, b)
}

Replay window is 5 minutes (t drift over 300s rejects). Always HMAC the raw bytes. JSON re-serialization changes whitespace and breaks the comparison.

What you can build

Webhooks are the bridge between Jobven's job data and your specific workflow. A few shapes we've seen in beta:

  • Job alerts in Slack or email. job.created fires the alert, your filter narrows to the roles your users care about. No polling, no missed mornings.
  • Inventory sync for job boards. job.created inserts, job.updated patches, job.closed flips the listing inactive, job.deleted removes it. Your store stays accurate to the minute without you owning the scraping.
  • ATS or recruiter CRM ingest. Match incoming roles against your client briefs in real time. Score and route before the listing has been live for an hour.
  • Search index warming. job.created writes to your ES/Typesense index immediately so the role is findable before the next batch refresh.
  • LLM enrichment pipelines. job.updated events make it cheap to keep embeddings, summaries, or labels current as descriptions change.

The shared property is react vs poll. If your product cares about being fresh (alerts, marketplaces, agent inboxes), webhooks save you both latency and quota.

The verification gate

This is the part worth highlighting because it's deliberately non-standard.

When you create a subscription, it lands in a status called pending_verification. It is not in the dispatch pool. No events flow to your endpoint until you hit Send test from the dashboard and your endpoint returns a 2xx response. Then, and only then, the subscription flips to active and starts receiving real events.

We took this stance on purpose. Common webhook implementations all default new subscriptions to active immediately. That works for low-rate event sources. Jobven isn't one. A broad filter against our crawler can blast hundreds of job.created events through your endpoint within a minute of save. If you saved the subscription before deploying the handler, that's a flood at an endpoint returning 502s and burning quota on retries.

The gate applies on every reactivation. If you pause and re-enable a subscription, it returns to pending_verification first. If we auto-disable it after a sustained failure streak and you hit Re-enable, same thing, plus we hand you a Pull-API backfill curl scoped to the disable window. You can backfill the gap and resume live delivery from a verified, healthy endpoint.

The cost is one extra click. The benefit is that "I shipped the dashboard config before the endpoint was ready" never breaks anything.

At-least-once, with backoff

Webhook delivery is at-least-once. Persist Jobven-Event-Id for each event you've processed and skip duplicates. The header stays the same UUID across retries of the same event.

Failed deliveries (non-2xx, network timeout, or 429) retry on this schedule:

  • Attempt 2 at 30 seconds
  • Attempt 3 at 2 minutes
  • Attempt 4 at 10 minutes
  • Attempt 5 at 30 minutes

After the fifth failure we stop trying for that specific event. 4xx responses other than 429 (think 400, 404, 410, 422) are treated as permanent. Fix your endpoint, don't ignore them.

Past a sustained failure pattern (50 consecutive failures or 24 hours with no successful delivery), Jobven auto-disables the subscription. The dashboard surfaces a banner, you fix the endpoint, hit Re-enable, send a test, and you're back in business with a backfill recipe for the gap.

Quota and pricing

Update, September 2026: plans are now measured in jobs delivered rather than API calls. A successful job.created or job.updated delivery counts one job; job.closed and job.deleted are free and keep flowing even when you are over your limit. The paragraphs below describe the original launch rule and are kept as written. See the changelog and Webhooks documentation for the current rule.

Successful webhook deliveries count toward your plan's monthly API call allowance, same as a Pull API request. Test events do not count. Failed deliveries do not count. You're only billed for value delivered.

There's no per-subscription rental fee. You pay for events you actually received successfully, on the same per-call quota that backs the rest of the API.

What's next

Open the dashboard, create a subscription, send a test, and stop polling. The Webhooks reference has the full lifecycle table, verifier recipes in three languages, the event payload schemas, and the filter semantics.

If you have a use case we haven't covered above, or if you want a Zapier / n8n / Make.com bridge before we ship one, tell me. I'm the one who reads the inbox.