AI-powered order intake automation. Monitors email inboxes, extracts structured PO data using Claude, maps SKUs, handles exceptions, and syncs to ERP systems.
Inbox (Gmail / Outlook)
│
▼
Inbox Poller ← polls every 2 min via cron
│
▼
Extraction Service ← Claude API: email → structured JSON
│
├── SKU Mapper ← exact / fuzzy / AI match → internal SKU
│
├── Validator ← checks required fields, price rules
│
└── Exception Handler
│ touchless=true │ touchless=false
▼ ▼
ERP Router Clarification Email
/ | \ (sent back to customer)
NetSuite QB CSV/Webhook
cd backend
cp .env.example .env
# Fill in at minimum: ANTHROPIC_API_KEY
npm install
npm run devServer starts on http://localhost:3000
curl -X POST http://localhost:3000/api/orders/parse \
-H "Content-Type: application/json" \
-d '{
"from": "buyer@customer.com",
"subject": "PO #1234",
"date": "2025-03-15",
"body": "Please send 48 units of Dark Roast 5lb at $18.50 each. Ship to 123 Main St, Columbus OH 43215. PO #1234. Delivery by March 20."
}'curl -X POST http://localhost:3000/api/orders/parse-file \
-F "file=@order.pdf" \
-F "from=buyer@customer.com"# All orders
curl http://localhost:3000/api/orders
# Only exceptions
curl "http://localhost:3000/api/orders?status=exception"curl -X POST http://localhost:3000/api/orders/{id}/push \
-H "Content-Type: application/json" \
-d '{ "target": "csv" }'
# targets: csv | webhook | netsuite | quickbookscurl -X PUT http://localhost:3000/api/orders/{id}/resolve \
-H "Content-Type: application/json" \
-d '{ "field": "shipTo", "value": "123 Main St, Columbus OH 43215" }'- Create a project in Google Cloud Console
- Enable Gmail API
- Create OAuth 2.0 credentials (Desktop app)
- Add
GMAIL_CLIENT_ID,GMAIL_CLIENT_SECRETto.env - Visit
http://localhost:3000/auth/gmailto authorize - Copy the refresh token from server logs →
GMAIL_REFRESH_TOKENin.env - In Gmail, create a label called
orders-inboxand set up a filter to apply it
- Register an app in Azure Portal → App registrations
- Add redirect URI:
http://localhost:3000/auth/outlook/callback - Add API permission:
Mail.Read,Mail.Send(delegated) - Add
OUTLOOK_CLIENT_ID,OUTLOOK_CLIENT_SECRET,OUTLOOK_TENANT_IDto.env - Visit
http://localhost:3000/auth/outlookto authorize - Copy refresh token from logs →
OUTLOOK_REFRESH_TOKENin.env
| Connector | Status | Notes |
|---|---|---|
| CSV | ✅ Ready | Always available, exports to ./data/exports/ |
| Webhook | ✅ Ready | Set ERP_WEBHOOK_URL to a Zapier/Make endpoint |
| NetSuite | 🔧 Configure | Needs TBA credentials in .env |
| QuickBooks | 🔧 Configure | Needs OAuth 2.0 credentials in .env |
Recommended order: Start with CSV for all early customers. Add Webhook for Zapier-savvy customers. Build NetSuite first among native connectors.
The skuMapper uses a three-tier lookup:
- Exact match — checks
src/services/skuMapper.jsproduct catalog - Fuzzy match — token overlap score ≥ 0.6
- AI fallback — Claude picks the best match from the catalog
To add products, edit the PRODUCT_CATALOG array in skuMapper.js. In production, replace this with a DB query against your product master.
backend/
├── src/
│ ├── server.js # Express entrypoint
│ ├── config/
│ │ └── index.js # Env var loader & validator
│ ├── api/
│ │ ├── orders.js # REST routes for order operations
│ │ ├── auth.js # Gmail + Outlook OAuth flows
│ │ └── webhooks.js # Webhook registration + dispatch
│ ├── services/
│ │ ├── extractionService.js # Claude AI extraction + file parsing
│ │ ├── skuMapper.js # 3-tier SKU matching
│ │ ├── inboxPoller.js # Gmail + Outlook scheduled polling
│ │ ├── orderStore.js # File-based order persistence
│ │ ├── clarificationService.js # Auto-reply emails for exceptions
│ │ └── erpRouter.js # Routes orders to correct connector
│ ├── connectors/
│ │ ├── netsuite.js # NetSuite REST API (OAuth 1.0a TBA)
│ │ ├── quickbooks.js # QuickBooks Online API (OAuth 2.0)
│ │ ├── csv.js # CSV file export
│ │ └── webhook.js # Generic HTTP webhook push
│ └── utils/
│ ├── logger.js # Structured JSON logger
│ └── asyncHandler.js # Express async error wrapper
├── data/ # Auto-created: orders.json, exports/
├── .env.example # Copy to .env and fill in
└── package.json
- Replace
orderStore.jsfile store with PostgreSQL (usepgordrizzle-orm) - Move
processedIdsSet ininboxPoller.jsto Redis - Add a job queue (BullMQ) for high-volume parsing
- Add auth middleware to API routes (API key or JWT)
- Move secrets to AWS Secrets Manager / Doppler
- Containerize with Docker, deploy to Railway or Fly.io