Skip to main content

Invoice Lifecycle

Overview

The invoice flow ties together collection, customer management, payment links, and Tanzania Revenue Authority (TRA) fiscal receipts. A merchant creates an invoice, MALIPOPAY generates a shareable payment link, the customer pays via any channel, the merchant receives confirmation, and MALIPOPAY issues the TRA fiscal receipt automatically.

Sequence diagram

sequenceDiagram
autonumber
participant M as Merchant App
participant API as Central API
participant URL as URL Shortener
participant SMS as SMS Service
participant C as Customer
participant GW as Gateway Service
participant TRA as TRA Service

M->>API: POST /invoice<br/>apiToken, customer, items, amount
API->>API: validate, compute totals<br/>+ VAT
API->>URL: create short link<br/>for payment page
URL-->>API: shortCode
API-->>M: 201 { invoiceId, shortUrl }

M->>API: POST /invoice/send<br/>channel: sms | whatsapp
API->>SMS: send notification<br/>with short link
SMS->>C: SMS / WhatsApp with link

C->>API: GET /invoice/{shortCode}<br/>(payment page)
API-->>C: render hosted checkout
C->>API: POST /payment/collection<br/>(from hosted checkout)
API->>GW: route to operator
GW-->>API: payment confirmed

API->>API: mark invoice PAID<br/>generate internal receipt
API->>TRA: POST fiscal receipt request
TRA-->>API: fiscal receipt number + QR
API->>M: webhook { invoiceId, status: PAID, fiscalReceipt }
API->>SMS: send receipt to customer
SMS->>C: receipt SMS / WhatsApp

Key endpoints

StepEndpointNotes
1POST /invoiceCreate a draft invoice with line items, customer, tax.
6POST /invoice/sendDispatch the payment link to the customer. Channels: sms, whatsapp, email.
8GET /invoice/{shortCode}Hosted checkout page (rendered for the customer, not for the merchant).
10POST /payment/collectionCalled by the hosted checkout when the customer picks a channel and pays.
14POST <merchant webhook>Final invoice status push with fiscalReceipt attached.

TRA integration

For merchants registered with TRA, MALIPOPAY automatically requests a fiscal receipt from the TRA service the moment the payment completes. The fiscal receipt arrives as part of the merchant webhook payload and also as a separate endpoint:

GET /invoice/{invoiceId}/tra/receipt

If the TRA service is unreachable (e.g. TRA downtime), the invoice is marked PAID but fiscalReceipt is null. MALIPOPAY automatically retries the TRA request every 15 minutes for up to 24 hours. The merchant can manually retrigger with:

POST /tra/retry/{invoiceId}

States

DRAFT → SENT → PAID → [FISCAL_PENDING →] FISCAL_ISSUED

VOIDED

A DRAFT invoice can be edited; once SENT it's immutable. VOIDED is terminal: a voided invoice can never be paid.

Cancellation

To cancel an invoice before payment:

POST /invoice/mark-voided
{ "invoiceId": "...", "reason": "customer request" }

After payment, refunds must go through the disbursement flow. See Payment Disbursement.