A Next.js example app that ingests receipts into Railengine. Drop a receipt image onto the page and Claude vision extracts the structured fields (vendor, amount, currency, date, category, line items, tax, tip), which you confirm and save into Railengine.
Built with Next.js 16 (app router), React 19.x, TypeScript, Tailwind CSS, and shadcn/ui. Includes a light/dark theme toggle and a mobile-responsive layout.
-
Sign up for a free account at Railengine
-
Create an Agent project
-
Create a new Engine with the schema in
engine-schema.json -
Install dependencies:
npm install
-
Copy
.env.exampleto.envand fill in your credentials:cp .env.example .env
Then edit
.envwith your:ENGINE_TOKEN— Engine Token for ingestionENGINE_PAT— Engine PAT for retrievalENGINE_ID— Engine IDANTHROPIC_API_KEY— Anthropic API key (only needed for receipt OCR; manual entry and delete work without it)
-
Run the development server:
npm run dev
Open http://localhost:3000 in your browser.
Treat this repository as a local / controlled demo. The Next.js route handlers forward to Railengine (PAT/token) and, when OCR is enabled, Anthropic — without end user authentication or rate limits. Hosting it on the public internet exposes those credentials to misuse and billed usage. Prefer VPN or private networking, secrets in the deployment environment only, auth in front of the app, or your own quotas and monitoring if you expose it outward.
image dropped
→ FileReader → base64
→ POST /api/extract
→ Claude vision (claude-opus-4-7)
→ JSON validated against ExtractedExpenseSchema
→ user reviews/edits in confirmation dialog
→ POST /api/ingest
→ RailEngineIngest.upsert(expense)
→ list refetches via /api/retrieve
The receipt image is never stored in Railengine — only the structured
fields end up in the document store. To change the model used for OCR, edit
the model string in
app/api/extract/route.ts.
The header search box calls @railtownai/railengine:
- Index search —
searchIndex(Azure Search style body, e.g.{ search: "…" }). - Vector search —
searchVectorStorewithVectorStore1.
Uses the same ENGINE_PAT, ENGINE_ID, and optional RAILTOWN_API_URL as retrieve/delete. Your engine must have indexing and/or VectorStore1 configured. Non-success HTTP responses from the indexing or embeddings endpoints surface as errors in /api/search instead of silently empty results.
The expense schema is defined in lib/schema.ts and the
sample document at engine-schema.json matches it
exactly — paste it into your Railengine engine when creating the schema.