Agent Playbook, build tutorial

How to Build an AI Agent for GST Invoicing and Reconciliation

A walkthrough of how to build a billing agent for India: it generates a GST-correct invoice, registers the IRN and signed QR, sends it with a payment link, reconciles incoming payments and your GSTR-2B so input tax credit stops leaking, and chases overdue invoices politely until they are paid. Every code step is shown in three frameworks, Google ADK, the Claude SDK, and LangGraph, so you can build it on the stack your team already knows. The code here is the agent's core logic; standing it up in production also means adding the setup, integrations, and hardening around it.

Why manual GST billing leaks money

Billing in India is invoicing, e-invoicing, collection, and tax reconciliation all at once, and each one quietly costs you. Invoices go out late and get chased later, so cash sits with customers: as of March 2024, a reported Rs 7.34 lakh crore was owed to Indian MSMEs in delayed payments, down from Rs 10.7 lakh crore in 2022 but still enormous (GAME, FISME, and C2FO). Meanwhile input tax credit leaks whenever your books and GSTR-2B do not match, and a missed IRN can make an invoice invalid.

A spreadsheet and reminders do not scale to that. An agent is different: it gets the GST right by construction, registers the IRN at issue, matches every payment, reconciles 2B every cycle, and chases on a steady, polite cadence, escalating to a human only when an invoice is disputed or an account needs a call.

Pick a framework: ADK, Claude SDK, or LangGraph

You do not build the agent loop from scratch. A framework gives you the moving parts, and you supply the logic: a step is a model plus an instruction plus a few typed tools. The code tabs on the build steps show the same reconcile, chase, and dispute flow three ways.

Google ADK composes the steps with a SequentialAgent and a Runner, the Claude SDK drives a tool-use loop, and LangGraph builds an explicit graph. The GST maths, the IRP registration, the bank-feed matching, and the GSTR-2B reconciliation are deterministic and identical in all three; only the orchestration and the model calls differ.

The architecture

Every invoice flows through one loop: generated and registered, issued and tracked, reconciled, then either closed when paid or chased when overdue. A dispute pulls it to a human, and guardrails for idempotency, consent, and audit wrap the whole thing.

1 to 2. Generate and register GST invoice + IRN, QR 3. Issue and track send, due date, pay link 4. Reconcile payments + GSTR-2B 5. Paid on time? by the due date? 6. Close and book mark paid, reconcile ITC Chase WhatsApp, escalating 7. Monitor DSO, ITC at risk Guardrails idempotency opt-in audit log yes, paid overdue paid after chase feedback loop

Before you build: prerequisites

Inputs and access

Your GSTIN and place of supply, a GSP or ASP for the IRP, a bank feed or statement source, your GSTR-2B, and the purchase register.

Systems to connect

A model API key (Gemini, Claude, or both), your accounting or ERP (Tally, Zoho Books, Vyapar), a payment-link provider, and WhatsApp plus email.

Governance

Credit terms and chase cadence, opt-in and DPDP Act 2023 consent, an audit log, and who signs off on disputes and write-offs.

Setup: install and keys

Install the packages and set your Gemini key. That is enough to run the runnable file below, which builds a GST-correct invoice and drafts a chase locally. For production you also connect, with provider-specific credentials, your GSP or ASP for IRN registration (ClearTax, Masters India), your bank feed for reconciliation, and WhatsApp for chasing.

Shell (install and key)
# Python 3.10 or newer
python -m venv venv && source venv/bin/activate

# The runnable path below uses Google ADK + Gemini:
pip install google-adk google-genai

# Your Gemini key from aistudio.google.com/apikey:
export GEMINI_API_KEY="your-key-here"

The stack, and why each piece

