You quote USD 2,000 US client. Wise INR 1,66,000 vs PayPal 1,62,000. Client GST? you Export, no GST? CA LUT? You log INR 1,66k Income without invoiceId src/lib/db/schema.ts:98 — next month FIRC missing, bank purpose code?, hunt email 40 mins.
USD to INR isn't conversion. It's invoice → fee → FIRC → GST → linked transaction.
Why USD to INR Leaks 2-4% Quietly
Three gaps tax foreign income:
- Fee opacity.
Wise 0.6%vsPayPal 4.5% + FX 3%—USD 2000 ×3% = USD 60 = ₹5klost per invoice, invisible in SheetUSD 2000 → 166000withoutfeeline.invoices items jsonbsrc/lib/db/schema.ts:74can holdPlatform fee -₹5k; SheetsAmounttext can't. - Currency mismatch.
invoices currency varchar(10)src/lib/db/schema.ts:70USDbuttransactions amount numericsrc/lib/db/schema.ts:92logsINR 166000— FX delta₹4kuntracked →2.3%leak. - Compliance gaps.
FIRC+purpose P0802+LUTneedsinvoiceNumber uniquesrc/lib/db/schema.ts:67+issueDate+amount+clientIdchain. Sheet PDF withouttaxType none|igstsrc/lib/db/schema.ts:77+invoiceId→ bankReissue LUTdelay5d.
Without currency + fee + FIRC linked, you celebrate USD 2000 and keep USD 1920.
Platform Fees — The Real Math on USD 2,000
| Platform | Fee | Net on USD 2,000 = ₹1,70,000 | FIRC |
|---|---|---|---|
| Wise | 0.43% + USD 4 | ₹1,68,900 fee ₹1,100 | Auto |
| Payoneer | 3% | ₹1,64,050 fee ₹5,950 | On request |
| PayPal | 4.4% + FX 3% | ₹1,57,250 fee ₹12,750 | No |
| SWIFT | USD 20 + FX 2% | ₹1,65,300 fee ₹4,700 | Auto |
₹1,68,900 vs ₹1,57,250 = ₹11,650 per USD 2000 — 6.8% swing. Track Platform Fee transactions src/app/api/transactions/route.ts:91 per payment.
The Linked USD → INR Graph
invoices(currency USD|INR src/lib/db/schema.ts:70, amount numeric src/lib/db/schema.ts:69, taxType none|igst src/lib/db/schema.ts:77, taxRate numeric(5,2) src/lib/db/schema.ts:76, items jsonb src/lib/db/schema.ts:74)
transactions(currency INR, amount numeric, category Invoice Payment|Platform Fee, invoiceId fk src/lib/db/schema.ts:98, clientId fk, date timestamp src/lib/db/schema.ts:96)
clients(id, name, email)
investments? not needed here, but wealth after net
cron flips sent→overdue src/app/api/cron/daily/route.ts:46 keeps USD receivables visibleWorkflow that keeps proof:
- Invoice USD or INR.
POST /api/invoices currency:USD amount:2000 taxType:nonefor exportLUT— orcurrency:INR 170000.items jsonbholdsDesign USD 2000 ×1. ServercomputedTotalsrc/app/api/invoices/route.ts:127ensures typednumeric. - Send via portal.
draft→sent+sendInvoiceEmail portalsrc/lib/emails/send.ts:347— client paysWiseNET 7. - Log two transactions.
POST type:income category:Invoice Payment INR 168900 invoiceId+POST category:Platform Fee 1100 INR—syncInvoicePaidStatussrc/app/api/transactions/route.ts:44flipssent→paid. Net₹1,67,800clear. - Attach FIRC.
vaultItems category othersrc/lib/db/schema.ts:123name FIRC INV-014linkedclientIdsrc/lib/db/schema.ts:133— CA finds in10s.
Excel vs QuickBooks vs FreshBooks vs RunoSO — FX Truth
| Need | Excel/Sheets | QuickBooks | FreshBooks | RunoSO | ||
|---|---|---|---|---|---|---|
| Multi-currency | Text USD 2000 — no FX ledger | Multi-currency US | Multi-currency | invoices currency varchar(10) src/lib/db/schema.ts:70 + transactions currency separate — quote USD, receive INR linked | ||
| Fee tracking | INR 166k flat, fee hidden | Expense Bank Fee manual | Expense manual | transactions category Platform Fee + invoiceId → net per invoice auto | ||
| Auto compute | =2000*85 manual FX err | Auto | Auto | Server taxable*rate/100 src/app/api/invoices/route.ts:121 + computedTotal src/app/api/invoices/route.ts:127 for INR GST side; USD taxType none zeroed correctly | ||
| Overdue USD | Overdue? YES manual | Flag | Reminder | Cron sent→overdue lt(dueDate, now) src/app/api/cron/daily/route.ts:49 30 3 * * * vercel.json:4 + daily digest — no USD receivable missed | ||
| Recurring USD retainer | Copy USD 1500 row, dup | Recurring US | Recurring | `recurringInterval monthly | quarterly | yearly src/lib/utils/recurring.ts:5 clones currency USD amount taxType` correctly |
| India proof | No LUT, no FIRC link | US 1099, not FIRC | US | invoiceNumber unique + issueDate + transactions invoiceId chain = FIRC/LUT pack ready; free 5/mo src/lib/plans/limits.ts:28 → Solo ∞ |
Excel hides FX fee; QuickBooks/FreshBooks auto USD but US proof not FIRC purpose P0802. RunoSO keeps USD→INR net + fee + invoiceId as graph.
GST on Export — Don't Guess
- With LUT:
taxType none taxRate 0src/app/api/invoices/route.ts:29—Export under LUT without IGSTitemsnoteLUT No: ARN.... Zero invoiceamount 2000 USD, nocgst_sgst|igst. - Without LUT:
taxType igst taxRate 18ontaxable INR value—IGST 18%payable, claim refund. Most freelancers getLUTFeb-Mar for next FY — setrecurring yearlybefore FY roll.
Log correct at POST /api/invoices — March GSTR 1 export + LUT reconciliation takes 5m, not 2h.
Mistakes That Cost USD Freelancers
Quoting INR but logging USD hides ₹4k leak — quote USD 2000 then split INR net + Platform Fee. One Income without fee split hides true margin — always split. No invoiceId → bank Which invoice? → always link.
RunoSO invoices USD, logs INR net + fee as linked transactions, keeps invoiceId for FIRC — so every dollar's net is known, not guessed.
→ Keep More of Every Dollar — Try RunoSO Free
By Gautam Parmar — solo founder. Foreign payments that stay profitable and proof-ready.
Keep Reading
- Quote right: How to Quote in USD & Get Paid in INR.
- GST: GST Invoicing for Indian Freelancers.
- Fast invoice: Professional Invoice 60 Seconds.
FAQ
Wise vs PayPal for USD 1500? Wise ₹1,26k net vs PayPal ₹1,17k on USD 1500 @85 — ₹9k diff monthly ₹1.08L/yr. Track transactions category Platform Fee for 3 months, decide with data not anecdote.
Do I charge GST on USD invoices? With valid LUT, taxType:none taxRate 0 — zero-rated export. Without LUT, taxType:igst 18% and claim refund. Set at POST /api/invoices src/app/api/invoices/route.ts:30 — not March fix.
How to prove FIRC quickly? invoices invoiceNumber + issueDate + amount linked transactions invoiceId src/app/api/transactions/route.ts:98 + vaultItems stored FIRC PDF src/lib/db/schema.ts:125 = 3-file pack bank loves. GET /api/transactions?invoiceId=xxx src/app/api/transactions/route.ts:87 pulls chain instantly.



