/api/v1/businesses/:businessId/invoices/batches
auth: jwt (administrator | view_invoices | submit_invoices)Paginated list of import batches for the business. Each batch row carries row counts (imported/failed) and the originating file metadata. Registered before /:invoiceId so the literal 'batches' segment never collides with the dynamic id.
handlers: InvoicesController.listBatches
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. Enforced by requireBusinessAccess (Administrator bypasses). |
offset queryinteger | no | 0 | Pagination offset. Coerced from string; min 0. |
limit queryinteger | no | 50 | Page size. Coerced from string; min 1, max 200. |
APIResponseDataList<ImportBatchDTO>/api/v1/businesses/:businessId/invoices/daily-fiscal-report
auth: jwt (administrator | view_audit | submit_invoices)Server-side aggregation of fiscalised payments inside a date window. Payment-aware — every fiscalised InvoicePayments row counts as one fiscal event and amounts come from PaymentAmount, so a multi-payment invoice with payments on different days splits correctly. Fires DAILY_FISCAL_REPORT_GENERATED (fire-and-forget) for audit traceability.
handlers: InvoicesController.getDailyFiscalReport
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
dateFrom queryISO-8601 datetime | yes | — | Inclusive start of the report window. Normalised to start-of-day server-side. Must be on or before dateTo (Zod refine). |
dateTo queryISO-8601 datetime | yes | — | Inclusive end of the report window. Normalised to end-of-day (23:59:59.999 UTC) server-side. |
APIResponseDataObject<DailyFiscalReportResponse>APIError/api/v1/businesses/:businessId/invoices
auth: jwt (administrator | view_invoices | submit_invoices)Paginated invoice list for the business. RTK infinite-query compatible. Returns invoices in the same shape as the single-invoice GET (with embedded payments[] and line-items omitted).
handlers: InvoicesController.list
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
offset queryinteger | no | 0 | Pagination offset. min 0. |
limit queryinteger | no | 50 | Page size. min 1, max 200. |
APIResponseDataList<InvoiceDTO>/api/v1/businesses/:businessId/invoices/:invoiceId
auth: jwt (administrator | view_invoices | submit_invoices)Fetch a single invoice with its line items and payments[] embedded. Cross-tenant probing returns 404 since the repo filters by businessId.
handlers: InvoicesController.getById
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
invoiceId pathuuid | yes | — | Invoice UUID. |
APIResponseDataObject<InvoiceDTO>APIError/api/v1/businesses/:businessId/invoices/:invoiceId/payments
auth: jwt (administrator | view_invoices | submit_invoices)List every payment under a single invoice. Returns the same payments[] array embedded on GET /invoices/:invoiceId plus per-payment fiscal data (FiscalInvoiceNumber, FiscalTimestamp, etc.). Ordered by PaymentDate ASC, CreatedAt ASC. Lets the FE refresh only the payments list after a per-payment action without re-fetching the parent invoice.
handlers: InvoicesController.listPayments
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
invoiceId pathuuid | yes | — | Parent invoice UUID. Existence under businessId is verified before payments are listed (prevents cross-tenant probing of payment IDs). |
APIResponseDataObject<GetInvoicePaymentsResponse>APIError/api/v1/businesses/:businessId/invoices/:invoiceId/payments/:paymentId
auth: jwt (administrator | view_invoices | submit_invoices)Direct drill-down for a single InvoicePayments row. Returns the same InvoicePaymentDTO shape that appears inside the parent invoice's payments[] array. Returns 404 when the payment doesn't belong to the (invoiceId, businessId) pair — protects against cross-tenant or cross-invoice probing.
handlers: InvoicesController.getPaymentById
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
invoiceId pathuuid | yes | — | Parent invoice UUID. |
paymentId pathuuid | yes | — | Payment UUID. Must belong to invoiceId under businessId. |
APIResponseDataObject<GetInvoicePaymentByIdResponse>APIError/api/v1/businesses/:businessId/invoices/reprocess-unmapped
auth: jwt (administrator)Re-evaluates every invoice blocked for MISSING_TAX_MAPPING against the current active TaxRateMappings. For each invoice whose codes are now fully mapped: updates line-item TaxLabel/TaxRatePercent in place, strips MISSING_TAX_MAPPING from FiscalisationBlockReasons, and sets EligibleForFiscalisation = 1. Idempotent — already-eligible invoices are untouched.
handlers: InvoicesController.reprocessUnmapped
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
APIResponseDataObject<{ reprocessed: number; nowEligible: number; stillBlocked: number }>/api/v1/businesses/:businessId/invoices/cancel-bulk
auth: jwt (administrator | submit_invoices)Bulk cancel up to MAX_PAYMENTS_PER_FISCALISATION_JOB fiscalised payments in one job. Builds a cancellation row per valid payment, then dispatches every freshly-inserted cancellation in a single FiscalisationJob so the client polls one jobId. Invalid IDs come back in blocked[]; IDs whose original already has a cancellation in flight come back in inFlight[]. Fires INVOICE_PAYMENT_CANCELLATION_REQUESTED audit per dispatched payment.
handlers: InvoicesController.cancelBulk
Request body type: CancelInvoicesBulkBody
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
paymentIds bodyuuid[] | yes | — | 1..MAX_PAYMENTS_PER_FISCALISATION_JOB payment UUIDs to cancel. Validated by CancelInvoicesBulkBodySchema. |
APIResponseDataObject<BulkCancelInvoiceResponse>APIError/api/v1/businesses/:businessId/invoices/:invoiceId/payments/:paymentId/cancel
auth: jwt (administrator | submit_invoices)Cancel a single fiscalised payment. Issues a cancellation row (Sale → Refund / Refund → Sale) with the same line items but BuyerTin set to the seller's TIN and ReferentDocumentNumber pointing back at the original SDC fiscal number, then dispatches it through the standard fiscalisation pipeline. Poll the returned jobId — on success the original payment is marked cancelled by the consumer. Fires INVOICE_PAYMENT_CANCELLATION_REQUESTED audit.
handlers: InvoicesController.cancel
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
invoiceId pathuuid | yes | — | Parent invoice UUID. |
paymentId pathuuid | yes | — | Payment UUID to cancel. Must be fiscalised and not already in flight. |
APIResponseDataObject<CancelInvoiceResponse>APIErrorAPIError/api/v1/businesses/:businessId/invoices/:invoiceId/payments/:paymentId/copy
auth: jwt (administrator | submit_invoices)Per-payment Copy. Inserts a new Invoices row with InvoiceType='COPY', CopiesInvoiceId pointing at the source invoice, totals scaled to the source payment's amount, plus a synthetic InvoicePayments row carrying CopiesPaymentId. Source payment's SDC FiscalInvoiceNumber is the V-SDC referent on the new submission; TransactionType is preserved (Copy of Sale → Sale, Copy of Refund → Refund). One-time per source payment (retry of a failed copy allowed). Immediately dispatches for fiscalisation and fires INVOICE_COPY_REQUESTED audit.
handlers: InvoicesController.copy
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
invoiceId pathuuid | yes | — | Source invoice UUID. |
paymentId pathuuid | yes | — | Source payment UUID. Must be a fiscalised payment under a supported invoice type. |
APIResponseDataObject<CopyInvoiceResponse>APIErrorAPIErrorAPIError/api/v1/businesses/:businessId/invoices/:invoiceId/payments/:paymentId/refund
auth: jwt (administrator | submit_invoices)Per-payment Refund. Inserts a new Invoices row with TransactionType='REFUND' and InvoiceType inherited from the source (Normal → Normal Refund, Advance → Advance Refund), RefundsInvoiceId pointing at the source invoice, totals scaled to the source payment's amount, plus a synthetic InvoicePayments row carrying RefundsPaymentId. Source payment's SDC FiscalInvoiceNumber is the V-SDC referent on the new submission. Only valid on a fiscalised SALE payment under a Normal or Advance invoice — refunding a refund is rejected. One-time per source payment (retry of a failed refund allowed). FE button is hidden on Normal/Advance (only surfaced for PROFORMA quotes); backend stays permissive so the service-layer REFUNDABLE_TYPES guard remains the source of truth. Fires INVOICE_REFUND_REQUESTED audit.
handlers: InvoicesController.refund
| name | required | default | description |
|---|---|---|---|
businessId pathuuid | yes | — | Target business UUID. |
invoiceId pathuuid | yes | — | Source invoice UUID. |
paymentId pathuuid | yes | — | Source SALE payment UUID. Must be fiscalised and not already refunded. |
APIResponseDataObject<RefundPaymentResponse>APIErrorAPIErrorAPIError