Skip to main content
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

Every notice MUST be rendered, including notices whose code your code has never seen. Render an unknown code generically: its title and body, verbatim, styled by its severity, placed in its slot.
This is what lets Vort ship a new notice (or change a sentence) without you redeploying. Concretely:
  1. Do not switch on code to decide whether to render. Render all of them.
  2. You MAY switch on code to add an icon or a secondary action. The fallback branch MUST render generically, never drop the notice.
  3. title and body are 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, the title and the first line of body stay visible.
  4. Place by slot:
  5. Fallbacks: an on_candidate or on_requirement notice whose ref is missing or does not match anything on screen is rendered in above_list. An unknown slot value is rendered in above_list. An unknown severity value is styled as warning.
  6. Within one slot, keep the array order.
  7. Report every rendered code, known or not, in notices_shown on POST /runs/{run_id}/decisions.
  8. 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.
Severity styling (details and wireframes in the UI specification):
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.
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.
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.
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.
What it tells the recruiter: some candidates are not shown because a must requirement came back unmet for them, with the count. This is a hard product rule, not a location fact: a candidate who fails a must is never presented as a match.When it appears: the run judged candidates and at least one failed a must.
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.
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.
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.
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.
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.
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.
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.
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_blockers and requirement_attribution answer different questions about the same requirements. requirement_blockers counts are independent (a candidate who failed three musts is counted under all three), so they do not add up. requirement_attribution counts 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_relaxed and paid_fallback each describe a way the result differs from the request. Several can appear on one run. Show all of them.
  • run_progress is the notice form of the progress object. You MUST still show progress.confirmed / progress.target yourself 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.
If you ever see one of these in a 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.
Report a code once it has been rendered on screen (not merely received). Send each code at least once per run; repeats are de-duplicated. Include unknown codes. If the recruiter makes no decision, still send {"acting_user_external_id": "...", "decisions": [], "notices_shown": [...]}.