Layer Pick Why
Invoice generation Your accounting tool API (Tally, Zoho Books, Vyapar, ClearTax) Create the invoice with the right GST fields: HSN or SAC, place of supply, and the correct CGST and SGST or IGST split.
E-invoicing IRP via a GSP or ASP (ClearTax, Masters India, GSTN) Register the invoice to get the IRN and signed QR. This is mandatory for B2B once turnover crosses Rs 5 crore, and the invoice is invalid without it.
Model Gemini 2.5 Flash, Claude, or any model behind LangChain Reads bank narrations, drafts on-brand chase messages, and classifies customer replies. The code tabs show the same call in all three.
Agent framework Google ADK, the Claude SDK, or LangGraph Drives each invoice through issue, reconcile, chase, and the dispute branch. Pick the one your team runs; the logic is identical.
Data Your ERP API + Postgres Holds invoices, payments, the purchase register, GSTR-2B, and an audit trail of every issue, chase, and match.
Messaging WhatsApp Cloud API and email Send the invoice and chase overdue amounts where the customer actually reads, with a payment link attached, opt-in respected.

Build it, step by step

The model and orchestration steps show the same logic in Google ADK, the Claude SDK, and LangGraph. Use the tabs to switch. The GST, IRP, and reconciliation steps are deterministic Python and identical everywhere. These are the building blocks, and they call your own systems (the ERP, the GSP, the bank feed) by name; the complete file you can run today is in "Put it together" below.

1

Generate a GST-correct invoice

Getting the tax right is the whole job, and it is deterministic code, not a model guess. From the order, the agent computes the line tax at the correct rate, then splits it: intra-state supply becomes CGST plus SGST, and inter-state becomes IGST, decided by comparing the seller and buyer place of supply. It carries the HSN code for goods or SAC for services, applies GST rounding, and builds the invoice through your accounting tool's API. This is the same in every framework.

Python (deterministic)
from decimal import Decimal, ROUND_HALF_UP

def build_invoice(order, seller_state, buyer_state) -> dict:
    cgst = sgst = igst = Decimal(0)
    intra = seller_state == buyer_state     # intra -> CGST+SGST, else IGST
    for li in order.items:
        tax = li.qty * li.rate * li.gst_rate / 100
        if intra: cgst += tax / 2; sgst += tax / 2
        else:     igst += tax
    base = sum(li.qty * li.rate for li in order.items)
    total = (base + cgst + sgst + igst).quantize(Decimal("1"), ROUND_HALF_UP)
    return {"items": order.items, "cgst": cgst, "sgst": sgst,
            "igst": igst, "total": total}
2

Register the e-invoice (IRN) and e-way bill

For B2B invoices once your turnover crosses Rs 5 crore, e-invoicing is mandatory: the invoice has to be registered on the Invoice Registration Portal, which returns an Invoice Reference Number and a digitally signed QR code. Without them the invoice is not valid for GST. The agent calls the IRP through your GSP or ASP at issue, stores the IRN and QR, and generates the e-way bill when goods cross the value threshold. This is a plain API call, the same in every framework.

Python (IRP / GSP API)
# irp is your GSP/ASP client (ClearTax, Masters India, GSTN).
def register_einvoice(inv: dict) -> dict:
    resp = irp.generate_irn(
        seller_gstin=inv["seller_gstin"],
        buyer_gstin=inv["buyer_gstin"],
        payload=to_irp_schema(inv))          # IRP's mandated JSON shape
    inv["irn"] = resp["Irn"]
    inv["signed_qr"] = resp["SignedQRCode"]  # printed on the PDF
    if needs_eway(inv):                      # goods over the value threshold
        inv["eway_bill"] = irp.generate_eway(inv)
    return inv
3

Issue, attach a payment link, and track the due date

Now send it where the customer will see it. The agent renders the PDF with the IRN and QR on it, creates a payment link tied to the invoice number, and delivers both over WhatsApp or email. It records the invoice as issued with its due date computed from your payment terms, so the clock that drives reconciliation and chasing starts the moment it goes out.

Python (render + send)
def issue(inv: dict):
    pdf = render_pdf(inv)                     # IRN + QR on the document
    link = payments.create_link(inv["total"], ref=inv["number"])  # UPI / card
    wa.send_document(inv["buyer_phone"], pdf,
                     caption=f"Invoice {inv['number']}. Pay here: {link}")
    ledger.record(inv, status="issued", due=inv["date"] + inv["terms"])
4

Reconcile incoming payments

