---
name: economico
description: Use Economico — an agent-native general ledger — to create parties (customers/vendors), draft and send invoices, record payments (on-chain or off-chain), void invoices, and summarize revenue. Use when asked to bookkeep, invoice a customer, send a bill, record a stablecoin or wire payment, reconcile a transaction, pull a balance sheet or income statement, or query the chart of accounts. Two paths: the `@economico/cli` npm package for shells / CI / coding agents, or the MCP server at `https://economi.co/mcp` for MCP-capable hosts (Claude Code, Claude Desktop, Cursor, ChatGPT, Lindy, OpenAI Agents). Both speak the same eight money-loop verbs and authenticate via OAuth 2.1.
---

# Economico — agent skill

Economico is an agent-native general ledger. Connect your agent in one of two ways. Pick **one** — they're mutually exclusive.

| Path | When to use | What you talk to |
|---|---|---|
| **CLI** | Shell, CI runner, coding agent with shell access. | `@economico/cli` npm package — `economico <command>` |
| **MCP** | MCP-capable host (Claude Code, Claude Desktop, Cursor, ChatGPT, Lindy, OpenAI Agents). | `https://economi.co/mcp` over HTTP with bearer auth |

Both expose the same surface — the same eight money-loop verbs, the same JSON shapes. Authentication is OAuth 2.1: the CLI runs a loopback PKCE flow on first use; MCP-capable hosts run RFC 7591 DCR + the same browser flow when you give them `https://economi.co/mcp`.

---

## Path A — CLI

The CLI is a thin shell over the REST API. Every command emits JSON to stdout; errors go to stderr with a non-zero exit.

### Install

Pick one. Both are documented because different hosts have different constraints.

**Persistent install** (recommended for long-lived agents):

```bash
npm install -g @economico/cli
economico --version
```

**Ephemeral via npx** (no global state — good for sandboxed agents):

```bash
npx -y @economico/cli@latest <command>
```

The CLI requires Node 20+ and works on Linux, macOS, and Windows. Set `ECONOMICO_API_URL` if you're not hitting the default `https://economi.co`.

### Bootstrap: log in (handles signup transparently)

Every business is owned by an email. Run one command — `economico login`. It opens the browser to `/oauth/authorize`, the user signs in (or signs up — same flow, same page), and the CLI captures the resulting OAuth access + refresh tokens.

```bash
economico login
# → Opens the browser, captures the loopback callback.
# → Persists access_token + refresh_token to ~/.config/economico/config.json (mode 0600).
# → {"ok":true,"api_url":"https://economi.co","client_id":"cli_pub_…","expires_in":3600}
```

On hosts without a browser (CI, SSH session), pass `--no-browser` and the CLI prints the URL for the user to open manually. The CLI silently rotates the access token via `grant_type=refresh_token` once on 401, so long-running agents don't need to re-authenticate every hour.

Environment variable override:

- `ECONOMICO_API_URL` — point at a different deployment (default `https://economi.co`).

