Invoice Module — Vendor
HTTP surface for a vendor to check, generate, stream, download, and regenerate the GST tax invoice for their own sub-order — async generation with SSE readiness notification.
HTTP surface for a vendor to access the invoice for one of their own sub-orders. Each vendor is the seller of record on its invoice (its own GSTIN), so a vendor only ever sees its own sub-order's invoice — never a sibling vendor's. Generation is lazy and async: the first POST …/generate call enqueues a background render job; an SSE stream reports when it is ready; repeat downloads stream the cached PDF instantly. Vendors may also regenerate their own invoice — it re-renders against the same, immutable serial.
Source:
api-modules/invoice/src/controllers/vendor-invoices.controller.ts.Scoped to the active vendor (
resolveActiveVendorId). A sub-order belonging to another vendor returns 404. An order still inpending_paymentreturnsstatus: "none".
Conventions
Authentication
All endpoints require a Better-Auth vendor session. The sub-order (orderVendorId) must belong to the active vendor. The SSE stream (/stream) is authenticated via the session cookie, which the browser EventSource sends automatically.
Response shape
- Status / generate endpoints return the standard JSON envelope:
{ data, message, statusCode }. - Download (
GET …/invoice) streams rawapplication/pdfbytes withContent-Disposition: attachment— no JSON envelope. - SSE stream (
GET …/invoice/stream) returnstext/event-stream— no JSON envelope.
Generation flow
POST …/invoice/generate
│
├─ status: "ready" ──► GET …/invoice (streams cached PDF)
│
└─ status: "pending" ──► open GET …/invoice/stream
│
├─ { status:"pending", heartbeat:true } (periodic)
├─ { status:"ready", downloadUrl } ──► GET …/invoice
└─ { status:"failed", error }On page load, call GET …/invoice/status to render the current state without triggering a render.
Endpoints
Check invoice status
GET /vendor/orders/:orderVendorId/invoice/status
Returns the current status without enqueuing anything. Safe to call on every page load.
Response (data field):
{
"status": "ready" | "pending" | "failed" | "none",
"invoiceNumber": "INV-2526-000001" | null,
"downloadUrl": "…" | null, // set only when ready
"streamUrl": "…" | null, // set only when pending or failed
"jobId": "…" | null
}status: "none" is returned when the parent order is still in pending_payment or no generate has been requested yet.
Enqueue invoice generation
POST /vendor/orders/:orderVendorId/invoice/generate
Enqueues the render job if not already cached. Idempotent — concurrent first-generation requests collapse onto one job.
Request body (optional):
{ "regenerate": true }Setting regenerate: true forces a fresh render against the existing, immutable serial and overwrites the cached PDF (e.g. to correct a stale invoice after a vendor-profile GSTIN change). Omit the body (or set regenerate: false) for normal generation. This is the only way a vendor regenerates — there is no separate regenerate endpoint on the vendor surface.
Always returns HTTP 200. Response (data field):
{
"status": "ready" | "pending",
"jobId": "…",
"downloadUrl": "…" | null, // set when ready
"streamUrl": "…" | null // set when pending
}Download my sub-order's invoice
GET /vendor/orders/:orderVendorId/invoice
Streams the cached application/pdf when the invoice is ready. Returns 409 while still generating — call POST …/generate first, then wait for the SSE ready frame before downloading.
Filename: invoice-{serial}.pdf (e.g. invoice-INV-2526-000001.pdf).
Stream readiness (SSE)
GET /vendor/orders/:orderVendorId/invoice/stream
Opens a Server-Sent Events connection (text/event-stream). Each data: frame is JSON:
// Periodic heartbeat while rendering
{ "status": "pending", "heartbeat": true }
// Terminal: ready
{ "status": "ready", "downloadUrl": "…" }
// Terminal: render failed
{ "status": "failed", "error": "…" }The stream closes automatically after ~60 s. If no terminal frame was received, re-check status with GET …/invoice/status and reconnect if still pending.
Inventory Module — Vendor surface
Vendor-facing HTTP endpoints for managing product-variant stock levels, policies, manual adjustments, audit trails, vendor-wide variant listing, and bulk CSV imports.
Notifications Module — Vendor surface
Vendor-facing HTTP surface for mobile device registration so the vendor app can receive push notifications (new-order alerts, payout updates, application status, etc.). The wider…