Matching money to invoices is where hours disappear. The agent reads each credit from the bank feed, first trying an exact match on the invoice number in the remittance narration plus the amount, then a fuzzy match on the same payer and amount against open invoices. A confident match marks the invoice paid with the UTR; anything it cannot match cleanly goes to a human queue instead of being guessed. Deterministic, and the same in every framework.

Python (deterministic match)
def reconcile_payment(txn) -> None:           # one bank-feed credit, with UTR
    # 1) exact: invoice number in the narration + matching amount
    inv = ledger.find(number=extract_ref(txn.narration), amount=txn.amount)
    # 2) fuzzy: same payer + amount, open invoice, within a date window
    inv = inv or ledger.fuzzy_match(payer=txn.payer, amount=txn.amount)
    if inv:
        ledger.mark_paid(inv, utr=txn.utr, on=txn.date)
    else:
        review_queue.add(txn, reason="unmatched_receipt")   # human decides
5

Reconcile GSTR-2B so you do not lose input tax credit

Input tax credit is real money, and it leaks when what the portal shows does not match what you booked. The agent compares each supplier invoice in your auto-drafted GSTR-2B against your purchase register, keyed on supplier GSTIN and invoice number. Anything in 2B you have not booked is credit to claim; any tax-amount mismatch is ITC at risk. This runs every cycle, so nothing is found the week after you have filed.

Python (deterministic)
def reconcile_2b(gstr2b: list, purchase_register: list) -> None:
    booked = {(p["supplier_gstin"], p["invoice_no"]): p for p in purchase_register}
    for row in gstr2b:
        key = (row["supplier_gstin"], row["invoice_no"])
        if key not in booked:
            flag(row, "in_2b_not_booked")    # claim it, or fix your records
        elif abs(row["tax"] - booked[key]["tax"]) > 1:
            flag(row, "tax_mismatch")        # ITC at risk until resolved
6

Chase overdue invoices, politely and on a cadence

Most invoices are not paid late on purpose, they are forgotten, so a steady, polite cadence collects more than sporadic angry calls. The cadence is deterministic, but the message itself is drafted by the model so it reads on-brand rather than robotic. The tabs show the same chase with the draft call in Gemini, Claude, and LangChain. Every chase is logged so it never sends twice, and the final step escalates to a human.

from google import genai
client = genai.Client()
CADENCE = [("due", "friendly"), (3, "reminder"), (7, "firm"), (15, "final")]

def chase(inv: dict):
    days_over = (today() - inv["due"]).days
    for trigger, tone in CADENCE:
        if reached(days_over, trigger) and not chased(inv, tone):
            text = client.models.generate_content(
                model="gemini-2.5-flash",
                contents=[f"Write a {tone}, on-brand payment reminder.", str(inv)]).text
            wa.send(inv["buyer_phone"], text, attach=payment_link(inv))
            log_chase(inv, tone)
            if tone == "final": escalate_to_human(inv)
from anthropic import Anthropic
client = Anthropic()
CADENCE = [("due", "friendly"), (3, "reminder"), (7, "firm"), (15, "final")]

def chase(inv: dict):
    days_over = (today() - inv["due"]).days
    for trigger, tone in CADENCE:
        if reached(days_over, trigger) and not chased(inv, tone):
            text = client.messages.create(model="claude-opus-4-8", max_tokens=300,
                messages=[{"role": "user",
                           "content": f"Write a {tone}, on-brand payment reminder for {inv}."}]
                ).content[0].text
            wa.send(inv["buyer_phone"], text, attach=payment_link(inv))
            log_chase(inv, tone)
            if tone == "final": escalate_to_human(inv)
from langchain_google_genai import ChatGoogleGenerativeAI
llm = ChatGoogleGenerativeAI(model="gemini-2.5-flash")   # or ChatAnthropic(...)
CADENCE = [("due", "friendly"), (3, "reminder"), (7, "firm"), (15, "final")]

