# How we chase down overdue invoices An accounts-receivable agent we run on Kortix — connected to Stripe, email, and the accounting ledger. It finds overdue invoices, sends the right reminder, logs every touch, and reconciles when payment lands. Canonical page: https://kortix.com/use-cases/ar-chaser Chasing overdue invoices is steady, repetitive work that still needs judgment. Most reminders are routine: an invoice is a few days late, a polite note goes out, the customer pays. But the timing, the tone, and the escalation depend on how late the balance is and how large it is, and some accounts are sensitive enough that no automated email should go out without a person looking first. We run an accounts-receivable agent on Kortix that does this chasing on a daily schedule. This is how we collect on our own invoices, including the connections and guardrails involved. - **Team:** Kortix - **Runs on:** A daily cron - **Connected systems:** Stripe · Email · Accounting ledger - **Mode:** Read-mostly · reminders and status notes gate-able ## The problem Receivables slip because no one has time to work the list every day. An invoice goes a week late, then two, and the reminder that should have gone out on day one never does. The ones that need a firmer note get the same generic email as the ones that are barely late, and the sensitive accounts — a large balance, a disputed line, something heading to legal — get chased the same way as everything else. The common fixes are incomplete. Stripe's built-in reminders send on a fixed cadence regardless of balance size or account context. A spreadsheet and a calendar reminder depend on someone actually working it. A generic automation sends the same email to everyone and has no way to hold the risky ones back. ## What we built On Kortix, a daily cron triggers an agent. Each morning it spawns an isolated session (a cloud sandbox) with scoped access to Stripe, our email, and the accounting ledger. It finds every invoice that's overdue or coming due soon, decides the right reminder for each based on how late and how large the balance is, sends it, logs the touch, and reconciles the invoice when payment lands. Anything sensitive stops at a human approval gate before it sends. ## How it works ### Trigger the run on a daily cron A **cron trigger** fires once a day and spawns a fresh **session** in its own sandbox. Each run works the full receivables list from scratch, so nothing carries over between days and a missed morning is just the next run picking up where it left off. One run maps to one session on one disposable machine. ### Give the agent the collections playbook Our collections policy lives as **skills** and **memory** that travel with the agent: the reminder cadence by days overdue, the escalating tone from a first notice to a final notice, the balance thresholds that change the approach, and which accounts are flagged as disputed or sensitive. When we adjust the policy, we write it down and the agent applies it on the next run. ### Connect Stripe, email, and the ledger Through scoped **connectors**, brokered server-side so no raw token reaches the model, the agent can: - **Read invoices from Stripe** — which are overdue, which are coming due, the balance and age of each. - **Send reminders by email** — the right escalating notice for each invoice, from the agent's own address. - **Read the accounting ledger** — to confirm balances and reconcile against what Stripe reports. - **Log every touch and status note** — each reminder and reconciliation recorded against the invoice. ### Set the guardrails The agent is **read-mostly**: it reads Stripe and the ledger, and the only writes it makes are reminder emails and status notes. Anything sensitive — a large balance, a disputed invoice, or an account heading to legal — stops at a **human approval gate** before it sends. Credentials are encrypted in the Secrets Manager and injected at runtime, never shown to the model or written to logs. ### Let the list work itself each morning With that in place, the daily run finds the overdue and soon-due invoices, sends each account the reminder its timing and balance call for, and logs the touch. A routine day-three nudge goes out on its own. A large or disputed balance is held for a person to approve. When a payment lands, the agent matches it to the invoice and marks it settled. > **The pattern** > A daily **cron** spawns a session with scoped **connectors** into Stripe, email, > and the ledger. The collections policy is encoded as **skills** and **memory**. > The agent stays read-mostly, sensitive accounts wait for a human, and every > touch is logged. ## Guardrails The agent sends email on our behalf and touches invoice state, so the access is scoped and contained: - **Isolation.** Every run happens in its own per-task microVM sandbox. The session reads Stripe and the ledger and can send only the reminders and status notes it's scoped to; nothing else leaves the sandbox. - **Scoped secrets.** The Stripe, email, and ledger credentials are encrypted in the Secrets Manager and injected into the sandbox at runtime, never exposed to the model or the logs. - **Human approval gate.** A large balance, a disputed invoice, or an account heading to legal stops for a person to approve before any email goes out. - **Everything is code.** The agent's configuration, skills, and per-system permissions are files in the repo, versioned and changed through a reviewed **change request** rather than a dashboard setting. ## The outcome - **Every morning:** The full receivables list worked on schedule - **Read-mostly:** Only reminders and status notes are written - **3 systems:** Stripe, email, and the ledger in one agent Overdue invoices now get the right reminder on the day they should, with each touch logged and each payment reconciled when it lands. Routine chases run on their own, the sensitive accounts wait for a person, and the receivables list no longer depends on someone finding time to work it.