Skip to content

Enrique-Omen/settle

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Settle

An autonomous accounts-receivable agent that collects overdue invoices — and knows when not to.

Python FastAPI Stripe Twilio Sandbox License

Most collection bots send more messages when a debtor doesn't pay. Settle does the opposite: it prices every action before taking it. It chases overdue B2B invoices by email, SMS or AI voice call, pays for its own usage (Twilio, ElevenLabs, LLM inference) out of a live ledger, and takes a real success commission through Stripe. When contacting a debtor is expected to cost more than it recovers, it downgrades the channel or skips the outreach entirely — and books the loss it avoided.

Built solo in about a week for Hermes Agent — Accelerated Business, a hackathon by NVIDIA × Stripe × Nous Research (June 2026). It did not place; the economics engine and the egress sandbox are the parts worth reading.

Why it exists

An agent that spends real money on every action needs a reason to stop. Give an LLM a list of overdue invoices and a phone API and it will happily burn $1.20 of voice call chasing a $40 invoice that was never going to be paid. Settle makes the spend/recover tradeoff an explicit, auditable calculation instead of an emergent behavior — the same ledger that pays its bills is the one it consults before acting.

The decision

For each debtor d and channel c ∈ {email, sms, voice}:

value(d, c) = amount(d) × P_pay(d, c, days_overdue) − cost(c)

choose c* = argmax value(d, c)
if max value < 0  →  skip paid outreach (free email only)

P_pay comes from the attempts table — real historical outcomes of previous contact attempts — not a hardcoded heuristic. Costs run roughly voice ≈ $1.20, sms ≈ $0.08, email ≈ $0.001, plus metered inference. It's a formula, not an if: when the numbers say a voice call loses money, the agent doesn't place it.

How the loop closes

overdue invoices ──▶ [scan] ──▶ [prioritize: expected recovery vs. channel cost]
                                             │
                           profitable ───────┴─────── not profitable
                               │                            │
                         [QA gate] ──▶ send / call     free email only
                         consent ·                   (loss avoided, recorded)
                         AI disclosure ·
                         opt-out · amount
                               │
                               ▼
                     debtor pays via Stripe (live mode)
                               │
                               ▼
                   webhook ──▶ signature verified ──▶ ledger
                               │                (+recovered, +commission)
                               ▼
                     P&L updates live over SSE ──▶ funds the next collection

Architecture

Layer Role
Agent core Runs the loop; loads on-demand skills (skills/*.md), one file per capability
Decision skill Per-channel unit economics from empirical attempt data — the only place a channel is chosen or skipped
QA gate Consent on file, AI disclosure present, amount correct — checked before anything is sent
Sidecar (app/sidecar.py) FastAPI: verifies Stripe webhook signatures, updates the ledger, pushes live P&L over SSE, serves TwiML audio
Egress sandbox (policy.yaml + security/) Docker + squid proxy on an isolated network — the agent's container has no default route out except through the allowlist
Storage SQLite, append-only ledger: invoices, debtors (consent/opt-out), ledger (earn/spend), attempts (outcomes → P_pay)

The sandbox is not a mock. policy.yaml is the source of truth: every allowed host becomes a squid ACL, and network.default: deny becomes the deny rule. A request to any undeclared host gets a real 403 — reproduce it with scripts/demo-403.sh. Host-level (not verb-level) enforcement is the honest limit for HTTPS traffic, and security/README.md explains why.

Stack

Python 3.11 · FastAPI + SSE · SQLite · Stripe (live mode, Connect/Checkout) · Twilio (voice) · ElevenLabs (TTS) · Resend (email) · NVIDIA Nemotron via NIM · Docker + squid (egress sandbox).

Quick start

git clone https://github.com/Enrique-Omen/settle && cd settle
python3 -m venv .venv && .venv/bin/pip install fastapi uvicorn stripe

cat > .env <<'ENV'
STRIPE_SECRET_KEY=<YOUR_STRIPE_KEY>
STRIPE_WEBHOOK_SECRET=<YOUR_STRIPE_WEBHOOK_SECRET>
TWILIO_ACCOUNT_SID=<YOUR_TWILIO_SID>
TWILIO_AUTH_TOKEN=<YOUR_TWILIO_TOKEN>
ELEVENLABS_API_KEY=<YOUR_ELEVENLABS_KEY>
RESEND_API_KEY=<YOUR_RESEND_KEY>
NVIDIA_API_KEY=<YOUR_NVIDIA_NIM_KEY>
ENV

sqlite3 app/settle.db < app/schema.sql       # schema
python3 scripts/seed_history.py              # demo business, debtors, attempt history
.venv/bin/uvicorn sidecar:app --app-dir app --port 8444

Point a Stripe webhook (payment_intent.succeeded, charge.succeeded) at https://<YOUR_DOMAIN>/webhook, then run scripts/settle-decide.py to see the decision engine choose a channel — and downgrade one debtor to email because the voice call doesn't pay for itself.

Compliance

Settle chases a business's own invoices, B2B only, with prior consent on file. Every message opens with an AI disclosure and offers an opt-out, and the QA gate blocks any message missing them. That is first-party, consent-based follow-up — outside the FDCPA/TCPA regime that governs third-party consumer debt collection.

Scope of the demo data

The business, its debtors and their invoices are seeded demo data (scripts/seed_history.py) — self-owned and consenting, not third parties. The economics engine, the Stripe integration (live mode, real webhook, real commission), the voice pipeline and the egress sandbox are real. Nothing here simulates a payment.

Docs

docs/ARCHITECTURE.md · docs/RISKS.md · security/README.md

About

Autonomous accounts-receivable agent that prices every action before taking it: chases overdue B2B invoices by email, SMS or AI voice, pays its own bills from a live ledger, and skips outreach that costs more than it recovers. FastAPI + Stripe Connect + Twilio, behind an egress allowlist.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors