Skip to content
Blog|Developer|India

Generating GST invoices via API for Indian SMBs and brokers.

Mezdoc team||8 min read
Loan Agreement

This loan is extended by lender.name to borrower.name.

IF coverage > 50000

Every Indian SMB I have worked with eventually has the same realisation about invoicing. It started with a Word template, became an Excel sheet, ended up as a Tally export, and at some point the founder typed twenty invoices manually because the accountant was on leave. By the time the team is doing 500 invoices a month, the spreadsheet has become the bottleneck and the GST notices are starting to land for missing fields.

This post walks through what a clean, API-driven GST invoice path looks like. Not a product pitch, just the fields that are actually mandatory, the e-invoice IRN flow, and where a templating layer like Mezdoc sits in it.

What makes an invoice a GST invoice

A GST tax invoice has a defined set of mandatory fields under the GST Act and the CGST Rules. Skip one and the invoice is technically invalid for input tax credit purposes for the buyer. The mandatory set:

  • Supplier name, address, and GSTIN.
  • Invoice number, dated and serially sequential per financial year.
  • Invoice date.
  • Recipient name, address, and GSTIN (if registered).
  • For B2B: place of supply, with state name and state code.
  • HSN code (for goods) or SAC code (for services), at the line level.
  • Description, quantity, unit, unit price, and total per line.
  • Taxable value per line.
  • Tax rate, split into CGST, SGST, IGST, UTGST as applicable.
  • Total invoice value, in figures and words.
  • Whether tax is payable on reverse charge.
  • Supplier's signature or digital signature.

The Word template most teams started with has maybe seven of these. That is the source of half the GST notices.

The e-invoice (IRN) layer on top

Above a threshold turnover, businesses must also generate an Invoice Reference Number (IRN) through the government's Invoice Registration Portal (IRP) before the invoice is considered valid. The flow:

  • You generate the invoice in your system.
  • You send the invoice JSON to the IRP, which validates it and returns an IRN plus a signed QR code.
  • You print or render the final PDF with the IRN and QR code embedded.
  • The IRP simultaneously pushes the invoice data to the GST returns system and the e-way bill system.

Skip the IRN and the invoice is not valid for the buyer. Generate the IRN after the buyer has already received a different PDF and you have two non-matching documents floating around. The PDF rendering and the IRN call have to be deterministic and tightly coupled.

The PDF the buyer sees and the JSON the government receives have to be the same invoice. If they are not, you have a problem nobody finds until reconciliation.

What a clean API path looks like

Here is the shape of an invoice flow that survives audit, scales past a thousand invoices a month, and does not require an ops person to copy-paste anything.

POST /v1/templates/gst_tax_invoice_v3/submissions
curl https://api.mezdoc.com/v1/templates/gst_tax_invoice_v3/submissions \
  -H "Authorization: Bearer $MEZDOC_KEY" \
  -H "Idempotency-Key: inv_2026_05_INV-00481" \
  -d '{
    "environment": "production",
    "data": {
      "invoice_number":     "INV-2026-00481",
      "invoice_date":       "2026-05-19",
      "supplier": {
        "name":             "Acme Logistics Pvt Ltd",
        "gstin":            "27AABCA1234C1Z5",
        "address":          "Plot 14, MIDC, Pune 411019, Maharashtra"
      },
      "recipient": {
        "name":             "Northstar Insurance Brokers",
        "gstin":            "29AAACN9876H1Z2",
        "address":          "MG Road, Bengaluru 560001, Karnataka",
        "place_of_supply":  "29-Karnataka"
      },
      "line_items": [
        { "hsn": "9967", "description": "Freight forwarding services - May 2026", "qty": 1, "unit_price": 84500, "tax_rate": 18 }
      ],
      "totals": {
        "taxable_value":    84500,
        "igst":             15210,
        "total":            99710,
        "in_words":         "Ninety nine thousand seven hundred and ten only"
      },
      "reverse_charge":     false
    }
  }'

