ProcureFlow AI — About the Project
Inspiration
Every mid-size operations team we've talked to has the same broken workflow: someone needs to source a product, they email three suppliers, wait two days for quotes, paste them into a spreadsheet, forward it to AP for approval, and hope the delivery date still holds. The whole process is manual, disconnected, and slow — not because the people are slow, but because there's no system that owns the full loop from request to decision.
We wanted to build that system. Not a form. Not a dashboard. A true agentic copilot that takes a single natural language request spoken or typed — and autonomously handles vendor discovery, supplier outreach, quote comparison, AP validation, and a final recommended action. The goal was to collapse a two-day procurement cycle into under 90 seconds, with every step visible, auditable, and governed.
What We Built
ProcureFlow AI is an end-to-end agentic procure-to-pay pipeline with five sponsor integrations doing real work at every layer:
Voice & Outbound Calling — Vapi Two distinct agent roles. A browser-side Web SDK voice agent captures the intake request — the user speaks, Vapi transcribes, and we parse the transcript into structured procurement fields via GPT-4o. A separate server-side assistant places a real outbound phone call to the top-matched vendor. An AI voice agent asks for price, stock availability, and delivery date. When the call ends, Vapi sends a webhook with a Call Summary structured output; we extract the quoted price using LLM parsing and route it directly into the ranking engine.
Autonomous Web Outreach — TinyFish Two parallel MCP-powered steps run simultaneously with the Vapi call. fetch_content reads a second supplier's live catalog page and extracts price per unit, stock quantity, lead time, and MOQ — with LLM fallback for unstructured content. run_web_automation fills and submits that supplier's quote request form autonomously and returns the confirmation reference. Two suppliers contacted through two completely different channels at the same time.
State, Search & Real-time — Redis
Redis Stack is the backbone across five distinct capabilities: HNSW vector search for semantic vendor matching (a request like "FDA-approved industrial coolant in San Jose" returns the top 5 vendors by cosine similarity); Redis pub/sub to stream every workflow step live to the frontend via Server-Sent Events; semantic caching on LLM calls so identical requests never hit the model twice; Redis Sets to track which quotes belong to which job; and JSON document storage with TTL expiry for all workflow state, quotes, vendors, and AP results.
Governance Layer — WunderGraph
Six typed operations form a governed BFF layer: GetApprovedVendors, GetQuotes, SaveQuote, RankSuppliers, ValidateInvoice, and ExecuteAction. Every operation goes through shared middleware that enforces role-based access control via X-ProcureFlow-Role headers, writes a full audit entry (operation, role, duration, status) to a queryable ring buffer at /audit, and returns structured errors with correct HTTP status codes. No AP decision — approve, hold, negotiate, escalate — can be taken without passing through the governance layer.
Zero-CVE Runtime — Chainguard
The backend runs on Chainguard's distroless Node.js base image. Multi-stage Docker build: dependencies and compilation in a build stage, only the Node runtime and application code in the final image. No shell, no package manager, no attack surface.
Challenges We Faced
Vapi webhook payload structure The biggest debugging rabbit hole. Vapi sends server-URL webhooks with the entire payload nested under a message key — body.message.call, body.message.analysis, body.message.endedReason. We were reading from body.call and getting undefined on everything. The call was completing, the structured output was there, but we were looking in the wrong place. Found it by dumping raw body keys to logs.
Async quote timing A real Vapi call takes 1–3 minutes. Our workflow was initiating the call and immediately moving to aggregate quotes — so the Vapi quote always arrived after the job was already complete. Fixed by turning runVapiStep into a Redis poller: after firing the call, it checks Redis every 4 seconds for up to 2 minutes for a quote with source: vapi. The workflow step stays in running state on the timeline while it waits — which actually makes the UI feel more honest about what's happening.
Extracting price from free-form transcripts
Real phone call transcripts don't say QUOTE_RECEIVED: $370 2026-04-25. They say things like "we can do nineteen dollars a gallon, next week delivery, minimum ten gallons." Built a three-tier extraction pipeline: structured marker regex → LLM extraction from Vapi's Call Summary structured output → fallback mock so the demo always produces a result.
WunderGraph as a real governance layer
It was easy to make WunderGraph a passthrough proxy. Making it genuinely enforce contracts — role validation that returns 403, input validation that returns 422, structured audit logging — required rethinking the operation resolver pattern and building a shared handleOperation function that every operation flows through.
What We Learned
Building agentic systems is less about the AI and more about the plumbing. The LLM calls were the easy part. The hard part was: what happens when a webhook arrives 90 seconds after you expected it? What happens when a transcript has no parseable price? What happens when TinyFish times out on a form? Every real integration introduced a new failure mode that pure demo mode never surfaced.
The lesson: build for the unhappy path first. Mock fallbacks, async polling, structured extraction tiers — all of those came from hitting real failure modes in real calls, not from planning.
We also learned that governance isn't an afterthought. Routing every action through WunderGraph with audit logging felt like overhead at first. By the end it was the most compelling part of the demo — being able to pull up /audit and see every operation, every role, every duration in real time is exactly what an AP team would actually want.
Built With
- express.js
- javascript
- node.js
- react.js
- redis

Log in or sign up for Devpost to join the conversation.