The compliance flow
Money in, auto-FIRA, reconcile, tax calc, ITR-4 prefill, yield allocation — end to end.
This is the core loop Lumeo runs on every cross-border payment. It is the single sequence that justifies the product — everything downstream (FIRA, compliance, tax exports) depends on it running correctly, every time.
The sequence
Step-by-step
1. Payment confirmed
A payment reaches CONFIRMED/COMPLETED status — either from a Crossmint card/wallet delivery or an OnMeta UPI/IMPS settlement. This is the trigger for everything that follows. The webhook event at this boundary is payout.settled.
2. Auto-FIRA
A Foreign Inward Remittance Advice is generated the moment the payment is confirmed, with no manual bank request. The FIRA captures:
- The remitting bank and country
- The INR equivalent at the settlement rate
- The RBI FEMA purpose code
- The timestamp of confirmation
The fira.generated webhook fires here. Fetch the document via GET /api/v1/compliance/fira/:firaId.
3. Ledger entry
The payment is posted to the TigerBeetle-backed double-entry ledger as a balanced set of journal entries: the user's settled account is credited, the platform float account is debited, and any FX spread or fee is split off into its own entry. This makes reconciliation provable — the ledger never has a net imbalance.
4. Reconciliation
The payment is matched against its source: the invoice reference supplied in the initiate call (invoiceRef), the FIRA that was just generated, and the ledger entry from step 3. When all three link to the same transaction, the payment is considered reconciled. The reconciliation.completed webhook fires.
If auto-matching fails (e.g. the invoiceRef was missing or doesn't match any known invoice), the payment enters a PENDING_RECONCILIATION state. See Reconcile a cross-border payment for the manual resolution flow.
5. Tax calculation
Once reconciled, GST applicability is computed from the transaction itself:
- If the user has filed a Letter of Undertaking (LUT), the payment is zero-rated for GST — no 18% levy applies.
- Income tax liability under Section 44ADA (presumptive taxation) is updated on the year-to-date total.
These values are always derived from the reconciled ledger entry, not from an estimate or a periodic batch job.
6. ITR-4 prefill
The year-to-date income total (in INR, at settlement rates) is written to the ITR-4 prefill record. At filing time, the user can export a pre-populated ITR-4 (44ADA) return directly from the compliance API. Fetch it via GET /api/v1/compliance/itr4/prefill.
7. Yield allocation
If the user has a yield policy configured, any settled balance above their working-capital threshold is allocated automatically to the configured yield-bearing instrument. The yield.allocated webhook fires.
Why this order matters
- FIRA before reconciliation: FIRA is the proof-of-remittance document that reconciliation references. You can't mark a cross-border payment as reconciled without it.
- Reconciliation before tax: Tax liability is calculated on reconciled income, not on unmatched payment events. A payment that hasn't been reconciled doesn't affect your tax position yet.
- Everything from the ledger: No compliance artifact (FIRA, GST summary, ITR-4 prefill) is derived from a summary table or an export — they all trace back to a specific, immutable ledger entry.
Where this shows up in the API
| Step | Endpoint group | Webhook event |
|---|---|---|
| Payment confirmed | Payments | payout.settled |
| Auto-FIRA | Compliance | fira.generated |
| Ledger entry | Ledger | — |
| Reconciliation | Ledger | reconciliation.completed |
| Tax calc | Tax | tax.updated |
| ITR-4 prefill | Compliance | — |
| Yield allocation | — | yield.allocated |