DunChase developer guide
DunChase is a first-party accounts-receivable agent. Everything the dashboard
shows — aging, invoices, chase drafts, payment promises, recovered cash — is
also available over a REST API, a CLI, and an MCP server.
- API base URL:
https://api.dunchase.com - OpenAPI spec:
https://api.dunchase.com/api/v1/openapi.json(public, no auth)
Authentication
All developer access uses tenant-scoped API keys. Create one in the dashboard
under Settings → Developer access. Keys look like ak_…; the full token is
shown exactly once at creation (only a SHA-256 hash is stored).
Send the key as a bearer token:
Authorization: Bearer ak_your_key_here
Scopes
| Scope | Grants |
|---|---|
api:read | GET endpoints (aging, invoices, drafts, promises, recovered, QBO status) |
api:write | Mutations (approve/reject/edit drafts, record promises, start chases) — implies api:read |
mcp:use | Legacy scope for MCP clients — grants read + write |
Scope enforcement is by HTTP method: GET needs api:read, everything else
needs api:write. A key with the wrong scope gets 403; an unknown, revoked,
or expired key gets 401.
API keys work on the core product surface only (/api/v1/ar/* and
GET /api/v1/qbo/connection). Account management — auth, billing, settings,
and API-key management itself — requires a dashboard session.
REST API
All amounts are integers in cents. Full request/response shapes are in the
Aging report
curl -s https://api.dunchase.com/api/v1/ar/aging \
-H "Authorization: Bearer $DUNCHASE_API_KEY"
Returns totals, aging buckets (current, d1_30, d31_60, d61_90,
d90_plus), and a per-debtor breakdown.
Invoices
# Open invoices (default). status: open | paid | voided | all
curl -s "https://api.dunchase.com/api/v1/ar/invoices?status=open" \
-H "Authorization: Bearer $DUNCHASE_API_KEY"
Drafts and approval
Chase messages are drafted by the agent but **never sent without human
approval**. List the pending queue, then approve by id (needs api:write):
# Pending approval (draft + edited). state: draft|edited|approved|rejected|sent|discarded|all
curl -s https://api.dunchase.com/api/v1/ar/drafts \
-H "Authorization: Bearer $DUNCHASE_API_KEY"
curl -s -X POST https://api.dunchase.com/api/v1/ar/drafts/<draft-id>/approve \
-H "Authorization: Bearer $DUNCHASE_API_KEY"
Approval runs the same unbypassable content guardrails as the dashboard; a
blocked draft returns 422.
Promises and recovered cash
curl -s "https://api.dunchase.com/api/v1/ar/promises?status=pending" \
-H "Authorization: Bearer $DUNCHASE_API_KEY"
curl -s https://api.dunchase.com/api/v1/ar/recovered \
-H "Authorization: Bearer $DUNCHASE_API_KEY"
QuickBooks connection status
curl -s https://api.dunchase.com/api/v1/qbo/connection \
-H "Authorization: Bearer $DUNCHASE_API_KEY"
Read-only for API keys; connecting/disconnecting QBO requires the dashboard.
CLI (dunchase)
A dependency-free Node CLI lives in packages/cli.
# From the monorepo
pnpm --filter @paidup/cli run cli -- help
# Or build once and link the `dunchase` bin
pnpm --filter @paidup/cli run build
Login
dunchase login
# API key (ak_…, from Settings → Developer access): ak_…
# API base URL [https://api.dunchase.com]:
Credentials are written to ~/.paidup/config.json (mode 0600). Overrides, in
precedence order: --api-key / --api-url flags, then DUNCHASE_API_KEY /
DUNCHASE_API_URL environment variables, then the config file.
Commands
| Command | Description |
|---|---|
dunchase login | Store an API key + base URL |
dunchase aging | A/R aging report, buckets per debtor |
dunchase invoices [--status open] | List invoices (open, paid, voided, all) |
dunchase drafts [--state <state>] | List chase drafts (default: pending approval) |
dunchase approve <draft-id> | Approve a draft for sending (needs api:write) |
dunchase promises [--status <s>] | List payment promises |
dunchase recovered | Dollars recovered this month and all-time |
Every command accepts --json to print the raw API response instead of the
human-readable table.
MCP server
packages/mcp ships an MCP server (stdio and streamable HTTP) that exposes
the same API to MCP-capable clients (Claude Desktop, Cursor, …). Point it at
your API key — create the key with the mcp:use scope (or api:read +
api:write). See docs/CLI_MCP.md and packages/mcp for transport setup.
Versioning and stability
The REST surface under /api/v1 is additive: new fields and endpoints may
appear, existing ones won't change shape without a version bump. The OpenAPI
document at /api/v1/openapi.json is the source of truth.