Back to Indeed

How the Indeed lane works

The operator manual for the inbound Indeed channel: what happens automatically, what the numbers mean, what you control, and the switches that take it live.

The pipeline at a glance
  1. A listing goes up on Indeed — either an evergreen always-on posting per region, or a branded posting chasing one live creatorDemand row (the same demand spine Handshake uses). Posting happens through the deployed browser service; the listing record here is our operational truth.
  2. Applicants arrive and are screened instantly — the deterministic screener (no AI, same input → same verdict) runs knockouts first, then scores the rubric. Every applicant becomes a lead on the shared leads spine, deduped by email.
  3. The funnel moves on its ownpassed applicants advance to contacted and enroll in the follow-up cadence; benched applicants park on the bench; rejected stay at discovered. Nobody already further along is ever moved backwards.
  4. Messaging runs automatically— Indeed's own automation sends the welcome (touch 1); our cadence sends touches 2–3. Applicant replies are read every 5 minutes: routine questions are auto-answered by the Mastra agent, edge cases escalate into the unified Inbox as Indeed threads you can answer directly.
  5. Spend is paced, watched, and clamped— a daily loop computes each branded listing's budget, never exceeding your ceiling; a reconcile loop reads Indeed's reported actuals and auto-pauses on drift.
  6. Conversion closes the loop — signups are detected by reading prod (email match), which stops the cadence and hands the lead off.
Reading the dashboard
Applicants / Passed / Benched / Rejected
Totals across all Indeed applications, by screen verdict.
Live listings
Listings currently up (status live; wound_down ones are closed on Indeed but kept for history).
Active demand
Live creatorDemand rows — programs currently recruiting. Branded listings must chase one of these.
Applicant rows
Each shows the lead's email + funnel status, the listing it came from, the UGC score, and the verdict badge. A knockout failure shows its reason (e.g. under_18, country_not_targeted).
Seed / Clear (dev only)
Local-development buttons that fabricate a realistic sample through the REAL screener, and wipe it again. They never appear in production; real applicants arrive via the transport ingest.
The screener — exactly

Eight knockouts run first; any failure = instant reject, score 0:

  • 18 or older
  • country matches the listing's target countries (branded listings only)
  • has a 1080p-capable smartphone (any brand — iPhone not required)
  • valid email
  • OK creating content without posting on their own socials
  • understands this is paid work
  • can commit monthly
  • consents to contact

Survivors are scored on a 105-point rubric— experience, camera comfort, editing skill, equipment setup, start availability, a sample link (+15 when present), and the "why" blurb (0/4/8) — normalized to the 0–100 UGC score shown on the dashboard.

Pass mark
40 for always-on listings · 55 for branded listings (a branded posting demands a stronger fit).
Bench floor
20 — scores between the floor and the pass mark go on the bench (kept, not contacted, revisitable); below 20 rejects.
Messaging — what is automated
  • Touch 1 is Indeed's own automation("message new candidates", the welcome with signup instructions) — we deliberately leave it on.
  • Touches 2–3 are ours: +2 days and +5 days after enrollment, capped at 3 total, drafted per-applicant by the Mastra agent, respecting quiet hours and a 1-message/24h floor. Only passed applicants are enrolled.
  • Replies are polled every 5 minutes.The agent classifies each one: anything answerable from our knowledge (device requirements, payment, how to sign up, "I sent my video") is auto-answered in-platform; genuine edge cases — complaints, legal topics, eligibility ambiguity, brand questions beyond the facts — escalate.
  • Escalations land in the unified Inbox as Indeed-channel threads. Reply there like any thread — the send goes back through the Indeed transport. The applicant's cadence halts the moment they reply (they are in a conversation now).
  • The agent's knowledge cannot drift: its FAQ is derived from the screener configuration itself, plus the operator-editable offer facts (Settings) and retrieval over past creator conversations. On any doubt or failure it escalates to a human — it never guesses.
  • Suppressed, opted-out, or already-converted people are never auto-answered — that gate is deterministic code, before any model runs.
Spend — human ceilings, autopiloted pacing
  • You set the ceiling; the loop never exceeds it. Daily budget = remaining quota ÷ remaining days × cost-per-apply (default $5), clamped between the $3 floor and your per-branded-posting daily ceiling. Ceilings are human-authored — the system never invents or raises one.
  • Dry funnel guard: a listing live for 2+ days with zero applicants holds its budget at the floor — spend is never scaled into a channel that isn't proving intake.
  • Reconcile every 6 hours: reported actual spend is compared to intent; a daily rate above 1.5× intent auto-pauses the listing (and zeroes its budget when live). Only a human un-pauses.
  • Indeed's account-level budget cap (CSM-set) is the hard backstop underneath all of this.
The switches — what is live right now

Everything ships dry-run by default. Real effects require these, in order:

INDEED_SERVICE_URL + INDEED_SERVICE_TOKEN
Points Convex at the deployed browser service (the thing that actually drives the Indeed employer dashboard). Until set, external ops fail with a clear "not configured" error and the crons skip cleanly.
STEEL_API_KEY + INDEED_STEEL_SESSION_CONTEXT
On the service: the Steel browser session carrying the warm Indeed employer login (a human seeds it once).
INDEED_DASHBOARD_VERIFIED
Until true, every dashboard-driving operation fails safe — flipped only after the selectors are confirmed against the live employer UI.
INDEED_MESSAGING_LIVE
Until true, the messaging lane is a full dry run: would-be auto-answers and cadence touches are recorded in the ledger, nothing is sent.
INDEED_SPEND_LIVE
Until true, the spend loop computes and records budgets but never moves a dollar. The only op that spends money sits behind BOTH this and the dashboard gate.

Per-listing kill switch: spendPaused (set automatically on drift, or by hand). The schedules: inbound poll + messaging drain every 5 min, spend pacing daily, reconcile every 6 h.

If something looks wrong
Tiles all zero
No applicants ingested yet — in dev, press Seed sample data; in prod, check the service env vars and that a listing is live.
“Indeed transport is not configured”
Expected until INDEED_SERVICE_URL/TOKEN are set on the Convex deployment.
An applicant appears twice on Indeed
They can't here — ingest is idempotent on Indeed's application id (their 60-day replay changes nothing), and people dedup by email onto one lead.
A listing stopped spending
Check spendPaused/pausedReason — reconcile likely detected drift, or the quota filled. Un-pausing is deliberately manual.