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.

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

ScopeGrants
api:readGET endpoints (aging, invoices, drafts, promises, recovered, QBO status)
api:writeMutations (approve/reject/edit drafts, record promises, start chases) — implies api:read
mcp:useLegacy 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

OpenAPI spec.

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

CommandDescription
dunchase loginStore an API key + base URL
dunchase agingA/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 recoveredDollars 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.