The approval layer for agentic commerce in India.
Haat connects any personal AI agent to sellers on ONDC, understands requests in 11 Indian languages, and never places an order without a human yes.
- GET/.well-known/poppy.jsonDiscover company · operations v2200
- POST/conversations/messagesPoppy-Session ES256 verified · jti fresh200
- LEXlexicon.parse()wheat flour · 2 kg, milk · 1 Lok
- BECKNsearch → on_search9 offers · 3 sellersok
- POST/operationsKashi Kirana Store · ₹197403
- BECKNconfirm → on_confirmapproved revision · sent exactly once201
Built on open standards
Official Poppy validator checks passed, zero warnings
Automated tests across signing, sessions and orders
Indian languages, native script and Latin spellings
Runtime dependencies. A tiny surface to audit
Agents can talk to sellers. They shouldn't spend without you.
Consumer AI agents speak Poppy. India's open commerce network speaks Beckn. Haat sits between them, translates every call, and owns the one decision that must never be automated: the purchase.
Understand how India types
A data-driven lexicon turns everyday requests in native scripts or Latin spellings into structured search terms and quantities.
Bridge Poppy to Beckn
Signed Beckn search fans out to sellers from the ONDC registry, then builds the best single-seller basket with the least wasted pack size.
Stop at the gate
Orders and cancels return 403 approval_required with an exact summary. The person approves one revision. Confirm runs at most once.
Type like you talk. Approve like you mean it.
Pick a language and watch the gateway understand the request, build a basket, and wait for your decision. Replayed from real Haat output against the mock ONDC network in this repo.
What the gateway is doing
- 1Discover the company (
/.well-known/poppy.json) - 2Verify the signed
Poppy-SessionJWT - 3Lexicon: text → search terms and quantities
- 4Beckn search fan-out, best-seller basket
- 5Approval gate:
403 approval_required - 6Beckn
confirm, at most once
// responses appear here as the demo runs
Sandbox only. No real seller or money is touched.
Four steps from a sentence to a single, approved order.
Understand
"2 kilo aata" or "இரண்டு கிலோ அரிசி" becomes wheat flour · 2000 g.
Search
Signed Beckn search to registry sellers. Pick pack sizes that waste least.
Ask
Gateway returns an exact summary. The human approves one specific revision.
Confirm once
Persisted across restarts. Unknown outcome means 503 Retry-After, never a double order.
Everything the buyer side needs. Nothing it doesn't.
Built so small sellers don't become invisible as consumer agents adopt Poppy, with the same safety guarantees for every agent.
Human approval gate
Operations extension v2. Approval binds to one revision, one session, and expires. Orders and cancels both need a yes.
"error": "approval_required",
"summary": "Kashi Kirana · ₹197 · COD"
Exactly-once orders
Idempotency is persisted in SQLite across restarts. Retrying the same approval returns the same order, never a second one.
retry #2 → 201 order KKS-1001 (replayed)
Beckn buyer app
Ed25519 + BLAKE2b-512 signing, signed ONDC v2 registry lookups, search through cancel.
Poppy conformant
Official validator over real HTTPS: 99 passed, 0 failed. Direct Sign-In with PKCE.
Conversations and SSE
Cursors, long polling, server-sent events with Last-Event-ID, idempotent message IDs.
Smart baskets
Picks the single seller that covers most of the list and says clearly what is missing.
Zero runtime deps
Node 22.18+ runs TypeScript directly. SQLite via node:sqlite. No build step.
Domain packs
Grocery and food today. Add a vertical with two JSON files, no TypeScript needed.
The model never holds the keys.
The company-side agent is rule-based on purpose. No language model touches signing keys, session tokens or the approval step.
- Signed sessions on every requestPoppy-Session JWT bound to
aud,htm,htu,ath, replay-protected byjti. - SSRF-safe fetchingOutbound URLs are HTTPS-only and private address ranges are refused.
- Scoped, expiring approvalsOne approval covers one revision in one session, then expires.
- Bounded storageEvery namespace has a cap. No unbounded growth under load.
Built for the way Bharat actually types.
Native scripts and Latin spellings in every language. Hindi is hand-written; the rest is machine-drafted and open for native-speaker review.
One minute to a running network.
Node.js 22.18 or newer. No build step. A local mock ONDC network with three sellers ships in the repo.
See Haat in one minute.
A Hinglish request is understood, searched across sellers, stopped at the approval gate, and confirmed exactly once.
Early, and clear about it.
Haat is production-grade in its guarantees and pre-production in its connections. Here is exactly where it stands.
Shipped in v0.2 Available
- Full order flow on a local mock ONDC network
- Official Poppy validator: 99 passed, 0 failed
- 126 tests, lint and typecheck clean
- ONDC onboarding pieces following official reference code
On the roadmap Next
- Live ONDC connection (legal entity, whitelisting, approval)
- Production SMS provider for sign-in codes
- Staffed human handoff
- Native-speaker review of non-Hindi lexicons
Bring every ONDC seller to every personal agent.
Open source and MIT licensed. Most contributions need no TypeScript: lexicon variants, language review, domain packs and docs.