def chase(inv: dict):
    days_over = (today() - inv["due"]).days
    for trigger, tone in CADENCE:
        if reached(days_over, trigger) and not chased(inv, tone):
            text = llm.invoke(f"Write a {tone}, on-brand payment reminder for {inv}.").content
            wa.send(inv["buyer_phone"], text, attach=payment_link(inv))
            log_chase(inv, tone)
            if tone == "final": escalate_to_human(inv)
7

Handle disputes and partial payments on reply

A reply changes everything, so the agent listens. When a customer responds over WhatsApp, the model classifies the intent into a fixed set: a promise to pay, a dispute, a partial payment, or other. A dispute immediately pauses chasing and routes to a human, because pursuing a contested bill makes things worse. A partial payment switches the invoice to expect-partial. The tabs show the same classification three ways.

from google import genai
from google.genai import types
client = genai.Client()
LABELS = ["will_pay", "dispute", "partial", "other"]

@app.post("/webhook/whatsapp")
def on_reply(payload: dict):
    msg = parse_whatsapp(payload); inv = ledger.find_by_phone(msg.sender)
    intent = client.models.generate_content(
        model="gemini-2.5-flash",
        contents=[f"Classify into {LABELS}: {msg.text}"]).text.strip()
    handle_intent(inv, intent)               # dispute -> hold + escalate, etc.
from anthropic import Anthropic
client = Anthropic()

@app.post("/webhook/whatsapp")
def on_reply(payload: dict):
    msg = parse_whatsapp(payload); inv = ledger.find_by_phone(msg.sender)
    res = client.messages.create(model="claude-opus-4-8", max_tokens=64,
        tools=[{"name": "set_intent", "input_schema": {"type": "object",
            "properties": {"intent": {"type": "string",
                "enum": ["will_pay", "dispute", "partial", "other"]}},
            "required": ["intent"]}}],
        tool_choice={"type": "tool", "name": "set_intent"},
        messages=[{"role": "user", "content": f"Classify intent: {msg.text}"}])
    handle_intent(inv, res.content[0].input["intent"])
from langchain_google_genai import ChatGoogleGenerativeAI
from pydantic import BaseModel
from typing import Literal

class Reply(BaseModel):
    intent: Literal["will_pay", "dispute", "partial", "other"]

classifier = ChatGoogleGenerativeAI(
    model="gemini-2.5-flash").with_structured_output(Reply)

@app.post("/webhook/whatsapp")
def on_reply(payload: dict):
    msg = parse_whatsapp(payload); inv = ledger.find_by_phone(msg.sender)
    handle_intent(inv, classifier.invoke(f"Classify intent: {msg.text}").intent)
8

Assemble the run, with idempotency and monitoring guardrails

Reconciliation and chasing run on a schedule over open invoices. ADK composes the reconciler and chaser under a SequentialAgent and a Runner, the Claude SDK runs them in a tool-use loop, and LangGraph builds the reconcile-then-chase graph. Whichever you pick, the same guardrails apply: key every issue on an idempotency token so a retry never creates a duplicate invoice or a second IRN, never chase the same invoice twice in a day, message only opted-in numbers, and write every action to an immutable audit log while tracking DSO and ITC at risk.

from google.adk.agents import SequentialAgent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService

ar_pipeline = SequentialAgent(name="ar_pipeline",
    sub_agents=[reconciler, chaser])         # each an LlmAgent with the tools above
runner = Runner(agent=ar_pipeline, app_name="ar",
                session_service=InMemorySessionService())

def guard(inv: dict) -> str | None:
    if ledger.has_irn(inv) or ledger.seen(inv["idempotency_key"]):
        return "duplicate"                   # never issue the same invoice twice
    if last_chase(inv) and hours_since(last_chase(inv)) < 24:
        return "too_soon"                    # never double-chase in a day
    return None
# Run nightly over open invoices via cron / Cloud Scheduler.
from anthropic import Anthropic
client = Anthropic()
TOOLS = [reconcile_tool, chase_tool]         # JSON tool schemas

