Invoice Download
On-demand invoice PDF generation and download flow for customer orders
Invoice Download
Overview
The order module supports two invoice download paths:
- Authenticated fresh download from order details.
- Signed URL download used by email CTA.
Invoices are generated on demand and streamed immediately.
API Endpoints
GET /api/orders/:id/invoice
Legacy authenticated endpoint (still supported for backward compatibility).
- Auth:
Bearer JWTrequired - Owner check: order must belong to authenticated customer
- Rate limit:
10 requests / minuteper client key - Response content type:
application/pdf
GET /api/orders/:id/invoice-download
Preferred authenticated endpoint for order-page Download Invoice button.
- Auth:
Bearer JWTrequired - Owner check: order must belong to authenticated customer
- Rate limit:
10 requests / minuteper client key - Response content type:
application/pdf
GET /api/admin/orders/:id/invoice-download
Admin invoice download endpoint for any order.
- Auth: admin
Bearer JWTrequired - Permission:
Orders_READ - Ownership check: not required (admin scope)
- Rate limit: admin order-operation limiter
- Response content type:
application/pdf
POST /api/orders/:id/invoice-token
Generates a signed, single-use invoice token for the specified order.
- Auth:
Bearer JWTrequired - Owner check: order must belong to authenticated customer
- Rate limit:
10 requests / minuteper client key - Response:
token(raw token for URL path)expiresAt(ISO timestamp)downloadUrl(/invoices/{token}or absolute frontend URL)
GET /api/invoices/:token
Public signed URL endpoint used by email CTA.
- Auth: none
- Rate limit:
20 requests / minuteper client key - Behavior:
- valid + unconsumed token -> streams invoice PDF
- expired token ->
302to login with?redirect=/invoices/{token} - consumed token ->
302to login with?error=token_consumed - invalid token ->
302to login with?error=invalid_token
Success Response
- HTTP
200 OK Content-Disposition: attachment; filename="invoice-{orderNumber}.pdf"
Error Responses
401Unauthorized403Forbidden (order ownership mismatch)404Order not found429Too many requests500Invoice generation failed400Invalid token (INVOICE_TOKEN_INVALID)409Expired or consumed token (INVOICE_TOKEN_EXPIRED,INVOICE_TOKEN_CONSUMED)
Generated Invoice Content
The generated PDF includes:
- Invoice number (
orderNumber) - Invoice date (
order.createdAt) - Payment status
- Buyer identity and shipping address
- Line items with quantity and unit price
- Subtotal, discount, shipping fee, final total
- Currency formatting
Order monetary values are stored in paisa and converted for invoice display.
Email Integration
Checkout and buy-now transactional emails include a Download Invoice CTA that points to:
{FRONTEND_BASE_URL}/invoices/{token}
Signed token characteristics:
- stored hashed (
SHA-256) ininvoice_tokens - single-use (
consumedAtis set on first successful download) - expiry defaults to 7 days and is configurable via
INVOICE_SIGNED_URL_TTL_MS
The existing View Order Details CTA remains unchanged.
Operational Notes
- PDF generation is on-demand, not pre-generated.
- Temporary PDF files are removed after response generation.
INVOICE_PDF_DIRis used when set.- If
INVOICE_PDF_DIRis unset, default directory is${UPLOAD_LOCATION}/invoices. - If signed URL is expired/consumed, user can still download via order page button using JWT endpoint.