import os, requests, time, base64
from collections import defaultdict
GH_KEY = os.environ["GREENHOUSE_API_KEY"]
MV = os.environ["MAVERA_API_KEY"]
GH_BASE = "https://harvest.greenhouse.io/v1"
MV_BASE = "https://app.mavera.io/api/v1"
MV_H = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
gh_auth = base64.b64encode(f"{GH_KEY}:".encode()).decode()
GH_H = {"Authorization": f"Basic {gh_auth}"}
# 1. Pull rejection reasons
reasons = requests.get(f"{GH_BASE}/rejection_reasons", headers=GH_H).json()
reason_map = {r["id"]: r.get("name", "Unknown") for r in reasons}
# 2. Pull rejected applications
rejected_apps = []
page = 1
while len(rejected_apps) < 500:
batch = requests.get(f"{GH_BASE}/applications",
headers=GH_H,
params={"per_page": 100, "page": page, "status": "rejected"}).json()
if not batch:
break
rejected_apps.extend(batch)
page += 1
time.sleep(0.3)
# 3. Group by rejection stage and reason
stage_groups = defaultdict(list)
for app in rejected_apps:
stage = app.get("current_stage", {})
stage_name = stage.get("name", "Unknown Stage") if stage else "Unknown Stage"
reason_id = app.get("rejection_reason", {})
reason_name = "No reason given"
if reason_id and isinstance(reason_id, dict):
reason_name = reason_id.get("name", reason_map.get(reason_id.get("id"), "Unknown"))
elif reason_id and isinstance(reason_id, int):
reason_name = reason_map.get(reason_id, "Unknown")
stage_groups[stage_name].append({"reason": reason_name, "app_id": app["id"]})
# 4. Create personas per rejection stage
persona_ids = []
stage_summary = []
for stage_name, apps in stage_groups.items():
if len(apps) < 5:
continue
reason_counts = defaultdict(int)
for a in apps:
reason_counts[a["reason"]] += 1
top_reasons = sorted(reason_counts.items(), key=lambda x: -x[1])[:3]
p = requests.post(f"{MV_BASE}/personas", headers=MV_H, json={
"name": f"GH Rejected: {stage_name}",
"description": (
f"Candidate rejected at {stage_name} stage. N={len(apps)}. "
f"Top reasons: {', '.join(f'{r} ({n})' for r, n in top_reasons)}."
),
"psychographic": {
"stage_at_rejection": stage_name,
"emotional_state": "disappointed, evaluating whether to engage with brand again",
},
}).json()
persona_ids.append({"id": p["id"], "stage": stage_name, "n": len(apps)})
stage_summary.append(f"- {stage_name}: {len(apps)} rejected. Top: {top_reasons[0][0]} ({top_reasons[0][1]})")
time.sleep(0.3)
# 5. Focus Group on brand perception
fg = requests.post(f"{MV_BASE}/focus-groups", headers=MV_H, json={
"name": "Rejection Brand Impact Assessment",
"persona_ids": [p["id"] for p in persona_ids],
"questions": [
"How does being rejected at your stage affect your perception of this company as an employer?",
"Would you reapply to this company in 12 months? Would you refer a friend? Why or why not?",
{"type": "ranking", "text": "Rank these factors by how much they affect your post-rejection perception: (A) Speed of response (B) Personalization of rejection (C) Feedback provided (D) Interviewer professionalism (E) Overall process transparency"},
"What would a rejection email need to say to leave you with a positive impression?",
"Would you leave a Glassdoor review about this experience? What would it say?",
],
"context": f"Company rejection data summary:\n" + "\n".join(stage_summary),
"responses_per_persona": 3,
}).json()
# 6. Poll results
for _ in range(20):
time.sleep(5)
data = requests.get(f"{MV_BASE}/focus-groups/{fg['id']}", headers=MV_H).json()
if data.get("status") == "completed":
break
print(f"Focus Group: {fg['id']} | Personas: {len(persona_ids)}")
for resp in data.get("responses", []):
stage = next((p["stage"] for p in persona_ids if p["id"] == resp.get("persona_id")), "?")
print(f"\n[Rejected at: {stage}] {resp.get('question','')[:70]}")
print(f" → {resp.get('answer','')[:300]}")