def run_ar(messages: list):
    while True:
        resp = client.messages.create(model="claude-opus-4-8", max_tokens=1024,
                                       tools=TOOLS, messages=messages)
        if resp.stop_reason != "tool_use":
            return resp
        messages.append({"role": "assistant", "content": resp.content})
        for b in resp.content:
            if b.type == "tool_use":
                out = dispatch(b.name, b.input)
                messages.append({"role": "user", "content": [
                    {"type": "tool_result", "tool_use_id": b.id, "content": str(out)}]})
from langgraph.graph import StateGraph, START, END

g = StateGraph(dict)
g.add_node("reconcile", lambda s: {"open": reconcile_open(s["bank_feed"])})
g.add_node("chase",     lambda s: {"chased": [chase(inv) for inv in s["open"]
                                              if overdue(inv)]})
g.add_edge(START, "reconcile")
g.add_edge("reconcile", "chase")
g.add_edge("chase", END)
ar_pipeline = g.compile()      # invoke nightly via your scheduler

Put it together: run it end to end

Here is a runnable file. It builds a GST-correct invoice from a sample order and drafts a payment chase, then prints both. Replace SAMPLE_ORDER and the state codes with your data. Save it as main.py and run python main.py.

Python (full runnable file, ADK)
# main.py  --  run:  python main.py
# A runnable reference: builds a GST-correct invoice from a sample order and
# drafts a payment chase. Replace SAMPLE_ORDER and the state codes with your data.
import asyncio
from decimal import Decimal, ROUND_HALF_UP
from dataclasses import dataclass
from google import genai
from google.genai import types
from google.adk.agents import LlmAgent
from google.adk.runners import InMemoryRunner

client = genai.Client()                       # reads GEMINI_API_KEY

# ---- a sample order (replace with your order source) ----
@dataclass
class Item:
    desc: str; qty: float; rate: float; gst_rate: float

SAMPLE_ORDER = [Item("Widget", 50, 2000, 18)]
SELLER_STATE, BUYER_STATE = "KA", "MH"        # different states -> IGST
# ---------------------------------------------------------

def build_invoice() -> dict:
    """Compute a GST-correct invoice (CGST+SGST intra-state, else IGST)."""
    cgst = sgst = igst = Decimal(0)
    intra = SELLER_STATE == BUYER_STATE
    for li in SAMPLE_ORDER:
        tax = Decimal(str(li.qty * li.rate * li.gst_rate / 100))
        if intra: cgst += tax / 2; sgst += tax / 2
        else:     igst += tax
    base = Decimal(str(sum(li.qty * li.rate for li in SAMPLE_ORDER)))
    total = (base + cgst + sgst + igst).quantize(Decimal("1"), ROUND_HALF_UP)
    return {"base": float(base), "cgst": float(cgst),
            "sgst": float(sgst), "igst": float(igst), "total": float(total)}

def draft_chase(invoice_no: str, amount: float, days_overdue: int) -> str:
    """Draft a polite, on-brand payment reminder."""
    tone = "friendly" if days_overdue <= 3 else "firm"
    return client.models.generate_content(
        model="gemini-2.5-flash",
        contents=[f"Write a {tone}, one-paragraph payment reminder for invoice "
                  f"{invoice_no}, amount Rs {amount}, {days_overdue} days overdue."]).text

agent = LlmAgent(
    name="billing_agent", model="gemini-2.5-flash",
    instruction=("Call build_invoice and report the GST split and total. Then call "
                 "draft_chase for invoice INV-1 using that total, 7 days overdue, "
                 "and show the drafted message."),
    tools=[build_invoice, draft_chase])

async def main():
    runner = InMemoryRunner(agent=agent, app_name="billing")
    session = await runner.session_service.create_session(app_name="billing", user_id="demo")
    msg = types.Content(role="user", parts=[types.Part(text="Build the invoice and draft a chase.")])
    async for event in runner.run_async(user_id="demo", session_id=session.id, new_message=msg):
        if event.is_final_response():
            print(event.content.parts[0].text)

if __name__ == "__main__":
    asyncio.run(main())

You should see the GST split (CGST and SGST, or IGST for an inter-state supply) with the total, followed by a drafted reminder. IRN registration and bank reconciliation need your GSP and bank credentials, so they stay in the build steps above rather than this local demo.

