Registry entry
Zimbabwe e-Visa Application (Ordinary Single-Entry)
The Department of Immigration Zimbabwe's online e-visa application, operated at evisa.gov.zw (linked from the Department's own zimimmigration.gov.zw), covering the ordinary single-entry visa product (`zwevisa`). Opens Zimbabwe's Visa vertical (3 of 6), following the registry's prior zw/zimra Taxes and Business Formation schemas. The live portal is an Angular single-page application whose entire compiled client (including every applicant-facing field name, validator, and conditional-visibility rule) ships on a plain unauthenticated GET before any login; this schema was authored by statically re-extracting that compiled bundle's own field-configuration object rather than by rendering pages, since the portal requires an account (email-verified sign-up) to reach the wizard interactively and a prior live-render attempt crashed on an unrelated MRZ/passport-scanner WASM asset. This schema models the ordinary e-visa's own four form sections (Personal Details, Emergency Contact, Travel Information, Supporting Documents) plus the two lead screens that precede them (Planned Entry / Document Type & Nationality). It excludes: the portal's other eight product types (`zwevisa_double`, `zwevisa_multiple`, `zwevisa_kaza`, `zwevisaarr`, `zweentry`, `zweexit`, `zweprovrespermit`, `zwevisaextc`/`zwevisaextab`), each a materially different field configuration in the same bundle and out of scope per this cycle's own narrow-scoping instruction; the system-generated "Application reference" (`BatchId`/`travelName`), which the client auto-fills and immediately disables rather than collecting from the applicant; five generic, unlabelled "Extra document" upload slots and one `hidden:true` legacy document field, neither carrying independent semantic meaning; and the `Dependants`/`SpouseDetails` (as distinct steps)/`ContactDetails`/`MiscellaneousDetails`/`VisitorDetails`/`Requirements` sections, which the extracted bundle's own shared section-name enum defines but which do not appear in this product's own field-configuration object (they belong to other, more complex products such as the KAZA UniVisa). This schema does not file the application itself; the live source is always authoritative. GovSchema is independent and is not affiliated with, endorsed by, or operated by the Government of Zimbabwe or the Department of Immigration.
Registry entry
zw/immigration/evisa-application
Authoritative source e-Visa portal (evisa.gov.zw), Angular SPA compiled client `app/main.baa2096ea7e0d09e.js` (7,376,521 bytes), ordinary single-entry visa product `zwevisa`.
Machine access
- Schema document
registry/zw/immigration/evisa-application/1.0.0/schema.jsonapplication/schema+json- Verification record
registry/zw/immigration/evisa-application/1.0.0/VERIFICATION.mdtext/markdown- Registry catalog
registry/index.jsonone record per schema id
Field reference
50 fields across 5 steps, read from the published schema.json, with names, types, requiredness, and validation as the document states them. The live government form remains the authoritative source.
Planned Entry, Document Type & Nationality
-
plannedEntrystring requiredThe source's own "travel-name" screen fetches this field's selectable options at runtime from a separate live API call, not embedded statically in the compiled client; modelled as an open string rather than a fabricated closed enum. See this schema's own verification.notes.
length: 0–200 -
passportTypeenum requiredThe 5 values confirmed with an English translation in the bundle, out of a shared 9-value PassportType enum. See this schema's own verification.notes for the 4 excluded, unconfirmed values.
enum: ordinary | diplomatic | service | refugee | marineclassification: pii -
nationalitystring requiredNationality
length: 0–100classification: pii
Personal Details
-
purposeOfVisitenum requiredSee this schema's own verification.notes Finding 6 for the disclosed inclusion of live_here ("Long-term Resident").
enum: 9 values -
invitingCompanyNamestring optionalInviting company name
length: 0–50 -
otherPurposestring optionalOther purpose (please specify)
length: 0–50 -
durationOfStayDaysinteger optionalSee this schema's own verification.notes Finding 7. Required unless purposeOfVisit is live_here.
range: 1–90 -
lastNamestring optionalSee this schema's own verification.notes Finding 2 for the disclosed absence of a required validator on this field in the source.
patternclassification: pii -
firstNamestring optionalSee this schema's own verification.notes Finding 2 for the disclosed absence of a required validator on this field in the source.
patternclassification: pii -
otherNamestring optionalOther name
patternclassification: pii -
dateOfBirthdate requiredThe source's own client-side rule also requires this date to be no more than 125 years in the past and on or before dateOfIssue — the latter is modelled as a crossFieldValidation rule; the 125-year bound is a plausibility ceiling rather than a value comparison and is not separately encoded.
classification: sensitive-pii -
placeOfBirthCountrystring requiredCountry of birth
length: 0–100classification: pii -
placeOfBirthCitystring requiredCity of birth
length: 0–150classification: pii -
genderenum requiredSee this schema's own verification.notes Finding 5 for the source's exact lower-case wire values.
enum: male | femaleclassification: sensitive-pii -
maritalStatusenum requiredSee this schema's own verification.notes Finding 5 for the source's exact lower-case wire values.
enum: single | married | separated | divorced | widowed -
emailstring requiredEmail
length: 0–200classification: pii -
phonestring requiredPhone number
patternclassification: pii -
occupationstring optionalOccupation
length: 0–50 -
homeAddressstring optionalHome address
length: 0–300classification: pii -
hostNamestring optionalHost name
length: 0–150classification: pii -
addressInZimbabwestring optionalAddress in Zimbabwe
length: 0–300classification: pii -
hasSpouseboolean optionalTravelling with spouse
-
spouseFullNamestring optionalSpouse's full name
patternclassification: pii -
spousePassportNumberstring optionalVisible only when hasSpouse is true, but the source's own configuration carries no required validator even then — modelled as unconditionally optional per the confirmed source, not requiredWhen-gated.
length: 0–50classification: sensitive-pii -
spouseDateOfBirthdate optionalSpouse's date of birth
classification: sensitive-pii -
spousePlaceOfBirthstring optionalSpouse's place of birth
length: 0–150classification: pii -
fundsAvailablenumber requiredFunds available at time of entry
range: 0–∞ -
fundsAvailableCurrencyenum requiredSee this schema's own verification.notes Finding 5 for the source's exact wire values.
enum: USD | EUR | GBP
Emergency Contact
-
emergencyContactLastNamestring optionalEmergency contact — last name
patternlength: 0–50classification: pii -
emergencyContactFirstNamestring optionalEmergency contact — first name
patternlength: 0–50classification: pii -
emergencyContactEmailstring optionalEmergency contact — email
patternlength: 0–100classification: pii -
emergencyContactPhonestring optionalEmergency contact — phone
patternlength: 0–20classification: pii
Travel Information
-
modeOfTravelenum requiredSee this schema's own verification.notes Finding 5 for the source's exact lower-case wire values.
enum: flight | ship | car | bus | train -
flightNumberstring optionalFlight number
pattern -
shipNumberstring optionalShip number
pattern -
carNumberstring optionalCar registration number
pattern -
busNumberstring optionalBus number
pattern -
trainNumberstring optionalTrain number
pattern -
passportCountrystring requiredCountry issuing passport
length: 0–100classification: pii -
passportNumberstring requiredPassport number
patternclassification: sensitive-pii -
dateOfIssuedate requiredPassport date of issue
classification: sensitive-pii -
dateOfExpirydate requiredSee this schema's own verification.notes Finding 8: the source's own client also requires this date to remain valid at least 6 months beyond arrivalDate, a duration-offset rule not expressible via this spec's direct field-to-field crossFieldValidation comparison.
classification: sensitive-pii -
placeOfIssuestring optionalPlace of issue
length: 0–150classification: pii -
arrivalDatedate requiredSee this schema's own verification.notes Finding 8 for the source's own additional duration-offset rule relative to dateOfExpiry, not separately encoded.
-
numberOfCompanionsinteger optionalNumber of travel companions
range: 0–100 -
departureDatedate requiredDeparture date
-
hasPreviousConvictionsZimbabweboolean requiredPrevious conviction(s) in Zimbabwe
-
previousConvictionsZimbabweDetailsstring optionalDetails of previous conviction(s) in Zimbabwe
-
hasPreviousConvictionsHomeCountryboolean requiredPrevious conviction(s) in home country
-
previousConvictionsHomeCountryDetailsstring optionalDetails of previous conviction(s) in home country
Verification record
Candidate selection
GOV-4481 (child of GOV-4476, "GovSchema Standard Research"). Opens Zimbabwe's Visa vertical (3 of 6), following the zw/zimra Taxes (GOV-4470) and Business Formation (GOV-4478) schemas.
Reaching the live source
The issue delegating this work disclosed that evisa.gov.zw's field schema is not behind login: the entire compiled Angular client ships on a plain unauthenticated GET before any auth. Independently re-fetched fresh rather than trusting the delegating issue's own disclosed hash: https://www.evisa.gov.zw/app/main.baa2096ea7e0d09e.js, HTTP 200, Content-Type JavaScript, 7,376,521 bytes — byte-for-byte matching the delegating issue's own disclosed size, confirming the specimen is unchanged. https://www.evisa.gov.zw/app/index.html#/start returns HTTP 200, 50,568 bytes, and redirects an unauthenticated visitor to #/sign-in (confirmed via a real Playwright/Chromium session, realistic desktop UA, LD_LIBRARY_PATH/FONTCONFIG_FILE sandboxed-launch fix applied per this registry's own established recipe). The sign-in screen's own "No account yet?" link reaches a sign-up form requiring e-mail verification to proceed — not completable without a real inbox, and not attempted, since GovSchema does not create accounts on government portals it documents. This confirms, first-hand, the delegating issue's own caution that live-browser rendering of the actual multi-step wizard is not the reliable path for this specimen (the issue additionally reported a prior SIGABRT crash on an unrelated MRZ/passport-scanner WASM asset); all field-level modelling below is instead drawn from static re-extraction of the compiled bundle's own source code, which is authoritative for what the client actually submits regardless of account access.
Extraction method
The bundle is minified but not obfuscated: every Angular reactive-form field configuration survives as a literal JavaScript object (e.g. {name:e.Wd.PURPOSE_OF_VISIT,type:"select",validators:[n.kI.required],...}), and the field-name enum (Wd) and section-name enum (mP) both survive as literal U.SOME_KEY="someValue" assignment chains. Located and bracket-matched (respecting string/escape state) four distinct product field-configuration objects, each keyed by section name ([e.mP.PERSONAL_DETAILS], etc.); the one beginning with PERSONAL_DETAILS+EMERGENCY_CONTACT+TRAVEL_INFORMATION+DOCUMENT sections and containing passport issue/expiry dates, arrival/departure dates, and funds-available fields is the one modelled here as the ordinary zwevisa product — distinguished from a second, adjacent configuration (personal details + travel information with vehicle/mode-of-travel numbers, an existing-entry-reference field, and a residence-permit-number field, but no advance passport-issue/expiry or arrival/departure dates) that is far more plausibly the physical border-crossing zweentry form, and from a third (attestant/extension-reason fields) that is plainly one of the zwevisaextc/zwevisaextab extension forms. Cross-referenced every field's translation key (form.*, 241 keys confirmed, matching the delegating issue's own disclosed count) against the bundle's own embedded, per-language translation object literals (no separate assets/i18n/*.json file exists; translations are inlined directly in main.js) to recover human-readable labels, taking the first English-language occurrence per key after confirming several samples resolved to genuine English text rather than a stray cross-reference.
The applicant's document-type (passportType) and nationality are set on a separate, shared "passport-type" screen (component class confirmed by name) reused across every product, not part of the four-section field-configuration object; its selectable document types are a subset of a shared PassportType enum (ordinary, diplomatic, marine, service, laissez-passer, identity-card, resident-permit, refugee, permanent-resident-permit) which are exposed to the applicant, only 5 of which (ordinary, diplomatic, service, refugee, marine) carry a confirmed English translation anywhere in the bundle — the remaining 4 (identity-card, resident-permit, permanent-resident-permit, laissez-passer) have no translation and no other reference in the bundle, and are excluded here as unconfirmed for this product rather than fabricated. Similarly, the applicant's planned port of entry (plannedEntry) is set on a dedicated "travel-name" screen whose own component code fetches its selectable options at runtime from a separate live API call (this.api.schema("zweentry"), reading properties.ProvisionnalEntryPort.enum) rather than embedding them statically in this bundle; that live endpoint was not called (it plausibly requires the same account session as the wizard itself, and calling an unfamiliar authenticated-looking endpoint speculatively was judged out of scope for a static bundle re-extraction), so plannedEntry is modelled as an open string rather than a fabricated closed enum.
Disclosed findings
- The "Application reference" field (
BatchId/travelName, called out in the delegating issue's own field list) is excluded fromfields[]entirely. Its own component code (found and read in full) shows it is not applicant-supplied:this.form.controls.travelName.patchValue(this.cart.currentApplication.travelName||this.cart.getUniqueReference(this.existingTravelNames))immediately followed bythis.form.controls.travelName.disable()— the client itself generates a unique reference and disables the control before the applicant ever sees it. It carries aValidators.requiredonly because the system always supplies a value, not because a human must type one; modelled here the same way this registry excludes other system/office-assigned identifiers (e.g. ZIMRA's own pre-issuance office box). lastName,firstName, andotherNameare modelledrequired: false, matching the source's own configuration exactly, despite this being surprising for a visa applicant's own name. The extracted field objects for these three carry only a name-shapepatternvalidator (^[A-Za-z\s\-]+$) and noValidators.required— confirmed by direct, repeated reading of the raw configuration text, not a parsing artifact. The most plausible explanation (not itself confirmed, disclosed as inference only) is that these fields are ordinarily auto-populated from the passport-scan upload's OCR/MRZ pipeline earlier in the same product family, making a client-side required check redundant in the reference implementation; this schema models the confirmed validator set as-is rather than adding a required flag the source does not carry.- No field in the Supporting Documents section carries a
Validators.required(or anyvalidatorsarray at all) in the extracted configuration, unlike every other section, where required fields are explicit. All 14 modelleddocuments[]entries are thereforerequired: false, disclosing this as a genuine, confirmed absence rather than an assumption; the government's own officer-review workflow (found separately in the same bundle) manually inspects and can reject an application short on supporting evidence, rather than the client blocking submission. - Five generic "Extra document" upload slots (
ExtraDocument1–ExtraDocument5) and one further upload field explicitly markedhidden: truein its own source configuration (PreviousVisa) are excluded fromdocuments[]. The five extra slots carry no semantic label distinguishing one from another (each only progressively reveals the next viaifFormControlHasValuechaining) and the sixth is explicitly hidden from the applicant by the source's own flag; none represents a distinct, nameable document requirement. gender,maritalStatus,fundsAvailableCurrency,passportType, andmodeOfTravelenum values are modelled using the exact lower-case (and, forpassportType, hyphenated) string literals the compiled client itself submits (e.g."male","married","USD","ordinary","flight"), rather than this registry's more common upper-cased convention for enums inferred from a printed paper form — because these values were read directly from the live client's own JavaScript enum definitions, not inferred from rendered text, source fidelity is best served by preserving the exact wire values.purposeOfVisit's 9-value enum (business_visa,holiday_visa,conferencing_visa,transit_visa,student_visa,sports_visa,arts_visa,live_here,other_visa) includeslive_here("Long-term Resident"), an option that reads oddly for an advance single-entry tourist/business e-visa product. Modelled as-is because it is the confirmed, complete set of values referenced by this exact product's own field-configuration object (durationOfStayDays's ownrequiredWhenexplicitly exempts this value), not a value borrowed from a different product.durationOfStayDaysisrequiredWhenthe applicant's purpose is anything other thanlive_here({"not":{"field":"purposeOfVisit","equals":"live_here"}}), matching the source's ownifFormControlHasNotValuecondition exactly.- The source's own relative-date rules that require date arithmetic beyond simple field-to-field comparison (e.g. a passport must remain valid at least 6 months beyond the arrival date; the applicant must be at least old enough that their passport's issue date follows their birth date) are disclosed in the relevant fields' own
description, not encoded ascrossFieldValidation, since GSP-0013'sfieldComparegrammar supports only direct value comparison between two fields, not comparison against another field plus a duration offset. The two relationships that do map cleanly to direct comparison (dateOfIssueon/afterdateOfBirth;departureDateon/afterarrivalDate) are modelled ascrossFieldValidationrules.
Conformance
3 valid mock scenarios — valid-holiday-single-applicant (an unmarried holiday visitor travelling by air, no spouse/companions/prior convictions); valid-business-visa-with-spouse-and-convictions-disclosed (a married business applicant travelling with their spouse, declaring a disclosed prior conviction in Zimbabwe, funds in EUR); and valid-long-term-resident-by-road (a live_here applicant entering by car, exercising carNumber and the durationOfStayDays exemption) — plus mutation-control fixtures (one missing-required-field fixture for each statically required field, an invalid-enum fixture, and an unknown-field-rejected fixture), committed under conformance/zw/immigration/evisa-application/1.0.0/. An ephemeral, from-scratch conformance checker (deriving required/requiredWhen rules directly from this schema's own fields[], discarded after use, not committed) ran all fixtures: all 3 valid scenarios at 0 errors, all mutation controls each raising exactly 1 error, and the unknown-field fixture correctly rejected. Validated clean with node tools/validate.mjs and node tools/validate-ajv.mjs, individually and as part of the full registry run. registry-index.json regenerated via npm run build-index in tools/govschema-client/.
View the raw record (VERIFICATION.md)
Version history
-
1.0.0draftlatestthis pagehas verification recordschema.json
Independent and non-affiliated
GovSchema is an independent, open-source project. This reference is not produced, reviewed, or endorsed by Department of Immigration or any government. The authoritative source is always the live government form and its official instructions.