> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vort-sourcing.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Certification fixtures

> Synthetic cert-* jobs that return fixed, deterministic payloads for building and certifying your screens.

Production keys are issued only after every [checklist](/certification) item passes in the sandbox. This page lists what Vort provides for that, and the fixtures you build and test against. RFC 2119 keywords apply.

## What Vort provides

* A sandbox partner key and a sandbox customer organization with credits.
* An activation code for that organization, plus an expired one and an already-redeemed one.
* **Synthetic jobs** whose runs return a fixed, known payload (the fixtures below).
* A requirements set that triggers every rejection code and every warning code (see [Requirement validation examples](/sandbox#requirement-validation-examples)).
* A signed test webhook for each event, and one webhook with a **bad signature** (see [Test webhooks](/sandbox#test-webhooks)).

## How fixtures work

A `POST /runs` whose `job_external_id` starts with `cert-` never runs the engine. It returns immediately with a deterministic payload you can build and test against. You do not have to create the job first (`POST /jobs` is optional for fixtures), and the `cert-` prefix is reserved in the sandbox: do not use it for your own jobs there.

<CodeGroup>
  ```bash curl theme={null}
  curl -sS -X POST "$VORT_BASE/runs" \
    -H "x-partner-key: $VORT_PARTNER_KEY" \
    -H "x-vort-org: $VORT_ORG" \
    -H "Content-Type: application/json" \
    -d '{"job_external_id":"cert-notices-all","acting_user_external_id":"u-88121","target_count":10}'
  ```

  ```javascript Node.js theme={null}
  const res = await fetch(`${process.env.VORT_BASE}/runs`, {
    method: "POST",
    headers: {
      "x-partner-key": process.env.VORT_PARTNER_KEY,
      "x-vort-org": orgToken, // from your server-side store
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      job_external_id: "cert-notices-all",
      acting_user_external_id: "u-88121",
      target_count: 10,
    }),
  });
  const { run_id } = await res.json();
  ```

  ```python Python theme={null}
  import os
  import requests

  res = requests.post(
      f"{os.environ['VORT_BASE']}/runs",
      headers={"x-partner-key": os.environ["VORT_PARTNER_KEY"], "x-vort-org": org_token},
      json={"job_external_id": "cert-notices-all", "acting_user_external_id": "u-88121", "target_count": 10},
      timeout=20,
  )
  run_id = res.json()["run_id"]
  ```

  ```php PHP (Laravel) theme={null}
  use Illuminate\Support\Facades\Http;

  $res = Http::withHeaders([
          'x-partner-key' => config('services.vort.partner_key'),
          'x-vort-org'    => decrypt($tenant->vort_org_token),
      ])
      ->acceptJson()
      ->post(config('services.vort.base') . '/runs', [
          'job_external_id' => 'cert-notices-all',
          'acting_user_external_id' => 'u-88121',
          'target_count' => 10,
      ]);
  $runId = $res->json('run_id');
  ```
</CodeGroup>

```http Response theme={null}
HTTP/1.1 202 Accepted
x-vort-environment: sandbox

{"run_id":"5b8d3c2a-1e4f-4a6b-9c7d-2e1f0a9b8c7d","status":"running","warnings":[],"requirements":[{"index":0,"text":"Kubernetes in production","kind":"must","origin":"partner"},{"index":1,"text":"Team leadership experience","kind":"must","origin":"partner"},{"index":2,"text":"Terraform","kind":"nice","origin":"partner"}],"sandbox":{"fixture":"cert-notices-all"}}
```

What still applies to a fixture run: the acting user must be registered (`404 user_not_found`), `target_count` must be 1 to 20, and any `requirements` you send are validated exactly as for a real run (so a fixture is a free place to test [validation](/sandbox#requirement-validation-examples)); the fixture's own payload always uses its fixed requirement list, shown above. Then use the `run_id` like any other: `GET /runs/{run_id}`, reveal, decisions and `notices_shown` all work.

* Fixture candidates have synthetic ids (`990000000001`, `990000000002`, …) and obviously fake names (`Test Candidate 1`, or `מועמד בדיקה 1` with `x-vort-lang: he`).
* A fixture never lists more candidates than its `target_count`.
* Fixture responses carry `"sandbox": {"fixture": "<name>"}`.
* Notice `title` and `body` in fixtures are produced by the same code that writes them for real runs, in the language you request.
* An unknown `cert-*` name answers `422 unknown_fixture` with the valid names in `fixtures`.
* Fixture runs do not count toward the sandbox's daily run quota.

## The fixtures

<AccordionGroup>
  <Accordion title="cert-notices-all" icon="list-checks">
    **`GET /runs/{run_id}` returns:** `completed`, up to 6 candidates with per-requirement `met` (`true`, `false`, `null`) and `evidence` (including `null`), and every notice code that a partner run can produce (9 of the 13), each in its catalogue slot: `function_error`, `run_progress`, `location_relaxed`, `must_unmet_hidden`, `paid_fallback`, `already_shown`, `requirement_blockers` (on its requirement, `ref.requirement_index`), `requirement_attribution`, `run_funnel`. All three severities appear. The other 4 codes cannot fire in v1 (see the [notices catalogue](/notices#the-catalogue)); your generic renderer covers them.

    **You MUST verify:** every notice renders in its slot with its severity styling, `title` and `body` verbatim; `warning` and `blocking` have no dismiss control (C-09). Candidate cards: verdict label, one row per requirement in `index` order, evidence verbatim, the fixed label for `met: null` (C-12).
  </Accordion>

  <Accordion title="cert-notice-unknown" icon="circle-help">
    **`GET /runs/{run_id}` returns:** `completed`, up to 3 candidates, and notices with the code `zz_certification_probe`: one per slot (`above_list`, `on_candidate` with `ref.candidate_id`, `on_requirement` with `ref.requirement_index`, `empty_state`) and severity (`blocking`, `warning`, `info`), plus one with the unknown slot `zz_unknown_slot` and one with the unknown severity `zz_unknown_severity`.

    **You MUST verify:** each probe renders generically from `title` + `body`; the unknown slot renders in `above_list`; the unknown severity renders as `warning`; nothing crashes, nothing is dropped (C-10). Report `zz_certification_probe` in `notices_shown` (C-16).
  </Accordion>

  <Accordion title="cert-empty" icon="inbox">
    **`GET /runs/{run_id}` returns:** `completed`, zero candidates, `empty_state` notices only (`run_progress`, `location_relaxed`).

    **You MUST verify:** the `empty_state` notices replace the list; no "0 results" text of your own (C-11).
  </Accordion>

  <Accordion title="cert-failed" icon="circle-x">
    **`GET /runs/{run_id}` returns:** `failed`, zero candidates, one `function_error` notice (`blocking`, `empty_state`).

    **You MUST verify:** the progress indicator stops; the notice and the `run_id` are shown (C-07, C-11).
  </Accordion>

  <Accordion title="cert-slow" icon="hourglass">
    **`GET /runs/{run_id}` returns:** `running` for 3 minutes after creation, with `progress.confirmed` rising from 0 to `target_count` (and candidates appearing as they are confirmed) and a `run_progress` notice; then `completed` with all `target_count` candidates.

    **You MUST verify:** `confirmed / target` as numbers and a determinate bar that updates at least every 10 s; the final count replaces the indicator on completion (C-08).
  </Accordion>

  <Accordion title="cert-extra-fields" icon="braces">
    **`GET /runs/{run_id}` returns:** `completed`, up to 3 candidates, and unknown fields everywhere: at the top level (`zz_extra_top_level`, `zz_future_object`), in `progress`, in every notice, every candidate, and every requirement (top-level and per candidate). The `POST /runs`, reveal and decisions responses of this run carry unknown top-level fields too.

    **You MUST verify:** the whole flow works with no error and no visible change (C-17).
  </Accordion>

  <Accordion title="cert-webhook" icon="webhook">
    **`GET /runs/{run_id}` returns:** `completed` immediately, up to 3 candidates. At creation a `run_completed` webhook is queued for this run (when your webhook is registered).

    **You MUST verify:** you receive `run_completed` for this `run_id`, verify its signature, answer `2xx`, and then fetch `GET /runs/{run_id}` (C-18, C-19).
  </Accordion>
</AccordionGroup>

## Reveals and decisions on fixtures

Only candidates currently listed on the run can be revealed (on `cert-slow`, the ones confirmed so far); decisions may name any candidate the fixture will ever list. Decisions are stored like production decisions and appear on Vort's side for certification (C-15).