The receivables view

Finance sees one screen: what is overdue, the invoice and its IRN, the reconciliation status, and a single action to take.

Receivables OVERDUE (3) Acme Traders15 days, final Globex Pvt7 days, firm Initech LLP3 days, reminder INVOICE NumberINV-2026-0441 IRNa4f9...registered AmountRs 1,24,500 Due15 days ago GST splitCGST+SGSTe-way billnot needed RECONCILIATION Paymentnot received Chases sent3 of 4 GSTR-2Bmatched Final notice due, escalate to a call Mark paid Call now

Build, buy, or no-code

Approach Best for Effort Cost Control
Custom agent (build in-house) You want your own rules, tight ERP and GSP fit, and control of the data High Build cost + API and model usage Full
GST suite (ClearTax, Zoho Books, Tally add-ons) Standard GST invoicing and e-invoicing, fast start Low Subscription per user or volume Medium
No-code (n8n, Make, Zapier) Low volume, simple reminders, a quick pilot Low Cheap, but brittle once GST logic grows Low

GST compliance and data protection

Compliance is built in, not bolted on. For B2B invoices above Rs 5 crore turnover, the agent registers the IRN and signed QR on the IRP at issue, generates the e-way bill when goods cross the value threshold, and keeps you inside the 30-day IRP reporting window that applies above Rs 10 crore turnover. The CGST, SGST, and IGST split follows the place of supply, and GSTR-2B is reconciled every cycle so input tax credit is claimed, not lost.

On the customer side, the contact details on every invoice are personal data under the DPDP Act 2023, so the agent chases only opted-in numbers on WhatsApp and falls back to email otherwise, honours a request to stop, and logs consent. Run the pipeline in your own cloud or on-premise where the sensitivity of invoices and bank data demands it.

The numbers

Benchmarks vary by source and should be treated as ranges, not promises. These are from neutral industry reports and the GST rules, not vendor marketing.

Metric Manual Agent
Money locked in delayed payments Rs 7.34 lakh crore owed to MSMEs as of March 2024 (GAME, FISME, C2FO), down from Rs 10.7 lakh crore in 2022 Every invoice is chased from day one, so less of yours sits unpaid
Days sales outstanding (DSO) Drifts upward because chasing is ad hoc and late Falls, because nothing is ever chased late and reminders never stop short
Input tax credit at risk GSTR-2B reconciled late or only sampled, so ITC quietly leaks Every line matched, and mismatches flagged before you file
E-invoice validity Risk of missing the 30-day IRP reporting window for Rs 10 crore+ turnover IRN registered at issue, so invoices stay valid for GST

Sources: GAME, FISME, and C2FO Delayed Payments Report 3.0 (March 2024); CBIC and GSTN e-invoicing rules. Figures are industry ranges and current thresholds.

What makes it fail

  • !Issuing without an IRN above the threshold, so the invoice is invalid.
  • !No idempotency, so a retry creates a duplicate invoice or double-chases.
  • !Getting CGST and SGST versus IGST wrong from a place-of-supply slip.
  • !Skipping GSTR-2B reconciliation, so input tax credit quietly leaks.
  • !Chasing a disputed bill, or messaging without opt-in, souring the customer.

A safe rollout

  1. Start read-only: reconcile payments and GSTR-2B and flag mismatches, a human acts.
  2. Add invoice generation and IRN registration for one customer segment, with approval.
  3. Turn on automated chasing with a gentle cadence and a human on the final step.
  4. Scale to all customers and entities, with DSO and ITC dashboards and alerts.

FAQs

General FAQs

