Inspiration
What it does
How we built it## Inspiration
Six months ago, I was stranded in India because I didn't understand one line in my visa letter. My Temporary Resident Visa had expired, and I missed the start of my Winter 2026 semester at the University of Toronto. For three weeks I wrote letters to IRCC officers, university officials, and my MP — trying to resolve a situation that started with a single document I hadn't read correctly.
The frustrating part wasn't the bureaucracy. It was that the information I needed was already there, printed on my documents. I just didn't know how to read them together, what the deadlines actually meant, or what would happen if I missed them. A licensed immigration consultant would have caught it in minutes. Most people can't afford one.
That's what Landed is for.
What it does
Landed lets you upload your Canadian immigration documents — study permits, work permits, TRVs, passports, IRCC correspondence — and tells you exactly what your situation is.
It doesn't treat each document in isolation. It reasons across all of them at once. An expired work permit doesn't override a valid study permit. An expired TRV becomes a travel warning, not a false instruction to leave Canada. A deadline buried on page 2 of a formal letter gets surfaced automatically.
The output is practical: your current status in plain English, every deadline from every document in one timeline, step-by-step action plans, consequences for missing each deadline, implied status guidance, work authorization details, and grounded Q&A that cites the specific document behind every answer. In any of 8 languages.
How we built it
The backend is a FastAPI application orchestrated through Railtracks — a new open-source Canadian agentic framework. The upload pipeline runs as a rt.Flow:
parse_document × N → synthesize_status → generate_action_plan
Each step is a @rt.function_node. Document parsing uses three extraction paths in sequence: deterministic regex parsing for structured IRCC permit fields, local macOS Vision OCR for scanned documents and images, and GPT-OSS 120B via the OpenAI-compatible HuggingFace endpoint for unstructured extraction and translation when a key is configured.
The cross-document reasoning step is where most of the immigration logic lives. It selects the active status document when older permits are superseded, separates stay authorization from work authorization from travel authorization, detects expired TRVs independently from permit validity, and computes implied status windows, processing timelines, and consequence text from a curated IRCC knowledge base.
The frontend is Next.js 14 with Tailwind CSS and Framer Motion, streaming live parse and reasoning updates to the UI over SSE as each document is processed.
Challenges we faced
Cross-document conflicts. The hardest problem wasn't parsing any single document — it was deciding which document governs the user's current status when they've uploaded both an expired work permit and a valid study permit. Getting the synthesizer to correctly ignore superseded documents required careful prompt engineering and explicit conflict resolution logic.
OCR noise and hallucination. Scanned immigration documents are messy. Permit numbers, dates, and reference codes extracted via OCR often contain character substitutions (0 vs O, 1 vs l). We built confidence scoring per field and fall back to deterministic parsing rather than silently trusting uncertain model output.
Implied status edge cases. Implied status — the authorization to remain in Canada while a renewal is processed — has conditions most people don't know about. It only applies if you applied before expiry. It doesn't allow re-entry if you travel. Getting the system to communicate this correctly without either alarming users unnecessarily or understating the risk took several iterations.
Making it feel trustworthy, not clinical. Immigration is stressful. The design had to feel warm and authoritative rather than like a government portal or a chatbot. Every copy decision, every color choice, every animation was made with that in mind.
What we learned
The most important insight was that the value isn't in reading any single document — it's in reading them together. Every immigration app that exists treats documents as separate inputs. Landed treats them as a set, and that single architectural decision is what makes the output actually useful.
We also learned that Railtracks makes agentic pipelines genuinely legible. The visualizer showing parse_document × 3 → synthesize_status → generate_action_plan with per-step timing isn't just a debugging tool - it's proof that the system is doing real work in a way judges and users can verify directly.
What's next
Processing time calculators that tell you not just when your permit expires but when you need to apply today to be safe. Calendar export so deadlines land in your phone. Support for PR pathways. And eventually — a version that works for immigration systems beyond Canada.
1.2 million people navigate Canadian immigration every year. Most of them don't know what they don't know. Landed is built for them.
Challenges we ran into
Accomplishments that we're proud of
What we learned
What's next for Landed
Built With
- fastapi
- framer-motion
- gpt-oss-120b
- macos-vision-ocr
- next.js-14
- openai-compatible-huggingface-endpoint
- pydantic
- pymupdf
- python
- railtracks
- react-dropzone
- reportlab
- sse-starlette
- tailwind-css
- typescript
- zustand
Log in or sign up for Devpost to join the conversation.