Employer Posting Evidence Verifier
Pricing
Pay per usage
Employer Posting Evidence Verifier
Point-in-time evidence for supported employer-published job posts, with explicit unknowns.
Pricing
Pay per usage
Rating
0.0
(0)
Developer
Jyoti Rawat
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
9 days ago
Last modified
Categories
Share
Employer Posting Verifier — local prototype
An original, evidence-first checker for employer-published Greenhouse job-board posts. It produces a small JSON record for each link: observed board status, stated location, short exact excerpts about work model and sponsorship, source, and check time. It does not assess a candidate, recommend a job, or submit an application.
State: local prototype, tested with fictional fixtures. As of the 29 September 2026 local validation, no live source run, Apify deployment, paid customer, or revenue had been established. A public repository by itself does not establish any of those outcomes.
Try the fictional example
Python 3.9 or newer is sufficient; the runtime has no third-party dependencies. From this directory:
python3 -m employer_posting_verifier --fixture fixtures/fictional_batch.jsonpython3 -m unittest discover -s tests -v
The fixture contains five fictional cases: a published post, an ID absent from a complete board list, an incomplete board response, an inaccessible board, and conflicting source responses. All example companies and content are invented. Fixture mode makes no network requests.
The GitHub Actions workflow checks the core, Actor wrapper, and fixture CLI, and parses the Actor JSON schemas on Python 3.11 and 3.13. Those checks use fictional data and do not run live source checks.
The package also has standard Python packaging metadata in setup.cfg. An isolated editable install may be made with python3 -m pip install -e .. The module command above needs no installation.
Supported input and result
The local core API is:
from pathlib import Pathfrom employer_posting_verifier import FixtureClient, verify_batchclient = FixtureClient.from_path(Path("fixtures/fictional_batch.json"))results = verify_batch(urls, client)
verify_batch accepts 1–20 URLs. The only supported formats in v0.1 are:
https://boards.greenhouse.io/{board_token}/jobs/{numeric_post_id}https://job-boards.greenhouse.io/{board_token}/jobs/{numeric_post_id}
Custom employer domains and other applicant-tracking systems need separately reviewed adapters. Query strings, fragments, credentials in URLs, unusual ports, local addresses, and unsupported hosts are rejected before a request. Invalid inputs are identified by input_index; their original text is not echoed because it might contain secrets.
Each result has these fields:
| Field | Meaning |
|---|---|
input_index, input_url, canonical_url | Position and accepted canonical URL; rejected inputs display [rejected]. |
provider, source_job_id | Source family and stable board/post identifier. |
status, status_reason, status_source_url | Observation and its exact basis. |
title, location | Published fields or Unknown. |
work_model, sponsorship_wording | Short excerpts of explicit source wording or Unknown; no eligibility inference. |
checked_at | UTC observation time. |
error_code, duplicate_of | Stable failure reason or the first input index reused for a duplicate. |
The CLI wraps the result list with schema_version and mode.
Status semantics
- Open: the post ID appeared in a complete successful response listing currently published jobs on that board. This does not guarantee that applications are being accepted or that a candidate is eligible.
- Closed: reserved for a future check that has reliable prior evidence the same post was Open and then observes an explicit closure. v0.1 does not emit this status.
- Unknown: source evidence was incomplete, inaccessible, malformed, conflicting, represented only a general-interest prospect post, or the ID was absent from the current published-jobs list. Absence does not prove the ID was ever published.
The tool records source wording. For example, “Visa sponsorship is not available” is shown as an excerpt; the tool does not convert missing language into a yes/no sponsorship decision. Greenhouse's Job Board API documentation describes the public GET endpoint and published-job list used for this observation.
Live mode boundary
The core has an optional LiveGreenhouseClient. No live request is made by default. A future authorized run must explicitly use --live --source-rights-reviewed (or instantiate LiveGreenhouseClient(source_rights_reviewed=True)). That flag records an operator acknowledgement; it is not evidence of legal permission or an approval to collect customer data.
Live requests are restricted to boards-api.greenhouse.io. The client checks all DNS answers for public addresses, connects to a vetted IP while validating the Greenhouse TLS certificate, blocks redirects, spaces requests by at least half a second, and limits input count, time, and response size. It sends no login, cookie, or candidate data. A failed request yields Unknown; it never becomes a false Closed result. Live execution and commercial use still need a source-rights decision, reliability review, and the workspace's action-time approvals.
Public GET access is not a blanket commercial republication license. The tool keeps only short relevant excerpts in its output and does not save full job descriptions. It does not use LinkedIn-derived pilot rows, CVs, the career application tracker, Apify logs, OAuth settings, or copied third-party code. LinkedIn's User Agreement restricts scraping and commercial use of its data; that source is outside this tool.
Limits and next gates
- Only Greenhouse board posts with a numeric public post ID are supported.
- The output is an observation at
checked_at, not continuous monitoring. - Work-model and sponsorship excerpts can be missing or ambiguous. A human must read the linked employer source for consequential decisions.
- No source-rights clearance, buyer willingness to pay, Actor pricing, payout setup, hosted operation, or support promise has been established.
- A public release needs a license choice, independent staged-file review for secrets and private data, reproducible checks, and exact publication approval.
The architecture decision and rollback plan are in ARCHITECTURE_DECISION.md.
Apify Actor candidate
The same core is packaged as an Apify Actor in .actor/, apify_actor/, and Dockerfile. Its default run is the five-row fictional demonstration. Every demo row says no employer website was checked. The Actor wrapper requires Python 3.11 or newer and requirements-actor.txt; the standalone core above still works with Python 3.9 and no SDK.
For a local SDK run after installing the requirements, use python -m apify_actor. Apify's local storage appears under storage/, which is excluded from Git. Wrapper tests use a fake Actor and do not contact an account:
python -m unittest apify_actor.test_main -v
Live Actor mode requires mode=live_greenhouse, 1–20 supported URLs, a sourceRightsReviewed=true input, the owner switch ALLOW_LIVE_SOURCE_CHECKS=1, and ALLOWED_GREENHOUSE_BOARDS containing each reviewed board token. An unlisted board is rejected before any request. The Actor processes and stores one result before fetching the next, and stops when its pay-per-event budget is exhausted. Duplicate inputs reuse cached source responses.
The intended paid event is verified-result for a live Open result. First-time absence and other Unknown rows do not request that custom charge. Apify can separately bill synthetic start and dataset-item events from its Console configuration. In pay-per-event mode, the Actor requires the owner-set APIFY_DATASET_EVENT_REMOVED=1 switch and blocks a positive flat-priced dataset-item event. SDK 4.0.2 does not expose tier-priced events in that price map, so the exact Console configuration, source rights, and buyer evidence must still be reviewed before any paid deployment.