Invoice Agent
An invoice says Net 30 from March 15. The deadline is anchored to the
invoice date, not to when your agent processes it. Set reference_date
to the document date and Biruni gives you the correct due date.
Invoice line
parse_invoice()Your LLM / OCR
→
resolve_time()Biruni API
→
schedule_payment()Your AP system
→
notify()Your alerts
The agent
invoice_agent.py
import httpx, os
BIRUNI_URL = "https://biruni.dev/v1/resolve"
# ── Stubs: replace with your integrations ────────────────────
async def schedule_payment(invoice_id: str, due_date: str):
"""Queue a payment or set a reminder. (ERP, QuickBooks, Xero ...)"""
...
async def notify(text: str):
"""Alert the AP team. (Slack, email, PagerDuty ...)"""
...
def parse_invoice(document: str) -> dict:
"""
Use your LLM or OCR pipeline to extract structured fields.
Returns: {
"invoice_id": str, "terms_phrase": str,
"invoice_date": str, "tz": str,
}
"""
...
# ── Biruni integration ──────────────────────────────────────
async def resolve_time(phrase: str, tz: str, ref: str) -> dict:
async with httpx.AsyncClient() as client:
r = await client.post(
BIRUNI_URL,
headers={"Authorization": f"Bearer {os.environ['BIRUNI_API_KEY']}"},
json={
"expression": phrase,
"reference_date": ref,
"timezone": tz,
},
)
r.raise_for_status()
return r.json()
# ── Agent entry point ────────────────────────────────────────
async def handle(document: str):
fields = parse_invoice(document)
result = await resolve_time(
fields["terms_phrase"],
fields["tz"],
ref=fields["invoice_date"], # anchor to the invoice date, not today
)
match result["status"]:
case "resolved":
await schedule_payment(fields["invoice_id"], result["resolved"])
await notify(
f"Invoice {fields['invoice_id']} due {result['resolved'][:10]}."
)
case "ambiguous":
await notify(
f"Invoice {fields['invoice_id']} has ambiguous terms — "
f"needs manual review."
)
case _:
await notify(
f"Couldn't parse terms for invoice {fields['invoice_id']}."
)