Base URL and credentials
The sandbox base URL ishttps://vort-partner-api.vercel.app/sandbox/v1.
Vort sends you a sandbox partner key (vpk_live_…), an activation code for a sandbox customer organization, and (on request) your webhook registration at onboarding. Keep the base URL in configuration: the production URL is different and is issued after certification.
Every sandbox response carries the header:
What is real and what is synthetic
A sandbox reveal answers
200 with the usual fields plus "sandbox": true:
candidate-<candidate_id>@sandbox.vort.invalid (the .invalid top-level domain can never receive mail) and the phone is always +97250000 followed by the last four digits of the candidate id. The same candidate always gets the same contact, so you can test that a second reveal is idempotent. After a reveal, GET /runs/{run_id} reports that candidate as contact_state: "revealed", and a candidate_revealed webhook is queued once per (run, candidate) when your webhook is registered. The sandbox never answers 202 pending or 402 insufficient_credits on a reveal; the scoping errors (run_not_found, user_not_found, candidate_not_in_run) behave exactly as in production.
Candidate names and identifiers
On runs of your own jobs, the sandbox masks direct identifiers before they leave Vort:namebecomes a stable pseudonym,Candidate XXXX(four hex digits derived from the candidate id; the same candidate always gets the same pseudonym).- Inside
evidence, the candidate’s real name (and each part of it) is replaced by the same pseudonym. - In
evidence,title,companyandlocation, any e-mail address, URL (including profile, LinkedIn and photo links) and phone number is replaced by[email hidden in sandbox],[link hidden in sandbox]or[phone hidden in sandbox].
met and evidence, notices. That is what you are demoing.
Real names are shown only after the Data Processing Annex is signed, when Vort turns them on for your partner account. Contact identifiers stay masked in the sandbox regardless. Your UI MUST NOT depend on the name format: render
name as an opaque string.Sandbox limits
Certification fixture runs do not count toward the daily run quota. A
POST /runs refused with 422 creates nothing and does not count either.
Certification fixtures
APOST /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. The fixtures, what each returns, and what you must verify are on Certification fixtures.
Simulating errors
Add this header to any authenticated sandbox request to get the exact error a real failure of that kind returns. The request is authenticated and logged first, so it appears in Vort’s request log like a real failure.curl
422 invalid_request with the valid values in allowed. Use it for certification C-20: a GET /runs with rate_limited MUST be retried only after Retry-After; a POST /runs with rate_limit_unavailable MUST NOT be retried automatically. Simulated requests count toward your per-minute rate limit like any other request.
Reveal price override
GET /runs/{run_id}, an integer from 0 to 1000 replaces reveal_price_credits on every candidate of that response, for that request only. Use it to prove your UI shows the price from the payload and never a stored or hard-coded value (C-13). A reveal still charges 0. Anything that is not an integer 0 to 1000 answers 422 invalid_request.
Test webhooks
curl
string
required
run_completed | run_failed | candidate_revealedboolean
default:"true"
true (default) | false202 {"event_id": "<uuid>", "event": "...", "run_id": "<uuid>", "valid_signature": true}. The delivery goes out through the normal webhook queue, usually within a minute, to the URL Vort registered for you, with the envelope you would get in production (event_id equals the returned event_id). The payload is a fixture: organization_external_id is this organization’s, job_external_id is cert-webhook, run_id is a fresh id that does not exist on GET /runs (answer 2xx anyway; your handler must not depend on the run existing), run_completed carries progress, candidate_revealed carries candidate_id: 990000000001.
If no webhook is registered for your partner account, the call answers 409 webhook_not_configured. Ask Vort to register your HTTPS URL and share the signing secret out of band.
Requirement validation examples
Send these as the body ofPOST /runs to see each code. A 422 creates nothing and costs nothing. All but location_as_requirement also work on any fixture job (fixtures have no location). For location_as_requirement, first create a job of your own with "location_text": "Tel Aviv, Israel".
Rejections answer 422 requirements_rejected, with rejected[] (and warnings[]), each item carrying the requirement index, the code, message_he / message_en and suggestion_he / suggestion_en. Show the message and suggestion verbatim under the requirement at index (C-05). Warnings answer 202 with warnings[] of the same shape; the run starts (C-06).
Rejections
empty_text (index 1)
empty_text (index 1)
invalid_kind (index 0)
invalid_kind (index 0)
kind must be must or nice. A requirements value that is not an array is also invalid_kind, at index -1.too_many_musts (index 3)
too_many_musts (index 3)
At most 3 musts.On a run of your own job, the job title counts as one must (Vort adds it as the last requirement unless one of yours is the title), so three musts of your own are refused too, at the third, with the message “The job title counts as one must, so at most 2 more musts are possible (3 in total).”
duplicate (index 1)
duplicate (index 1)
Same text after trimming and case-folding, whatever the kind.
too_long (index 0)
too_long (index 0)
Over 300 characters.
location_as_requirement (index 0)
location_as_requirement (index 0)
The requirement is a place that is part of the job’s then
location_text. Needs a job of your own. First POST /jobs:POST /runs:All rejection codes in one request
All rejection codes in one request
On the job above; indexes 1
empty_text, 2 invalid_kind, 3 duplicate, 4 too_long, 5 location_as_requirement, 7 too_many_musts:Warnings (the run starts)
short_term_may_be_dropped (index 0)
short_term_may_be_dropped (index 0)
A term shorter than 3 characters.
years_band_ceiling (index 0)
years_band_ceiling (index 0)
A bounded years range that can act as a ceiling.
unverifiable_must (index 0)
unverifiable_must (index 0)
A must that profiles almost never state (salary, availability, willingness, clearance, driving licence, soft traits).
All warning codes in one request
All warning codes in one request
Indexes 0, 1, 2; valid on your own job too, where the job title makes it three musts.
202 like on a real run; the fixture’s payload still uses its fixed requirement list.
Sandbox-only codes and headers
Request headers (ignored in production):
Response header:
x-vort-environment: sandbox on every response.
Route (answers 404 not_found in production): POST /sandbox/webhooks/test.
Error codes that only the sandbox returns:
Handle them like any unknown code, by HTTP status: your production client never sees them.