Context
Every destination has its own visa form and its own portal, and none of them offers an API. Visa specialists were typing the same applicant data into each country's portal by hand, applicants were abandoning long forms partway through, and one small mistake could cost weeks.
Constraints
- One wrong field can cost an applicant weeks, or a refused visa.
- Official portals have no API, and every country's form is different.
- Coverage keeps growing: Schengen, the US, the UK, Turkey, the UAE, Sri Lanka, Kenya and more.
- Every automated action has to be explainable to the person who checks it.
- My wife is travelling with me. She has her own passport.
- Passport number
- ···
- Travel dates
- ···
- Co-applicant
- ···
- Bank statement
- ···
My responsibility
Sole engineer on the platform: agent design, the browser extension, the core API, document and identity workers, payments, status tracking and the production rollout.
Architecture
- Core platform
- A Spring Boot modular monolith on Java 21 with clear module boundaries: applicants, visa applications, documents, admin, travel agents, quality control, consent and notifications.
- The agent
- The agent works from the applicant's own documents, read by OCR. The model runs on AWS Bedrock, answers stream to the browser over Server-Sent Events, and every action is a typed tool call: fill a form field, draft a letter, escalate to a reviewer.
- Portal autofill
- A browser extension reads the official portal's HTML form, sends its fields together with the validated application to an AI model, and applies the field mapping that comes back. Visa specialists no longer retype applications: they check the filled form and submit it, on any country's portal from Schengen to Kenya.
- Documents and identity
- OCR and face-match workers consume from RabbitMQ, so heavy document and identity checks run off the request path and never block the applicant.
- Payments
- A separate service for checkout, 3-D Secure, webhooks and refunds.
- Status tracking
- For supported countries, RPA workers built on Playwright check embassy and government portals for status changes and report them into the core API, so nobody refreshes a portal by hand.
Critical decisions
Typed tool calls only
The model can act only through typed tool calls. Each one is a structure the system validates before it touches the filing, so nothing the model writes as prose can change an application.
Hold the case when unsure
If the agent cannot establish a field from the applicant's documents, the submission stops. A visa specialist sees the case with the reason attached and makes the call.
An extension, because there is no API
Official portals offer no API, so the extension fills the form in the browser and stops there. A visa specialist validates every field and clicks Submit; nothing reaches an embassy without a person.
Let AI map the form
An AI model maps each portal's form from its live HTML at fill time, so a redesigned portal or a new country usually needs little or no new code. The mapping comes back as JSON the extension applies field by field, and a person checks the result.
A modular monolith
One deployable with strict module boundaries. At this size that avoids the cost of running a distributed system, and any module can be split out later if volume demands it.
Payments behind an interface
The payment provider sits behind one interface. When the business moved from Razorpay to Stripe, no caller changed.
When things go wrong
| When | What happens |
|---|---|
| A supporting document, such as a bank statement, is out of date or doesn't match the application | The case is held for a visa specialist with the reason attached. |
| A country redesigns its visa portal | The extension maps the new form from its live HTML on the next fill, and a person still checks every field. |
| OCR or face matching is slow or fails | The worker handles it off the request path; the applicant keeps going. |
Result
Running in production with real applicants, across Schengen, the US, the UK and more.
Of each application filled by the agent from the applicant's own documents
Stack
Java 21 · Spring Boot 3 · PostgreSQL · RabbitMQ · AWS Bedrock · Server-Sent Events · Stripe · Playwright · Browser extension