Registry entry
Uzbekistan Electronic Visa (e-Visa) Application
The Ministry of Foreign Affairs of the Republic of Uzbekistan's Consular Department e-Visa application, served unauthenticated by the live Angular single-page application at e-visa.gov.uz. The live wizard has six steps (Country, Date, Personal information, Photo and passport, Activation, Payment). This schema models the first three data-collection steps in full: Country (citizenship, document type, visa entry type, purpose of visit — each populated from the site's own live `/api/v1/dic/*` dictionary endpoints, plus a real-time visa-free-eligibility check keyed on citizenship that this schema does not model, since a visa-free citizenship makes the application itself inapplicable), Date (arrival and departure date, gated by the same 1-to-30-day stay window and 90-day advance-booking window the live page's own JavaScript enforces), and Personal information (identity, an other-citizenship/previous-name change history, passport number and issue/expiry dates, and Uzbekistan-stay/contact details). It additionally models the two file-upload fields from the Photo and passport step as `documents[]`, and the applicant's email address from the Activation step (used to receive a digital activation code by email). The Payment step (a Click.uz-style merchant payment-gateway redirect for the USD 20/35/50 consular fee) is out of scope, as is the CAPTCHA-gated activation-code/payment-info retry flow — both are payment/session mechanics, not government-form data. The live site's own step-2+ navigation is blocked in this session by a reproducible client-side rendering bug (a persistent loading overlay that never clears after the Country step's selections are made, confirmed via a live Playwright session showing zero pending network requests while the overlay stays visible — a pure client-state bug, not a server dependency). This schema's fields, property names, and validation rules are instead sourced directly from the live production JavaScript bundle's own compiled Angular ViewEngine template output and TypeScript-compiled component logic (element attributes, `NgModel` binding expressions assigning into the component's own `form.application.*` object graph, and the exact date-formatting/masking functions the component runs before submission) — not inferred or guessed. No application was actually submitted and no fee was paid in producing this schema. Filing this application is a traveller action performed directly with the Ministry of Foreign Affairs of the Republic of Uzbekistan through e-visa.gov.uz; this schema does not file the application itself, and the live source is always authoritative. GovSchema is independent and is not affiliated with, endorsed by, or operated by the Republic of Uzbekistan or its Ministry of Foreign Affairs.
Registry entry
uz/mfa/evisa-application
Machine access
- Schema document
registry/uz/mfa/evisa-application/1.0.0/schema.jsonapplication/schema+json- Verification record
registry/uz/mfa/evisa-application/1.0.0/VERIFICATION.mdtext/markdown- Registry catalog
registry/index.jsonone record per schema id
Field reference
26 fields across 6 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.
Country
-
citizenshipstring requiredThe applicant's citizenship, selected from the live `/api/v1/dic/countries/en` dictionary (248 entries as of this session), modelled as a free-text string carrying that dictionary's numeric country ID rather than as a large enum, consistent with this registry's convention for large country pickers (see `am/mfa/evisa-application`'s `birthCountry` field). Each country entry carries a `status` code confirmed live to gate the application itself: `status 1` (44 countries, e.g. India, Algeria) genuinely requires this e-visa; `status 2` (82 countries, e.g. United States, United Kingdom, China) is visa-free for up to 30 days, and selecting one live-confirmed disables the wizard's Next button with a "Visa-free entry" notice rather than proceeding; `status 4` (9 countries, e.g. France, Georgia, Armenia) and `status 3` (1 country) use a different consular channel not modelled here. This schema targets the `status 1` (e-visa-required) pathway.
classification: pii -
documentTypeenum requiredThe type of travel document being used. The live `/api/v1/dic/documents/en` dictionary returns exactly one entry, "ORDINARY PASSPORT" (id 1), as of this session — modelled as a single-value enum on that basis, not assumed to be extensible.
enum: ORDINARY_PASSPORT -
visaTypeenum requiredThe requested visa's entry type and associated consular fee, read from the live `/api/v1/dic/visa/types/en` dictionary: id 1 "SINGLE ENTRY 20$", id 2 "DOUBLE ENTRY 35$", id 3 "MULTIPLY 50$" (a source-side spelling, i.e. Multiple Entry, USD 50 — carried here as `MULTIPLE_ENTRY`). Fee amounts independently corroborated by the site's own `en.json` translation `TERM_CONTENT_4_1`: "e-visa Visa application fee is USD 20.00 for single entry, USD 35.00 for double entry and USD 50.00 for multiple entry."
enum: SINGLE_ENTRY | DOUBLE_ENTRY | MULTIPLE_ENTRY -
purposeOfVisitenum requiredThe applicant's purpose of visit, read from the live `/api/v1/dic/purposes/en` dictionary (id 1 "TOURISM", id 2 "BUSINESS"). The site's own `en.json` (`LABEL_PURPOSE_VISIT_MESSAGE`) notes that a non-tourism purpose requires the inviting organization to separately apply to the Ministry of Foreign Affairs — a disclosed downstream process this schema does not model.
enum: TOURISM | BUSINESS
Date
-
arrivalDatedate requiredThe applicant's planned date of arrival in Uzbekistan, entered via an `ngb-datepicker` calendar in the site's own `DD.MM.YYYY` format. The component's own date-picker configuration (`minDate`/`maxDate`) restricts selection to between today and 90 days out, corroborating the site's own `en.json` note (`TERM_CONTENT_2_8`) that "the electronic visa is valid for entry ... within 90 days from the date of registration."
pattern -
departureDatedate requiredThe applicant's planned date of departure from Uzbekistan, same `DD.MM.YYYY` format as `arrivalDate`. The component's own `dateToTest.markDisabled` function (compiled bundle) disables any date more than 29 days after `arrivalDate` or before `arrivalDate` itself, matching the site's own `en.json` note that "the period of stay must not exceed 30 days" (`APPLICATION_INFO_DATERANGE_WARNING`) — the 30-day maximum-stay ceiling itself is not separately expressible as a `crossFieldValidation` operator in this spec and is disclosed here rather than silently omitted.
pattern
Personal Information
-
surnamestring requiredThe applicant's surname, matching their passport. The live input carries no explicit character-pattern or length restriction beyond being required; the component uppercases every `passportInfo`/identity string field before submission (compiled bundle, a loop over `this.form.application.passportInfo` calling `.toUpperCase()`).
classification: pii -
firstNamestring requiredThe applicant's given name(s), matching their passport.
classification: pii -
otherNamesstring optionalThe applicant's middle name or patronymic, if any. The live `` carries no `required` attribute, unlike its `applicantSurname`/`applicantName` neighbours.
classification: pii -
surnameChangedboolean optionalWhether the applicant's surname has changed from a previously used surname. When checked, reveals a required `previousSurname` field.
-
previousSurnamestring optionalThe applicant's previously used surname, required only when `surnameChanged` is checked. Confirmed live: the field's own conditional template block (`*ngIf`) only renders when `isPreviousLastName` is true, and its `` there carries a `required` attribute.
classification: pii -
nameChangedboolean optionalWhether the applicant's given name has changed from a previously used name. When checked, reveals a required `previousName` field.
-
previousNamestring optionalThe applicant's previously used given name, required only when `nameChanged` is checked, mirroring `previousSurname`'s conditional structure.
classification: pii -
sexenum requiredThe applicant's sex, a two-option radio group (`name="sex"`, `#applicantMale`/`#applicantFemale`), matching the site's own `LABEL_MALE`/`LABEL_FEMALE` translation strings.
enum: MALE | FEMALEclassification: pii -
dateOfBirthdate requiredThe applicant's date of birth, a masked text input in `DD.MM.YYYY` format (placeholder "XX.XX.XXXX", confirmed live via the component's own `birthDateMask` definition).
patternclassification: pii -
placeOfBirthstring requiredThe applicant's place of birth, free text.
classification: pii -
passportNumberstring requiredThe applicant's passport series and number, a 9-character alphanumeric field entered via a masked input (confirmed live via the component's own `passportMask` definition, nine `/(\d|[a-zA-Z])/` character slots) and uppercased before submission.
patternclassification: sensitive-pii -
passportIssueDatedate requiredThe date the applicant's passport was issued, selected via an `ngb-datepicker` calendar in `DD.MM.YYYY` format.
pattern -
passportExpiryDatedate requiredThe date the applicant's passport expires, same `DD.MM.YYYY` format as `passportIssueDate`.
pattern -
permanentResidenceAddressstring requiredThe applicant's permanent (home-country) residence address, free text.
classification: pii -
workInfostring requiredThe applicant's place of work or study, and position/role there, free text.
-
phoneNumberstring requiredThe applicant's phone number (mobile and/or land line). A live `keypress` handler restricts entry to digits only (`keysNumber = /^[0-9]*$/`, confirmed in the compiled bundle).
patternclassification: pii -
preliminaryResidenceInUzbekistanstring requiredWhere the applicant intends to stay while in Uzbekistan (e.g. hotel or host address), free text.
-
hasOtherCitizenshipboolean optionalWhether the applicant holds citizenship of a country other than the one selected in `citizenship`. When checked, reveals a required `otherCitizenship` field.
-
otherCitizenshipstring optionalThe applicant's other citizenship, required only when `hasOtherCitizenship` is checked. Selected from the same live country dictionary as `citizenship`, modelled the same way (a string carrying the dictionary's numeric country ID).
classification: pii
Activation
-
emailstring requiredThe applicant's email address, entered on the Activation step and used to receive a digital activation code (confirmed by the site's own `en.json`: `APPLICATION_LABEL_CHECK_STATUS`, "Enter the application code, received by e-mail", and `SAVED_APPLICATION_DESC`, "An email with a link to activate the receipt has been sent to your email address"). Submission from this step is additionally gated by an image CAPTCHA (compiled bundle: `ApplicationService.prototype.getCaptcha` / `sendEmail`), not modelled as a schema field, consistent with this registry's treatment of CAPTCHA gates elsewhere (see `ge/mfa/evisa-application`).
patternclassification: pii
Verification record
Candidate selection
GOV-3313 ("GovSchema Standard Research", 2026-07-16) scouted Uzbekistan's e-visa.gov.uz alongside four other candidates while looking for a new jurisdiction, and recorded it as "a real, live Angular SPA blocked by a client-side rendering bug that leaves a permanent loading overlay before any step-2+ field could be confirmed" — authoring Ethiopia instead that cycle and leaving Uzbekistan un-authored, without even a disclosed-backlog entry in CATALOG.md's "Known Gaps & Opportunities" section (unlike Georgia, which that same cycle did record and a later cycle, GOV-3321, picked up). This cycle (GOV-3368) independently rediscovered the same candidate while scouting for new jurisdictions, re-confirmed the exact rendering bug still reproduces, and worked around it by decompiling the site's own production Angular bundle directly rather than relying on live interactive navigation. Uzbekistan had no prior schema of any kind in this registry; this opens it as a new jurisdiction with one vertical (Visa).
Reaching the live source and reproducing the rendering bug
https://e-visa.gov.uz/application is live, unauthenticated, and returns HTTP 200 (confirmed via plain curl with a standard desktop Chrome User-Agent string, and via a real Playwright/Chromium session — executablePath pointed at the locally cached Chromium build at /paperclip/.cache/ms-playwright/chromium-1228/chrome-linux64/chrome, LD_LIBRARY_PATH set to the sysroot's shared libraries).
Filling the Country step's four <select> elements with a genuinely e-visa-required citizenship (India, dictionary status 1) — Citizenship, Document Type, Visa Entry Type, Purpose of Visit — correctly enables the "Next" button. Clicking it (both a normal Playwright click and a direct element.click() via page.evaluate, bypassing the overlay's hit-testing entirely) does not navigate: the URL stays at /application and no new network request fires. A .loader-wrapper overlay becomes permanently visible at this point and stays visible indefinitely (10 seconds of polling, well beyond any plausible API round trip). Separately confirmed this is a pure client-side state bug, not a slow/failed dependency: while the overlay was showing, zero HTTP requests were pending (request/requestfinished event bookkeeping across the whole session showed an empty pending set). This is the exact "client-side rendering bug" the GOV-3313 cycle's note described, independently reproduced rather than merely re-read.
Separately confirmed the visa-free branch is a distinct, intentional gate, not the same bug: selecting a status 2 (visa-free) citizenship (United States) surfaces a live "Visa-free entry for up to 30 days" banner and permanently disables the Next button — the source's own correct behavior (a visa-free traveller has no e-visa to apply for), not a defect. Switching to India (status 1) immediately re-enables the button before the separate rendering bug then blocks actual navigation.
Decompiling the production bundle: why this source is stronger than template-string extraction
https://e-visa.gov.uz/main.<hash>.bundle.js (953,309 bytes, fetched directly via curl) is compiled with Angular's older ViewEngine renderer (not the modern Ivy renderer most contemporary Angular apps ship). ViewEngine's compiled output embeds each component's template as a literal sequence of factory-function calls — critically, l"ɵeld" calls carry the element's tag name and its full static attribute array verbatim (e.g. ["class","form-control text-uppercase"],["id","applicantBirthPlace"],["required",""],["type","text"]), and each view's separate "update" function contains literal property- assignment expressions showing exactly which component-instance property an NgModel binding writes into on change — for example:
`` "ngModelChange"===t&&(r=!1!==(o.form.application.arrivalInfo.countryId=e)&&r) ``
This is a stronger source than this registry's precedent template- string extractions (am/mfa/evisa-application's AngularJS $templateCache, br/tse/requerimento-alistamento-eleitoral's Angular bundle): the exact JSON property path each field writes to (e.g. form.application.arrivalInfo.countryId, not just an element id or name attribute) is read directly from compiled code, not inferred from markup naming conventions alone. A Python regex (\\u0275eld"\]\(\d+,0,null,null,(\d+),"([a-zA-Z0-9-]+)",\[(\[.*?\])\]) extracted all 809 element definitions in file order; a second pass located each field's own ngModelChange/dateSelect handler function body immediately following its element definition and extracted the literal assignment target.
Live dictionary corroboration
Fetched all four dictionary endpoints through the real Playwright session navigated to the Country step (confirmed via the browser's own request/ response events, not a standalone curl, since the endpoints live on a separate port, e-visa.gov.uz:8443, reachable only via the app's own CORS-configured requests):
GET /api/v1/dic/countries/en— 248 entries, each{id, name, status}.statusvalues observed:1(44 countries, e.g. ALGERIA, INDIA, EGYPT, CAMBODIA, ECUADOR — genuinely require this e-visa),2(82 countries, e.g. UNITED STATES OF AMERICA, UNITED KINGDOM, CHINA, most of the EU — visa-free, confirmed live to disable the wizard),4(9 countries, e.g. FRANCE, GEORGIA, ARMENIA, BELARUS, AZERBAIJAN — use a different consular channel),3(1 country, unclassified in this session). This schema'scitizenshipfield targets thestatus 1pathway; the field itself is not restricted to only those 44 values, since the dictionary and itsstatussemantics are a live, server-side classification not hard-coded into the form.GET /api/v1/dic/documents/en— exactly one entry,{"id":1,"name":"ORDINARY PASSPORT"}.GET /api/v1/dic/visa/types/en— three entries:{"id":1,"name":"SINGLE ENTRY 20$"},{"id":2,"name":"DOUBLE ENTRY 35$"},{"id":3,"name":"MULTIPLY 50$"}(the source's own spelling of "Multiple", not a transcription error introduced by this schema).GET /api/v1/dic/purposes/en— two entries,{"id":1,"name":"TOURISM"},{"id":2,"name":"BUSINESS"}.
Independently corroborated by the site's own https://e-visa.gov.uz/assets/localization/en.json (fetched directly, 191 translation keys), whose TERM_CONTENT_4_1 key states: "e-visa Visa application fee is USD 20.00 for single entry, USD 35.00 for double entry and USD 50.00 for multiple entry" — matching the three visaType fee tiers exactly.
Date format and validation logic, read directly from compiled code
The compiled bundle's selectDateFrom/selectDateTo methods (bound to the Date step's two ngb-datepicker controls via (dateSelect)) contain the literal serialization logic:
`` this.form.application.arrivalInfo.arrivalDate=(this.dpDateFrom.day<10?"0"+this.dpDateFrom.day:this.dpDateFrom.day)+"."+(this.dpDateFrom.month<10?"0"+this.dpDateFrom.month:this.dpDateFrom.month)+"."+this.dpDateFrom.year ``
confirming the exact DD.MM.YYYY wire format for arrivalDate — and, by the same pattern found immediately adjacent, departureDate, passportIssueDate (this.form.application.passportInfo.issuedDate, via passportIssueDate(n)), and passportExpiryDate (...expiredDate, via passportExpiredDate(n)). dateOfBirth uses the same DD.MM.YYYY format via a masked text input rather than a calendar widget, confirmed by its own birthDateMask definition ([/(\d|x)/,/(\d|x)/,".",/(\d|x)/,/(\d|x)/,".",/(\d)/,/(\d)/,/(\d)/,/(\d)/]) and its live placeholder="XX.XX.XXXX" attribute.
The same compiled code's dateToTest.markDisabled function (bound to the departure-date picker) reads:
`` return l>o+29||l<o+1 ``
(where l/o are day-offsets for the candidate departure date and the already-selected arrival date respectively) — confirming departure must be between 1 and 29 days after arrival (i.e. a stay of up to 30 days total), matching the site's own en.json string APPLICATION_INFO_DATERANGE_WARNING: "The period of stay must not exceed 30 days between the date of submission and completion of the validity period." This registry's crossFieldValidation vocabulary has no "difference at most N days" operator, so only the minimum bound (departureDate greaterThan arrivalDate) is expressed as a crossFieldValidation rule; the 30-day ceiling is disclosed in the field's own description instead of silently dropped. The picker's own minDate/maxDate configuration ({year: currentYear, month:1, day: currentDate} through {year: currentYear+1, month:12, day:31}, i.e. today through 90 days out in practice) corroborates the site's own en.json note (TERM_CONTENT_2_8) that the e-visa is valid for entry "within 90 days from the date of registration."
The passport-number field's passportMask definition ([/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/,/(\d|[a-zA-Z])/]) confirms a fixed 9-character alphanumeric passport number, and a separate loop over this.form.application.passportInfo ("string"==typeof this.form.application.passportInfo[t] && (this.form.application.passportInfo[t]= this.form.application.passportInfo[t].toUpperCase())) confirms every passport-info string field is uppercased before submission — consistent with the live inputs' own text-uppercase CSS class.
Conditional fields, confirmed structurally
surnameChanged/previousSurname and nameChanged/previousName each follow the same structural pattern in the compiled template: an l["ɵand"] conditional-view-container call (Angular's *ngIf compiled form) immediately follows each checkbox's own element definition, and the conditionally-rendered <input> inside it carries a required attribute. hasOtherCitizenship/otherCitizenship follows the identical pattern (isOtherCitizenship gates a conditionally-rendered applicantPreviousCitizenship <select>).
Photo and passport uploads
The compiled ApplicationService class (a plain TypeScript service, fully preserved by name in the bundle) exposes photoUploadService.startUpload/passportStartUpload methods whose bodies read:
`` url:ml.SERVER_URL+"/api/v1/photo/upload/face",method:"POST",fieldName:"face",... url:ml.SERVER_URL+"/api/v1/photo/upload/passport",method:"POST",fieldName:"passport",... ``
confirming the two upload endpoints and their field names. Size/format constraints are drawn from en.json: PHOTOS_INFO ("The photo must have a size of 35x45 mm with a resolution of 300 dpi. Image dimensions should not exceed 1 Mb."), ERROR_BIG_PHOTO ("Required image should be jpg format and file size should be less than 1024 KB"), ERROR_FACE_NOT_VALID_FORMAT/ERROR_PASSPORT_NOT_VALID_FORMAT ("Image format is wrong (jpg, jpeg)" / "Wrong format for passport image (jpg, jpeg)"). maxBytes: 1048576 models "less than 1024 KB."
The Activation step, the CAPTCHA gate, and Payment (out of scope)
en.json's APPLICATION_LABEL_CHECK_STATUS ("Enter the application code, received by e-mail") and SAVED_APPLICATION_DESC ("An email with a link to activate the receipt has been sent to your email address") confirm the Activation step's function: the applicant supplies an email address, receives a digital activation code by email, and enters it to activate the saved application. The compiled ApplicationService class's getCaptcha/sendEmail/activateApplication methods (GET /captcha/jcaptcha.jpg, POST /api/v1/application/mail, GET /api/v1/application/activate/{code}) confirm this flow is CAPTCHA-gated (this.form.captcha) — this schema models only the email field itself, not the CAPTCHA or the emailed activation code, consistent with this registry's treatment of CAPTCHA gates elsewhere (see ge/mfa/evisa-application's VERIFICATION.md).
The Payment step's compiled template embeds a plain HTML <form> with hidden inputs named VENDOR_ID, MERCHANT_TRANS_ID, MERCHANT_TRANS_AMOUNT, MERCHANT_CURRENCY, MERCHANT_TRANS_NOTE, MERCHANT_TRANS_DATA, MERCHANT_TRANS_RETURN_URL, SIGN_TIME, SIGN_STRING, and a type="submit" button — the standard integration pattern for Uzbekistan's Click.uz-style merchant payment gateway. This is payment-processor plumbing, not government-form data, and is excluded from this schema entirely (an empty payment step, matching this registry's convention for out-of-scope trailing steps — see et/ics/e-visa-application's review step).
Disclosed, not modelled: two unused translation keys
The site's own en.json contains LABEL_CONTACT_PERSON ("Contact person in Uzbekistan"), LABEL_INVITING_PARTY_IN_UZBEKISTAN ("Inviting party in Uzbekistan"), APPLICATION_CONTACT_PERSON_TITLE ("Contact person"), and APPLICATION_LAST_VISIT_TITLE/LABEL_VISITED ("Previous visit date"/ "Previous visits to Uzbekistan"). None of these four keys were found bound to any element (translate attribute or property binding) or any this.form.application.* assignment anywhere in the 953KB bundle actually shipped in this build — a direct string search located every other translation key referenced in this document at least once. Treated as unused/legacy translation keys from an earlier version of the form, not modelled, rather than guessed at or force-fit into a field.
Conformance
2 valid fixtures (0 errors each — one single-entry tourism applicant with no name/citizenship changes, one double-entry business applicant exercising every conditional field: surnameChanged, nameChanged, and hasOtherCitizenship all true) plus 8 mutation-control fixtures (each raising exactly 1 error: three requiredWhen cascade violations —previousSurname, previousName, otherCitizenship— an enum violation on visaType, a pattern violation on passportNumber, a missing top-level required field (email), and both crossFieldValidation rules — departureAfterArrival and passportExpiryAfterIssue) are committed under conformance/uz/mfa/evisa-application/1.0.0/. Checked with a from-scratch mock validator written for this session (structural JSON Schema tooling in this repo validates schema.json itself against the spec, not fixture data against a schema instance — consistent with this registry's established practice). node tools/validate.mjs and node tools/validate-ajv.mjs both pass with this document included.
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 Ministry of Foreign Affairs of the Republic of Uzbekistan, Consular Department or any government. The authoritative source is always the live government form and its official instructions.