A few things to notice about this shape:

  • The idempotency key is the invoice number. Retry safely, never get two invoices with the same number.
  • Line items are an array. The template renders the table with a loop, no matter how many items you send.
  • The place of supply is sent with the state code so the template can decide between IGST (inter-state) and CGST+SGST (intra-state) at render time.
  • The totals block carries the "in words" string. You can compute this yourself or let the template engine compute it on render.

How Mezdoc handles e-invoice IRN

We do not generate IRNs ourselves. That is the IRP's job and they own the relationship with your GSP. What we do is wire the flow so the IRN lands in the PDF without anyone copy-pasting:

  • You call the IRP first with the invoice JSON. You get back an IRN and a signed QR code.
  • You call our submission API with the invoice JSON plus the IRN and the QR code.
  • Our template renders the final PDF with the IRN at the top and the QR code in the corner.
  • The PDF you send to the buyer carries the IRN. The audit log carries the IRN. Reconciliation later is one SQL query.

For SMBs below the IRN threshold, you just call our submission API directly and the invoice is the artefact.

Where the savings actually compound

Templates fix the schema, not the fields

When the GST council updates the invoice format, you publish v4 of the template. Every invoice since the change carries `template_version: 4`. Old invoices stay on v3. Auditors see the version pin and stop asking why the format differs between April and June.

Multi-state without multi-template

The same template handles inter-state and intra-state invoices through one condition on the place of supply. You do not maintain a separate "Karnataka invoice" and a "Maharashtra invoice". The render branch picks the right tax split.

Reissue is one API call

Customer asks for a copy of the May invoice. You call the API with the same idempotency key and get back the same PDF, with the same IRN, byte-for-byte. No version drift, no "is this the latest" back and forth.

Annexure invoices for insurance and broking

Insurance brokers and freight forwarders often issue invoices with annexures that list the underlying policies or shipments. The template handles this with a per-row loop and a separate annexure page that is only included when the line count crosses a threshold. One template, two rendering modes.

What this does not do

  • It does not file your GSTR-1. That is your GSP's job.
  • It does not reconcile your books. That is Tally or Zoho or your in-house accounting system.
  • It does not assess HSN classification. You still need to know whether your service is 9967 or 9985.

It does one thing well, which is produce a clean, mandatory-field-complete, version-pinned GST invoice PDF on every API call, with the IRN baked in when you supply it.

The US parallel

The closest US equivalent is the sales-tax invoice plus the 1099-MISC / 1099-NEC year-end packet. There is no national e-invoice portal in the US (each state runs its own sales tax regime), but the templating problem is identical: mandatory fields per jurisdiction, a deterministic PDF that must match what was sent to the customer, and an annual reconciliation against what was reported to the IRS. US teams use the same Mezdoc template engine for their invoices and their 1099-NEC bulk runs in January. The fields differ, the version-pinning, idempotency, and reissue mechanics are the same.

A practical starting point

  • Pick the invoice format you use today. Probably a Word doc or an Excel sheet with merged cells.
  • Map every visible field to a snake-case alias. Make sure every mandatory field from the list above has a place to live.
  • Recreate the layout in a Mezdoc dynamic template. Variables for the header, loop for the line items, conditional for IGST vs CGST+SGST.
  • Run ten test submissions with real invoice data you control. Diff the PDFs against your current invoices, fix what is off.
  • Wire the trigger into your invoice-creation event. The next invoice your team raises is rendered through the API.

A day or two of setup buys you reliable, audit-ready invoices for the rest of the financial year. See the live demo if you want to feel the API shape first.

Live demo
One template. Fill it two ways.
Tokenized link for the customer
4/4 fields filled
Generated PDF preview
M
Meridian Insurance
Policy declaration
Policy number
POL-2026-00481
Named insured
Acme Logistics Pvt Ltd
Effective date
01 Jun 2026
Sum insured
₹15,00,000
Authorised signatory

Same template. Your code or your customer can fill it. The audit trail records both.

Open the full demo