notices[] in GET /runs/{run_id} is contractual. It is how Vort tells the recruiter what a run actually did: where it widened, where it narrowed, what cost the most candidates, why a list is short or empty, and whether it is still working.
Vort’s product rule behind it: nothing is ever filtered invisibly. A run that widened past the requested location, or narrowed a query, and does not say so, is a false result the recruiter would pass on to a client. Your UI is the only place the recruiter can read these sentences, so rendering them is part of the integration, not decoration.
RFC 2119 keywords apply.
The generic-rendering rule
This is what lets Vort ship a new notice (or change a sentence) without you redeploying. Concretely:-
Do not switch on
codeto decide whether to render. Render all of them. -
You MAY switch on
codeto add an icon or a secondary action. The fallback branch MUST render generically, never drop the notice. -
titleandbodyare Vort’s text in the request language. Render them verbatim. Do not truncate, rewrite, translate or template them. If the text is long, wrap it; if you must collapse it, thetitleand the first line ofbodystay visible. -
Place by
slot: -
Fallbacks: an
on_candidateoron_requirementnotice whoserefis missing or does not match anything on screen is rendered inabove_list. An unknownslotvalue is rendered inabove_list. An unknownseverityvalue is styled aswarning. - Within one slot, keep the array order.
-
Report every rendered code, known or not, in
notices_shownonPOST /runs/{run_id}/decisions. - Notices can appear, change or disappear between polls while a run is running. Re-render from the latest response each time; do not keep stale notices.
Certification sends a run with an invented code (
zz_certification_probe) in every slot and severity. It must render generically. See Certification fixtures.The catalogue
Thirteen codes are stable in v1. They will not be renamed. New codes may be added at any time (additive change). Each code carries Vort’s own sentence; the descriptions below tell you what the recruiter is being told, so you can test and support it. The example texts are illustrative; render what the API sends.Severity and slot are per instance. The values below are Vort’s current reading; the value in the payload always wins. A code may arrive with a different severity or slot from run to run (for example
run_progress is info while running and warning when a run stopped on its ceiling). Never hard-code severity or slot by code.
Fires in v1. Four codes (
relaxation_ladder, global_relaxed, lean_search_failed, widen_hint) belong to search lanes or screen state that the Partner API v1 path does not use, so they never fire today. They stay in the vocabulary so a future lane can emit them without a contract change; your generic renderer covers them either way.
function_error
function_error
What it tells the recruiter: a server-side failure turned into an instruction the recruiter can act on: for example the run has no requirements (add one and rerun), the job has no title, the run was not found, no permission, or a credits refusal. Never a raw technical error.When it appears: a run or one of its steps failed. Often accompanies
status: failed.run_progress
run_progress
What it tells the recruiter: whether the run is still working, finished, or stopped on its per-run ceiling. For an empty list it separates “nobody matched” from “the run stopped before it looked at everyone”, with how many were checked out of how many ranked.When it appears: while running; on completion when the run stopped on its ceiling.
location_relaxed
location_relaxed
What it tells the recruiter: not enough candidates were found in the requested location (named when known), so candidates from outside that area are included.When it appears: the run could not fill its target inside the location and widened past it.
paid_fallback
paid_fallback
What it tells the recruiter: Vort’s own pool returned no candidates, so the search was widened beyond it, and exactly how the widened search was narrower than the recruiter’s spec (limited to one title, and/or required a keyword), when it was.When it appears: last resort when the pool returned zero. The text never names where candidates came from.
already_shown
already_shown
What it tells the recruiter: this job remembers who it already showed the recruiter. One of three facts: N candidates already shown by an earlier run were left out; or every candidate found had been shown before, so they are shown again rather than returning an empty page (nothing was removed); or the run repeated earlier candidates on request.When it appears: a repeat run on the same job.
relaxation_ladder (does not fire in v1)
relaxation_ladder (does not fire in v1)
What it tells the recruiter: the filters search ran out of time on the full query, so a simpler query was served instead, and which parts were not applied (free text, candidates without a known location, skills). One step can instead narrow a nationwide query to the job’s own location; the sentence says so.When it appears: filters-lane searches that timed out and fell back.
global_relaxed (does not fire in v1)
global_relaxed (does not fire in v1)
What it tells the recruiter: for searches outside Israel: which filters were opened because the market was too small, which stricter steps were skipped, how many candidates came from Vort’s accumulated pool, or that a per-run or monthly cap on the search was reached.When it appears: international (“abroad”) runs whose strict search was widened or capped.
lean_search_failed (does not fire in v1)
lean_search_failed (does not fire in v1)
What it tells the recruiter: the search could not produce a result: either it took too long even after every fallback (suggests narrowing and one retry) or it failed to load (suggests a retry). It never presents this as “0 candidates”.When it appears: every fallback timed out, or the search errored.
widen_hint (does not fire in v1)
widen_hint (does not fire in v1)
What it tells the recruiter: the candidate pool for this search is thin, and which of the optional filters actually set would widen it, ordered by how many more candidates removing each one would bring. A filter whose removal gains nothing is not named.When it appears: the pool behind the search is small. Before the gains are measured the sentence lists what is set without ranking it.
requirement_blockers
requirement_blockers
What it tells the recruiter: for each must requirement, how many screened candidates did not meet it, and one sentence naming the must that costs the most.When it appears: the run has must requirements and has screened out candidates, typically when the list is shorter than the target.
requirement_attribution
requirement_attribution
What it tells the recruiter: for each requirement, how many candidates were rejected because of it (the first requirement that blocked each person; each candidate counted once). A zero is stated only when proven; otherwise the count is reported as unknown.When it appears: the run has rejected candidates at the must-have check.
run_funnel
run_funnel
What it tells the recruiter: the run’s funnel from Vort’s whole pool (stated as a fixed round figure, never a measured count) to candidates pulled for the search, screened, surviving, and meeting every must. Each stage is a subset of the previous one. No percentages.When it appears: runs with a census of screened candidates, typically on completion.
How the codes relate
requirement_blockersandrequirement_attributionanswer different questions about the same requirements.requirement_blockerscounts are independent (a candidate who failed three musts is counted under all three), so they do not add up.requirement_attributioncounts each rejected candidate once, under the first requirement that blocked them, so they do add up. Vort sends whichever applies; render each exactly as sent and never sum or combine them yourself.location_relaxed,relaxation_ladder,global_relaxedandpaid_fallbackeach describe a way the result differs from the request. Several can appear on one run. Show all of them.run_progressis the notice form of theprogressobject. You MUST still showprogress.confirmed / progress.targetyourself while running (see Screen 3); the notice adds the explanation.
What notices never contain
- Percentages. Vort’s counts describe a shortlist of a pool, not a market.
- A specific size of Vort’s database.
- The name of any data source or supplier.
- Technical error strings, codes or stack traces.
title or body, report it to Vort with the run_id; do not filter it out yourself.
Reporting what was shown
notices_shown on POST /runs/{run_id}/decisions is how Vort knows which sentences recruiters actually saw.