`economico skill` re-prints this guide (the connected deployment's `skill.md`) to stdout at any time — no login required. `economico agent-context` emits the full command surface (every command, flag, type, and enum) as versioned JSON, so you can introspect the exact shapes before calling instead of guessing.

### Discover commands and parameters with `--help`

**Don't guess flags — ask the binary.** `--help` (`-h`) works at every level and is the canonical source of truth for what each command accepts. Walk it top-down.

#### Top-level: what subcommands exist?

```bash
economico --help
```

```
Usage: economico [options] [command]

Commands:
  login        Authenticate this CLI via the OAuth browser flow (handles signup + login).
  parties      Manage customer / vendor parties.
  invoices     Manage invoices.
  revenue      Revenue rollups.
  accounts     List the system chart of accounts (with ledger account IDs).
  balances     Current balances for all postable accounts.
  reports      Financial reports.
  oauth        Manage OAuth 2.1 clients for MCP agents.
```

#### One level down: what verbs does a noun support?

```bash
economico invoices --help
```

```
Commands:
  create   Create a draft invoice. No GL impact until `invoices send`.
  list     List invoices.
  get      Get one invoice with its lines and payments.
  send     Post the AR/revenue journal and deliver via the chosen channel.
  void     Void an invoice (reversing journal if already sent).
  pay      Record a payment against an invoice.
```

#### Two levels down: what parameters does a verb take?

```bash
economico invoices create --help
```

```
Options:
  --party-id <id>     customer party UUID
  --amount <minor>    total in minor units (cents)
  --currency <iso>    ISO 4217 (USD) or CAIP-19 (eip155:8453/erc20:0x…)
  --due <yyyy-mm-dd>  due date
  --lines <json>      JSON array of {description, quantity_micros, unit_price_minor}
  --memo <memo>       optional memo
```

This is exhaustive — every flag the server accepts is here. Build the call from the flag names; don't try to remember them.

A few more examples worth running once so you've seen the shape:

```bash
economico parties create --help         # --name, --url
economico invoices send --help          # --channel { flow | email | link }
economico invoices pay --help           # on-chain (--tx-hash, --chain-id, --log-index, --settlement-address) vs off-chain (--idempotency-key)
economico revenue summary --help        # --from, --to (inclusive period)
economico reports balance-sheet --help  # --currency
economico accounts list --help          # --currency, --party (repeatable), --sku (repeatable)
economico oauth clients create --help   # --jwks-file, --name, …
```

Every command accepts `--json` (default) and `--human` (compact human-readable summary instead of raw JSON). On any non-2xx, the CLI writes a JSON error envelope to stderr and exits non-zero — never try/catch around it, just let the exit code surface.

---

## Path B — MCP

Use this path if your host speaks MCP-over-HTTP with OAuth (Claude Cowork, Claude Code, Claude Desktop, Cursor, ChatGPT, Lindy, OpenAI Agents, and others).

### Bootstrap: install the MCP server

The host runs the full OAuth dance itself once you give it the MCP URL. There are no MCP tools to call for sign-up or sign-in — the host hits `/mcp`, gets a 401 + `WWW-Authenticate` pointing at the OAuth Authorization Server, runs RFC 7591 Dynamic Client Registration, opens `/oauth/authorize` in the user's browser, the user enters their email + the 6-digit OTP, clicks Allow on the consent screen, and the host receives an access + refresh token pair.

```bash
claude mcp add economico https://economi.co/mcp
```

Other hosts: swap `claude mcp add` for your host's equivalent MCP install command. The endpoint is the same. New emails create a business; known emails log in — both go through the same browser page.

### Tools

The promoted surface — the invoice → payment → revenue loop:

- `create_party` — a counterparty (customer and/or vendor; the role lives on contracts, so one party can be both). Required before invoicing.
- `create_contract` / `update_contract_status` — a contract with a role (customer/vendor), ISO currency, and a lifecycle (draft→offer→active, plus rejected/terminated/expired). Billing requires an active contract.
- `create_obligation` — a billable obligation on a contract: `one_off`, `recurring` (subscription), or `usage` (metered pricing definition; no usage recorded yet).
- `create_invoice` — draft an invoice for a customer; lines may tie to a customer obligation
- `send_invoice` — channel: `flow` (Notabene Flow), `email` (SendGrid), `link` (Flow-hosted payment link)
- `receive_bill` / `approve_bill` / `pay_bill` / `void_bill` / `get_bills` — vendor bills (accounts payable): Dr expense/COGS / Cr AP on approve, Dr AP / Cr cash on pay
- `get_invoices` — filter by status, party, period
- `void_invoice` — posts a reversing journal if the invoice was already sent
- `record_payment` — settle an invoice; composite-key idempotency
- `summarize_revenue` — invoiced + paid + outstanding + recognized for a period

Additional tools cover chart-of-accounts management, manual journals, balance and report queries, and blockchain wallet operations — call `tools/list` to discover them.

### Confidential clients for unattended MCP agents

For hosted agents that run unattended (CI jobs, server workers) and need to authenticate without a browser, register a confidential OAuth client and authenticate with RFC 7523 `private_key_jwt` instead of the browser flow.

1. Generate an RSA or P-256 EC keypair locally (e.g. `openssl genrsa` or `openssl ecparam`). Publish only the JWKS.
2. From an authenticated MCP session call `create_oauth_client` with `{ name, jwks }`. The response includes `client_id`, `token_endpoint`, `resource`, and `issuer`.
3. The hosted agent signs a short-lived JWT assertion (`alg=RS256` or `ES256`, `iss=sub=<client_id>`, `aud=<token_endpoint>`, fresh `jti`, `exp ≤ 60s`) and POSTs to `/oauth/token` with `grant_type=client_credentials` to receive a short-lived access token.
4. Use the access token as the Bearer on `/mcp` requests.

Discovery: `GET /.well-known/oauth-protected-resource`, `GET /.well-known/oauth-authorization-server`, `GET /.well-known/jwks.json`. Spec: https://github.com/modelcontextprotocol/ext-auth/blob/main/specification/draft/oauth-client-credentials.mdx.

Companion tools: `list_oauth_clients`, `revoke_oauth_client`.

---

## Lines JSON

`invoices create` / `create_invoice` takes a structured JSON `--lines` array. Example:

```bash
economico invoices create \
  --party-id 6f5b… \
  --amount 200000 \
  --currency USD \
  --due 2026-06-01 \
  --memo "March consulting" \
  --lines '[
    {"description":"Consulting","quantity_micros":10000000,"unit_price_minor":20000}
  ]'
```

`quantity_micros` is the quantity × 1_000_000; `unit_price_minor` is the unit price in minor units (cents for USD). 10 hours × $200 → `quantity_micros=10000000`, `unit_price_minor=20000`, `amount` = 200000.

## Money model

- **Amount**: always an integer in minor units (cents for USD). Never floats.
- **Currency**: ISO 4217 (`USD`, `EUR`), stablecoin shorthand (`USDC`, `USDT`, `PYUSD`), or full CAIP-19 (`eip155:8453/erc20:0x833…`).
- **Idempotency**: `record_payment` is idempotent on `(chain_id, tx_hash, log_index, currency, settlement_address, amount)` for on-chain payments and on `(invoice_id, idempotency_key)` off-chain. Re-running a failed call is safe.

## Contracts, obligations & bills — the model

This is the layer above raw invoices. Use it when money is governed by an agreement, when you bill the same thing every month, or when you want to see unit economics per customer.

- **A party is just a counterparty.** It is neither "customer" nor "vendor" on its own — the *same* company can be both (your customer who is also your cloud reseller). Which side you're on is a property of the **contract**, not the party. So `create_party` takes no type.
- **A contract is the agreement.** It carries a `role` — `customer` (you sell → it bills as an invoice → revenue/AR) or `vendor` (you buy → it bills as a vendor bill → expense/AP) — an ISO 4217 denomination `currency`, an optional `order_form_url`, and a `status` lifecycle: `draft → offer → active`, plus `rejected` / `terminated` / `expired`. **Billing only works against an `active` contract** (`update_contract_status` to advance it) — that's the guardrail that stops you invoicing under terms nobody agreed to yet.
- **An obligation is one billable term of a contract.** Three shapes: `one_off` (a single charge), `recurring` (a subscription — carries an `interval` + amount), or `usage` (a metered price definition: a `metric_name` + `price_per_unit`). Obligations inherit role, party, and currency from their contract, and each one **requires an `account_code`** — the GL account its revenue or expense lands in. This is enforced to match the contract role: a customer obligation must use a **revenue** account (e.g. `4110`), a vendor obligation a **cost/expense** account (e.g. `5300`); see the chart guide below. They are the stable thing your line items point at, month after month.
- **How to build the obligations (do this when setting up a contract).** Read the **order form and the contract terms** and create one obligation per distinct billable term — the monthly subscription, each usage meter, any one-off setup fee. If there is no order form, set `order_form_url` to the counterparty's **pricing page** and derive the obligations from there. Pick each obligation's `account_code` from the chart of accounts so revenue and cost are categorised from day one.
- **Invoices and bills reference obligations on their lines.** `create_invoice` (customer) and `receive_bill` (vendor) take a per-line `obligation_id`. That link is what makes a charge traceable back to the term that authorized it — and what lets revenue and cost be attributed to the same SKU sub-account in the ledger.
- **Why two verbs per side.** A customer invoice is *sent* (`send_invoice` posts Dr AR / Cr revenue, then delivers it). A vendor bill you *receive* (`receive_bill`) and then *approve* (`approve_bill` posts Dr expense / Cr AP) — you don't "send" a bill to yourself, you book the liability when you approve it — then `pay_bill` settles it (Dr AP / Cr cash).
- **Unit economics.** A vendor obligation can point at the customer obligation it funds via `source_obligation_id` on `create_obligation`. That's the link that ties "the AWS spend that serves Acme" to "Acme's SaaS subscription," so per-customer margin is computable. (The link ships now; a roll-up report does not — query the obligations + journals yourself for now.)
- **Pricing vs settlement currency.** A contract can be priced in `EUR` while you settle the invoice/bill in `USD` or `USDC`. The contract/obligation currency is the *pricing* currency; the invoice currency is what actually moves. When they differ, the original priced amount is recorded on the journal line as a reporting annotation (`asset` / `asset_amount`) — there is no automatic FX conversion.
- **Not here yet (by design):** usage is *defined* but not *recorded* (no metered-consumption ingestion), and there is no automatic unit-economics report.

Minimal vendor flow: `create_party` → `create_contract --role vendor` → `set-status … active` → `create_obligation` → `receive_bill` (lines tie to the obligation) → `approve_bill` → `pay_bill`. The customer flow is the mirror image with `--role customer` and `create_invoice` / `send_invoice`.

## Chart of accounts — quick guide

The full chart is available via `list_chart_of_accounts` (MCP) or `economico accounts list` (CLI). Here's how to pick accounts for common tech-company transactions.

**Revenue** — all SKU-keyed so you can track per-product:

| What you're recording | Account |
|---|---|
| SaaS / subscription billing | 4110 Subscription Revenue |
| Metered / consumption billing | 4120 Usage-Based Revenue |
| Software licenses | 4130 Licensing Revenue |
| Professional services / advisory | 4210 Consulting Revenue |
| Marketplace take-rate / commissions | 4220 Platform and Marketplace Revenue |
| Referral / affiliate payouts received | 4230 Referral and Affiliate Revenue |
| Government grants, accelerator awards | 4500 Grant and Award Revenue |
| Catch-all product revenue (invoice default) | 4100 Sales Revenue |
| Catch-all service revenue | 4200 Service Revenue |

**Cost of Revenue (COGS)** — direct costs of delivering your product:

| What you're recording | Account |
|---|---|
| AWS / GCP / Azure / Vercel (production) | 5300 Hosting and Infrastructure (SKU = vendor) |
| OpenAI / Anthropic / Cohere API (production inference) | 5400 AI and LLM Inference Costs (SKU = vendor) |
| Stripe / PayPal / Adyen fees | 5500 Payment Processing Fees |
| Third-party APIs consumed by your product | 5600 Third-Party API and Data Costs (SKU = vendor) |
| Support team directly tied to service delivery | 5700 Customer Support Costs |
| FTE salaries for people delivering the product | 5100 Direct Salaries and Wages |
| Contractors / Deel / Remote for delivery staff | 5200 Direct Contractors and EOR |

**Operating expenses** — organized by function (R&D / Sales & Marketing / G&A):

| What you're recording | Account |
|---|---|
| Engineering salaries | 6110 R&D Salaries and Wages |
| Contract engineers via Deel / Remote | 6120 R&D Contractors and EOR |
| Dev infra, CI/CD, GitHub | 6130 R&D Cloud and Dev Tools |
| Copilot, Cursor, Claude Code for engineering | 6140 R&D AI and LLM Tools |
| IDE licenses, Figma, testing tools | 6150 R&D Software Licenses |
| Sales / marketing team salaries | 6210 Sales and Marketing Salaries |
| Sales / marketing contractors via Deel | 6220 S&M Contractors and EOR |
| Google Ads, LinkedIn, sponsorships | 6230 Advertising and Paid Media |
| HubSpot, Mailchimp, analytics | 6240 Marketing Tools and Software |
| Finance / HR / ops salaries | 6310 G&A Salaries and Wages |
| G&A contractors via Deel | 6320 G&A Contractors and EOR |
| Google Workspace, Slack, Notion, 1Password | 6350 SaaS and Productivity Tools |
| Legal counsel, incorporation | 6380 Legal and Corporate |
| Bookkeeping, tax prep, audit | 6390 Accounting and Tax |
| Deel / Remote / Gusto platform fees | 6400 HR and People Operations |
| Job boards, recruiter fees | 6410 Recruiting |
| Laptops, monitors | 6420 Equipment and Hardware |
| Co-working, office lease | 6330 Rent and Facilities |

**Rule of thumb**: COGS (5xxx) = costs that scale with revenue. R&D (61xx) = building the product. S&M (62xx) = selling the product. G&A (63xx-64xx) = running the company. When in doubt, `list_chart_of_accounts` returns the full tree.

## Read more

- CLI introspection: `economico --help` (and `economico <command> --help` at every level)
- MCP introspection: `tools/list` over `/mcp` returns every tool with its full input schema
- MCP endpoint: `https://economi.co/mcp`
- OAuth discovery: `https://economi.co/.well-known/oauth-protected-resource`
