# Invoice Watch

> Generate a Chia invoice (a markdown receipt template) for X XCH payable to a chosen address, then watch the address for the matching deposit and emit a paid receipt when it lands. Use when the user is billing someone in XCH, needs a payment-confirmation flow, or asks to "invoice in Chia". Accepts address, amount_xch, memo, payer, channel as arguments for programmatic invocation.

- Skill: `spacetime-technology/invoice-watch` (Agent Skill)
- Install (CLI): `npx skillmds@latest add spacetime-technology/invoice-watch`
- Raw SKILL.md: https://api.skillmd.com/api/skills/spacetime-technology/invoice-watch/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: Spacetime-Technology (https://skillmd.com/u/spacetime-technology)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/spacetime-technology/invoice-watch

---


# Invoice watch

You are creating an XCH invoice and watching the user's address for the matching deposit. When the deposit lands, you emit a paid receipt and notify the user. Two-phase skill: **issue** (first run) and **check** (subsequent runs). Read-only — no wallet, no signing.

This skill follows the conventions in this repo's `SKILLS.md`. Read that if anything below is unclear.

## Required capabilities

- **chia-explorer** (`mcp__chia-explorer__*`) — mandatory.
- **A notification MCP** — pick whichever is installed. Email is the natural channel since the user usually emails the invoice to the payer.
- **Bash + Read + Write** — for invoice and receipt files.

## Resolve inputs

You need: `$address`, `$amount_xch`, `$memo`, `$payer`, `$channel`.

- `$address` — the receiving Chia address (yours). Required.
- `$amount_xch` — XCH amount due. Required. Accept either decimal XCH or mojos with a `mojos:` prefix.
- `$memo` — short description (`"Design work, May 2026"`). Optional.
- `$payer` — name / handle / email of who's paying. Optional but recommended for the receipt.
- `$channel` — notification channel for the "paid" alert. Default `auto`.

Resolve: arguments → context → ask user. If `$address` or `$amount_xch` is missing after asking, emit `STATUS: aborted`, `REASON: missing required inputs`.

Validate `$address` (xch1/txch1 prefix). Convert `$amount_xch` to mojos for storage.

## State and files

Per-invoice state file: `~/.chia-skills/state/invoice-watch__<sha1(address+amount+memo+created_iso)>.json`.

Shape:

```json
{
  "invoice_id": "INV-2026-05-19-001",
  "address": "xch1...",
  "amount_mojos": 2500000000000,
  "amount_xch": 2.5,
  "memo": "Design work, May 2026",
  "payer": "alice@example.com",
  "created_iso": "2026-05-19T14:33:00Z",
  "first_seen_height": 6532109,
  "status": "open" | "paid" | "overpaid" | "expired",
  "paid_at_iso": null,
  "paid_coin_id": null,
  "paid_height": null,
  "paid_block_hash": null
}
```

Invoice files: `~/.chia-skills/invoices/<invoice_id>.md` (the bill the user emails out).
Receipt files: `~/.chia-skills/receipts/<invoice_id>.md` (the paid record, emitted after payment).

## Issue phase (first run)

If no state file matches, this is the issue phase.

1. Generate `invoice_id` like `INV-YYYY-MM-DD-NNN` (sequential per day; check the invoices dir for collisions).
2. Capture the current chain peak as `first_seen_height`.
3. Write the state file.
4. Render the invoice markdown:

```markdown
# Invoice INV-2026-05-19-001

**From:** (your name / business — pull from `$payer` context or ask)
**To:** alice@example.com

**Amount due:** 2.500 XCH (2,500,000,000,000 mojos)
**Pay to:** xch1yxqsmyuyjdlgxw4sqjg4vqlqv5ms2qzex00586nu643jqemmarwslh08yl

**Memo:** Design work, May 2026
**Issued:** 2026-05-19

The exact amount must land at the address above. Partial or over-payments
will be flagged on the receipt.

This invoice is being watched on-chain — a paid receipt will be issued
automatically when the deposit lands.
```

5. Save to `~/.chia-skills/invoices/<invoice_id>.md`.
6. Tell the user inline: "Invoice issued. Send this file to <payer>. I'll watch for the deposit."
7. Emit `STATUS: success`, `ARTIFACT: <invoice file path>`, `PHASE: issued`.

## Check phase (subsequent runs)

If state file exists with `status: open`:

1. Look up coin records created at `$address` since `first_seen_height`. Apply the standard chia-explorer filtering.
2. For each coin, compare amount to `$amount_mojos`:
   - **Exact match** → `paid`. Record `paid_coin_id`, `paid_height`, `paid_at_iso`. Stop.
   - **Greater than expected** → `overpaid`. Same fields. Still treat as paid but flag in the receipt.
   - **Less than expected** → ignore (the payer might be sending in multiple chunks; don't conclude anything yet).
3. If multiple matching coins land in a single check, treat the first one as the payment.
4. If `now - created_iso > 30 days` and still unpaid, set `status: expired`. (Configurable later.)

If status flips to `paid` or `overpaid`:

1. Render the receipt:

```markdown
# Receipt for INV-2026-05-19-001

**Paid:** 2026-05-20 09:14 UTC
**From:** alice@example.com
**Amount:** 2.500 XCH (matches invoice)
**Block height:** 6,532,210
**Coin id:** 0xabc...123

Original memo: Design work, May 2026
```

For `overpaid`, add a line: `Overpayment: +0.050 XCH — reach out to the payer if a refund is appropriate.`

2. Save to `~/.chia-skills/receipts/<invoice_id>.md`.
3. Send a notification through the chosen channel: subject `Invoice <id> paid`, body = receipt.
4. Update state to `paid` / `overpaid`, atomic write.
5. This watch is terminal — emit `TERMINAL: true` in the output.

If still `open`, emit `STATUS: no_change`, `PHASE: watching`.

## Scheduling

This skill is one-shot. The issue phase runs once; the check phase is what gets scheduled.

- **`schedule` skill / cron** — every 5–15 minutes once the invoice is issued. Stop scheduling when the run emits `TERMINAL: true`.
- **`/loop`** — useful when the user is actively waiting for a payment.

## Hard rules

- **Read-only.** Don't refund overpayments — that needs a wallet. Just flag them.
- **Exact-amount match by default.** Overpayments are flagged, underpayments ignored. Don't try to total partial payments without explicit user opt-in.
- **No wallet integration.** The invoice file is markdown the user emails out. No QR codes (require external libs); the address is enough.
- **Expire long-unpaid invoices** so the schedule doesn't run forever on dead invoices.

## Recovery patterns

- **Address didn't see any coins.** `STATUS: no_change`, `PHASE: watching`.
- **chia-explorer call fails.** Don't update state. `STATUS: failed`.
- **State file says `paid` already.** Emit `STATUS: no_change`, `TERMINAL: true`. Tell the user the schedule is stale.

## Output

```
STATUS: success | no_change | partial | failed | aborted
PHASE: issued | watching | paid | overpaid | expired
INVOICE_ID: INV-YYYY-MM-DD-NNN
AMOUNT_XCH: <decimal>
ADDRESS: <full address>
PAID_COIN_ID: <0x...> | none
PAID_HEIGHT: <int> | none
TERMINAL: true | false
ARTIFACT: <absolute path to invoice or receipt file>
REASON: <one line, only when STATUS is failed, partial, or aborted>
```