Everything you need to know about the service and how it works. Can’t find an answer? Mail us at info@galific.com

  • Is GST e-invoicing mandatory for my business?
    If your aggregate annual turnover has crossed Rs 5 crore in any financial year since 2017-18, then yes, e-invoicing is mandatory for your B2B invoices, and has been since 1 August 2023. The agent registers each qualifying invoice on the Invoice Registration Portal at the moment of issue, so you get the IRN and signed QR every time. A few categories such as SEZ units, banks, and goods transport agencies are exempt.
  • Which framework should I use: ADK, the Claude SDK, or LangGraph?
    The right framework depends on your team, and the agent logic is the same in all three. The code tabs let you read the identical reconcile, chase, and dispute flow in Google ADK, the Anthropic SDK, and LangGraph and pick the one you already know. ADK and LangGraph are model-agnostic, so you can run Gemini or Claude under either; the GST maths and IRP calls are the same code regardless.
  • Does it generate the IRN, the QR code, and the e-way bill?
    Yes. It calls the IRP through your GSP or ASP to register the invoice and receive the Invoice Reference Number and the digitally signed QR, which are printed on the PDF, and it generates the e-way bill when goods cross the value threshold. Registering at issue also keeps you inside the 30-day IRP reporting window that applies to businesses above Rs 10 crore turnover.
  • How does it get the CGST, SGST, and IGST split right?
    By comparing the place of supply. An intra-state supply, where the seller and buyer states match, is taxed as CGST plus SGST, and an inter-state supply is taxed as IGST. This is deterministic code applied per line at the correct rate, with HSN or SAC carried through and GST-style rounding, so it is testable and auditable rather than a model guess.
  • Can it reconcile GSTR-2B so I do not lose input tax credit?
    Yes, and this is one of the biggest money savers. The agent matches every supplier invoice in your auto-drafted GSTR-2B against your purchase register on supplier GSTIN and invoice number, flags anything in 2B you have not booked, and flags tax-amount mismatches as ITC at risk. It runs every cycle, so issues surface before you file, not after.
  • How does payment reconciliation actually work?
    The agent reads each credit from your bank feed and first tries an exact match using the invoice number in the remittance narration and the amount, then a fuzzy match on the same payer and amount against open invoices within a window. Confident matches mark the invoice paid with the UTR; anything ambiguous goes to a human queue rather than being closed on a guess.
  • Does it integrate with Tally, Zoho Books, or ClearTax?
    Yes, through each tool's API. Invoices are created in your accounting system, e-invoicing goes through your GSP or ASP, and payments and reconciliation write back to the same ledger. Where a system has no clean API, the agent can exchange validated files instead of re-keying, so your books stay the single source of truth.
  • How does chasing avoid annoying good customers?
    By being polite, paced, and aware. The cadence starts friendly and only firms up over time, each message is drafted on-brand by the model rather than as a robotic template, and the agent never sends two chases for the same invoice in a day. The final step escalates to a human for a call instead of another message, and any reply that looks like a dispute pauses chasing at once.
  • What happens with partial payments and disputes?
    A partial payment switches the invoice to expect-partial so reconciliation matches against the amount actually received, and the balance keeps its own due date. A dispute immediately stops chasing and routes the invoice to a human with the customer's message attached, because pursuing a contested bill damages the relationship and rarely gets you paid faster.
  • How does it prevent duplicate invoices or double chasing?
    Every issue is keyed on an idempotency token, so a retry or a webhook delivered twice can never create a second invoice or a second IRN. Chasing checks the log before every send, so the same invoice is never chased twice in a day. These guardrails are what make it safe to run automatically against live financial records.
  • Should I build a custom agent or buy a GST suite?
    Buy a suite if your invoicing is standard and you want compliance quickly with little engineering. Build, or have it built, when you need your own credit rules, tight ERP and bank integration, custom reconciliation, and control of the data. Many teams combine the two, using a suite for e-invoicing and a custom agent for reconciliation and collections. See the comparison table above.
  • What does it cost to run, and how fast is payback?
    Running cost is mostly API and model usage plus hosting, which is small next to the working capital freed up when invoices are paid sooner and input tax credit stops leaking. Against a backdrop where Rs 7.34 lakh crore was owed to Indian MSMEs as of March 2024, even a modest cut in your own DSO usually pays for the build within a few months.

Want this built and running in your stack?

Galific designs, builds, and runs billing agents like this on ADK, the Claude SDK, or LangGraph, wired into your ERP, your GSP, and your bank feed. Or explore the ready-made versions, from the GST Invoicer to Payment Recon and the Invoice Chaser, in our agent suite.